codis 介绍和集群搭建

2023年 7月 16日 152.2k 0

Codis 介绍

简介

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有显著区别 (有一些命令不支持), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务。

Codis的github:https://github.com/CodisLabs/codis

Codis特性如下

  • 最新 release 版本为 codis-3.2,codis-server 基于 redis-3.2.8
  • 支持 slot 同步迁移、异步迁移和并发迁移,对 key 大小无任何限制,迁移性能大幅度提升
  • 相比0:重构了整个集群组件通信方式,codis-proxy 与 zookeeper 实现了解耦,废弃了codis-config 等
  • 元数据存储支持 etcd/zookeeper/filesystem 等,可自行扩展支持新的存储,集群正常运行期间,即便元存储故障也不再影响 codis 集群,大大提升 codis-proxy 稳定性
  • 对 codis-proxy 进行了大量性能优化,通过控制GC频率、减少对象创建、内存预分配、引入 cgo、jemalloc 等,使其吞吐还是延迟,都已达到 codis 项目中最佳
  • proxy 实现 select 命令,支持多 DB
  • proxy 支持读写分离、优先读同 IP/同 DC 下副本功能
  • 基于 redis-sentinel 实现主备自动切换
  • 实现动态 pipeline 缓存区(减少内存分配以及所引起的 GC 问题)
  • proxy 支持通过 HTTP 请求实时获取 runtime metrics,便于监控、运维
  • 支持通过 influxdb 和 statsd 采集 proxy metrics
  • slot auto rebalance 算法从0 的基于 max memory policy 变更成基于 group 下 slot 数量
  • 提供了更加友好的 dashboard 和 fe 界面,新增了很多按钮、跳转链接、错误状态等,有利于快速发现、处理集群故障
  • 新增 SLOTSSCAN 指令,便于获取集群各个 slot 下的所有 key
  • codis-proxy 与 codis-dashbaord 支持 docker 部署

codis架构如下

image001

codis 组件介绍

codis server:基于redis-3.2.8 分支开发。增加了额外的数据结构,以支持slot有关的操作以及数据迁移指令。具体的修改可以参考文档redis的修改

codis proxy:客户端连接的redis代理服务,实现了redis协议。除部分命令不支持以外(不支持的命令列表),表现的和原生的redis没有区别。

对于同一个业务集群而言,可以同时部署多个codis-proxy实例;

不同codis-proxy之间由codis-dashboard保证状态同步。

codis dashboard:集群管理工具,支持codis-proxy、codis-server的添加、删除、以及数据迁移操作。在集群状态发生改变时,codis-dashboard维护集群下所有codis-proxy的状态一致性。

对于同一个业务集群而言,同一时刻codis-dashboard只能有0个或者1个

所有对集群的修改都必须通过codis-dashboard完成。

codis FE:集群管理界面

多个集群实例共享可以共享同一个前端展示页面;

通过配置文件管理后端codis-dashboard列表,配置文件可自动更新。

storage:

提供namespace概念,不同集群会按照不同product name进行组织;

目前仅提供了zookeeper、etcd、fs三种实现,但是提供了抽象的interface可自行扩展。

codis 是如何分片的

Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。

每一个 slot 都会有一个且必须有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。数据的迁移也是以slot为单位的。

Codis部署

环境说明

节点编号 IP地址 操作系统
node1 192.168.28.71 Centos 7.2
node2 192.168.28.72 Centos 7.2
node3 192.168.28.73 Centos 7.2

Codis部署架构如下图

image003

codis server主从分布如下图

image004

安装部署

zookeeper 安装

codis的元数据存储依赖zookeeper,所以在安装codis之前我们需要安装一个zookeeper环境

安装过程略

go安装

由于codis是go语言写的,所以需要在每台codis主机安装go语言运行环境。

1、安装go

[root@node1 ~]# yum -y install golang

2、设置go运行环境

[root@node1 ~]# mkdir /data/go -p
[root@node1 ~]# vim /etc/profile
export GOPATH=/data/go
export PATH=$PATH:$GOPATH/bin
[root@node1 ~]# source /etc/profile

3、安装godep

[root@node1 ~]# yum -y install git
[root@node1 ~]# go get -u github.com/tools/godep && which godep
/data/go/bin/godep

codis 安装

1、安装依赖

yum install autoconf automake libtool -y

2、编译安装

mkdir -p /data/go/src/github.com/CodisLabs
cd /data/go/src/github.com/CodisLabs
git clone https://github.com/CodisLabs/codis.git -b release3.2
cd codis/
make

3、配置文件修改
dashboard 配置修改

# vim config/dashboard.toml
coordinator_name = "zookeeper"
coordinator_addr = "192.168.28.71:2181,192.168.28.72:2181,192.168.28.73:2181"
product_name = "xuele-codis"

复制配置文件到另外两个节点

scp config/dashboard.toml 10.1.13.172:/data/go/src/github.com/CodisLabs/codis/config/dashboard.toml 
scp config/dashboard.toml 10.1.13.173:/data/go/src/github.com/CodisLabs/codis/config/dashboard.toml 

4、codis-proxy配置

# vim config/proxy.toml
product_name = "xuele-codis"
product_auth = ""
jodis_name = "zookeeper"
jodis_addr = "192.168.28.71:2181,192.168.28.72:2181,192.168.28.73:2181"
jodis_auth = ""
jodis_timeout = "20s"
jodis_compatible = true

复制配置文件到另外两个节点

scp config/proxy.toml 10.1.13.172:/data/go/src/github.com/CodisLabs/codis/config/proxy.toml 
scp config/proxy.toml 10.1.13.173:/data/go/src/github.com/CodisLabs/codis/config/proxy.toml

5、codis-server配置

[root@c7-node1 redis-3.2.11]# pwd
/data/go/src/github.com/CodisLabs/codis/extern/redis-3.2.11
[root@c7-node1 redis-3.2.11]# mkdir /data/redis
[root@c7-node1 redis-3.2.11]# cp redis.conf /data/redis/redis-6379.conf
[root@c7-node1 redis-3.2.11]# cp redis.conf /data/redis/redis-6380.conf
[root@c7-node1 redis-3.2.11]# cp redis.conf /data/redis/redis-6381.conf

6、redis配置文件修改

# vim /data/redis/redis-6379.conf
port 6379
pidfile /tmp/redis_6379.pid
logfile "/tmp/redis_6379.log"
dbfilename dump_6379.rdb
maxmemory 1g
dir /data/redis/redis_6379 

修改6379为6380

# vim /data/redis/redis-6380.conf
port 6380
pidfile /tmp/redis_6380.pid
logfile "/tmp/redis_6380.log"
dbfilename dump_6380.rdb
maxmemory 1g
dir /data/redis/redis_6380

修改6379为6381

# vim /data/redis/redis-6381.conf
port 6381
pidfile /tmp/redis_6381.pid
logfile "/tmp/redis_6381.log"
dbfilename dump_6381.rdb
maxmemory 1g
dir /data/redis/redis_6381

复制配置文件到另外两个节点

scp /data/redis/*.conf 10.1.13.172:/data/redis/
scp /data/redis/*.conf 10.1.13.173:/data/redis/

修改完配置文件,还需要创建相关目录

mkdir /data/redis/redis_6379 -p
mkdir /data/redis/redis_6380 -p
mkdir /data/redis/redis_6381 -p

7、服务启动及初始化集群
启动dashboard

# nohup ./bin/codis-dashboard --ncpu=1 --config=config/dashboard.toml --log=dashboard.log --log-level=WARN >> /var/log/codis_dashboard.log &

启动proxy

nohup ./bin/codis-proxy --ncpu=1 --config=config/proxy.toml --log=proxy.log --log-level=WARN >> /var/log/codis_proxy.log &

启动codis server

nohup ./bin/codis-server /data/redis/redis-6379.conf &
nohup ./bin/codis-server /data/redis/redis-6380.conf &
nohup ./bin/codis-server /data/redis/redis-6381.conf &

启动codis-fe

nohup ./bin/codis-fe --ncpu=1 --log=fe.log --log-level=WARN --zookeeper=192.168.28.71:2181,192.168.28.72:2181,192.168.28.73:2181 --listen=192.168.28.71:8090 &

访问codis管理界面
image005

web界面配置

1、添加proxy

image007

2、添加group和server

image009

3、通过fe初始化solt

新增的集群 slot 状态是 offline,因此我们需要对它进行初始化(将 1024 个 slot 分配到各个 group),而初始化最快的方法可通过 fe 提供的 rebalance all slots 按钮来做,如下图所示,点击此按钮,我们即快速完成了一个集群的搭建。

image011

测试验证

通过连接codis-proxy进行验证

# redis-cli -h 192.168.28.71 -p 19000
192.168.28.71:19000> INFO
# Server
redis_version:3.2.11
redis_git_sha1:7191a280
redis_git_dirty:0
redis_build_id:a9271caacf948e7
redis_mode:standalone
os:Linux 3.10.0-514.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:48993
run_id:2f8dff0622b212a2838f232abf8a166c0f0efb25
tcp_port:6379
uptime_in_seconds:1369
uptime_in_days:0
hz:10
lru_clock:7144691
executable:/data/go/src/github.com/CodisLabs/codis/./bin/codis-server
config_file:/data/redis/redis-6379.conf

# Clients
connected_clients:49
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:5338840
used_memory_human:5.09M
used_memory_rss:13819904
used_memory_rss_human:13.18M
used_memory_peak:6361912
used_memory_peak_human:6.07M
total_system_memory:1912107008
total_system_memory_human:1.78G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:1000000000
maxmemory_human:953.67M
maxmemory_policy:noeviction
mem_fragmentation_ratio:2.59
mem_allocator:jemalloc-4.0.3

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1533870359
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:150
total_commands_processed:7126
instantaneous_ops_per_sec:22
total_net_input_bytes:153606
total_net_output_bytes:2783917
instantaneous_input_kbps:0.36
instantaneous_output_kbps:8.56
rejected_connections:0
sync_full:1
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:18123
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:1
slave0:ip=192.168.28.71,port=6380,state=online,offset=1373,lag=1
master_repl_offset:1373
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:1372

# CPU
used_cpu_sys:1.65
used_cpu_user:0.72
used_cpu_sys_children:0.31
used_cpu_user_children:0.00

# Cluster
cluster_enabled:0

# Keyspace

读写数据验证

192.168.28.71:19000> SET name hehe
OK
192.168.28.71:19000> GET name
"hehe"

web界面验证key已经正常写入

image013

压测

[root@c7-node1 codis]# ./bin/redis-benchmark -h 192.168.28.71 -p 19000 -c 100 -d 100 -t set -n 10000 -r 10000

上述命令的意思是,使用redis-benchmark压力测试命令连接codis集群,同时并发10000个(-c),测试set操作(-t),每个测试数据集是100字节(-d),请求数是100000(-n),使用使用随机数插入数值(-r)。

测试结果为1秒内完成1万个set操作

====== SET ======
  10000 requests completed in 0.96 seconds
  100 parallel clients
  100 bytes payload
  keep alive: 1

压测后可以看到分到后端group的数据还是比较均衡的

image014

基于redis-sentinel实现主备切换

修改sentinel配置文件

[root@c7-node1 codis]# cat /data/redis/sentinel.conf 

port 26379
bind 0.0.0.0

pidfile "/data/redis/logs/sentinel.pid"
logfile "/data/redis/logs/sentinel.log"
dir "/data/redis/db"

sentinel monitor codis-server-01 192.168.28.71 6379 2
sentinel down-after-milliseconds codis-server-01 5000
sentinel failover-timeout codis-server-01 60000
sentinel parallel-syncs codis-server-01 2

sentinel monitor codis-server-02 192.168.28.72 6380 2
sentinel down-after-milliseconds codis-server-02 5000
sentinel failover-timeout codis-server-02 60000
sentinel parallel-syncs codis-server-02 2

sentinel monitor codis-server-03 192.168.28.73 6381 2
sentinel down-after-milliseconds codis-server-03 5000
sentinel failover-timeout codis-server-03 60000
sentinel parallel-syncs codis-server-03 2

复制sentinel配置到其他节点

scp /data/redis/sentinel.conf 192.168.28.72:/data/redis/sentinel.conf
scp /data/redis/sentinel.conf 192.168.28.73:/data/redis/sentinel.conf

创建相关目录

mkdir /data/redis/logs/
mkdir /data/redis/db/

启动sentinel

[root@c7-node1 codis]# pwd
/data/go/src/github.com/CodisLabs/codis
[root@c7-node1 codis]# nohup ./bin/redis-sentinel /data/redis/sentinel.conf &

codis web页面添加sentinels

image016

配置完成后可以在group中看到明显的HA标志

image017

手动kill 掉一个主节点测试可用性

kill掉192.168.28.72机器上的6380主节点,验证从节点可以正常转移

image018

验证死一台机器(手动关闭192.168.28.73节点),codis集群能否正常提供服务

image019

数据平滑迁移

redis 数据 平滑迁移到codis 使用codis官方提供的redis-port工具。

原理:redis-port本质是以slave的形式挂在到现有redis服务上去的

1、redis会生成RDB dump文件给做为slave的redis-port

2、redis-port分析RDB文件,并拆分成key-value对,通过slotsrester指令发给codis

3、迁移过程中发生的修改,redis会将这些指令在RDB DUMP发送完成后,在发给redis-port,而redis-port收到这些指令后不做处理,而直接转发给codis

redis-port github地址: https://github.com/CodisLabs/redis-port

(1)安装redis-port

cd /data/go/src/github.com/CodisLabs
go get -u github.com/CodisLabs/redis-port
go get github.com/cupcake/rdb
cd redis-port/
make

数据同步命令

./bin/redis-sync -m 192.168.201.3:6381 -t 192.168.28.71:19000

参数说明:

-m 源集群地址和端口

-t 目标集群地址和端口

redis 数据扩容

说明:本次扩容添加3组codis-server,数据扩容测试由于不涉及高可用相关内容,所以扩容的codis server均为单点

(1)按照之前的部署方式,分别在三个节点各自启动了一个codis server,端口分别为6382,6383,6384,并在web管理界面添加到了集群中

image020

(2)通过rebalance all slots来实现集群的slots自动均衡

image022

(3)确定每个新加入的group分配的slots。

image024

(4)分配完成slot显示如下所示

image025

从group看,每组分片的memory空间占用情况也是均衡的

image027

dashboard 故障异机启动

codis 官方仅允许运行一个dashboard节点,dashboard节点启动会在zk上注册自己的节点,同时在程序正常退出的时候删掉对应的节点,但如果异常退出就会导致zk的节点无法删除,在下一次启动的时候会报“zk: node already exists”的错误。

如果dashboard节点出现故障,短时间无法恢复,我们需要在另外一台节点启动dashboard的话,需要在zookeeper中删除节点的注册信息,方法如下:

# ./zkCli.sh
delete /codis3/xuele-codis/topom

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论