十codis
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十codis相关的知识,希望对你有一定的参考价值。
一、简介
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 , 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
组成部分
Codis Proxy (codis-proxy)
Codis Manager (codis-config)
Codis Redis (codis-server)
codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 Twemproxy), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.
codis-config 是 Codis 的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config 本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察 Codis 集群的运行状态.
codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.
Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.
Codis 支持按照 Namespace 区分不同的产品, 拥有不同的 product name 的产品, 各项配置都不会冲突
特性
自动平衡
使用非常简单
图形化的面板和管理工具
支持绝大多数 Redis 命令,完全兼容twemproxy
安全而且透明的数据移植,可根据需要轻松添加和删除节点
提供命令行接口
优点:实现高并发读写,数据一致性高.
缺点:性能有较大损耗,故障切换无法保证不丢key,无法进行读写分离.
逻辑架构如下:
访问层:访问方式可以是vip或者是通过java代码调用jodis,然后连接调用不同的codis-proxy地址来实现高可用的LVS和HA功能.
代理层:然后中间层由codis-proxy和zookeeper处理数据走向和分配,通过crc32算法,把key平均分配在不同redis的某一个slot中.实现类似raid0的条带化,在旧版本的codis中,slot需要手工分配,在codis3.2之后,slot会自动分配,相当方便.
数据层:最后codis-proxy把数据存进真实的redis-server主服务器上,由于codis的作者黄东旭相当注重数据一致性,不允许有数据延时造成的数据不一致,所以架构从一开始就没考虑主从读写分离.从服务器仅仅是作为故障切换的冗余架构,由zookeeper调用redis-sentinel实现故障切换功能.
因为机器有限,部署的架构如下:
序号 | IP | 主机名 | 部署程序 |
---|---|---|---|
01 | 172.16.1.150 | codis-porxy | codis-proxy:19000 codis-dashborad:18080、codis-fe:18090 |
02 | 172.16.1.151 | codis-redis1 | codis-server:(6379&6380) redis-sentinel:26379 |
03 | 172.16.1.152 | codis-redis2 | codis-server:(6379&6380) redis-sentinel:26379 |
04 | 172.16.1.153 | codis-redis3 | codis-server:(6379&6380) redis-sentinel:26379 |
1.安装go
cd /application/tools/ wget https://dl.google.com/go/go1.10.2.linux-amd64.tar.gz tar -zxf go1.10.2.linux-amd64.tar.gz -C /usr/local/ cat << EOF >>/etc/profile export PATH=$PATH:/usr/local/go/bin export GOROOT=/usr/local/go export GOPATH=/usr/local/go/work path=$PATH:$HOME/bin:$GOROOT/bin:$GOPATH/bin EOF source /etc/profile
2.获取codis
wget https://github.com/CodisLabs/codis/archive/release3.2.zip mkdir -p $GOPATH/src/github.com/CodisLabs cd /usr/local/go/work/src/github.com/CodisLabs unzip /application/tools/release3.2 mv codis-release3.2/ codis cd codis/ make
#执行全部指令后,会在 bin 文件夹内生成 codis-proxy、codis-server三个可执行文件。另外, bin/assets 文件夹是 dashboard http 服务需要的前端资源) [[email protected] application]# ll /usr/local/go/work/src/github.com/CodisLabs/codis/bin total 107560 drwxr-xr-x 4 root root 4096 Jun 2 03:57 assets -rwxr-xr-x 1 root root 16237048 Jun 2 03:57 codis-admin -rwxr-xr-x 1 root root 17222240 Jun 2 03:56 codis-dashboard -rwxr-xr-x 1 root root 15512405 Jun 2 03:57 codis-fe -rwxr-xr-x 1 root root 14457471 Jun 2 03:57 codis-ha -rwxr-xr-x 1 root root 19425814 Jun 2 03:57 codis-proxy -rwxr-xr-x 1 root root 7983449 Jun 2 03:56 codis-server -rwxr-xr-x 1 root root 5578703 Jun 2 03:56 redis-benchmark -rwxr-xr-x 1 root root 5710507 Jun 2 03:56 redis-cli -rwxr-xr-x 1 root root 7983449 Jun 2 03:56 redis-sentinel -rw-r--r-- 1 root root 97 Jun 2 03:59 version [[email protected] application]#
3.codis-server配置
作用:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。具体的修改可以参考文档 redis 的修改。 #拷贝codis程序 mkdir -p /application/codis/bin mkdir /application/codis/conf mkdir /application/codis/log mkdir /application/codis/proc mkdir /application/codis/data/redis_data_6380 -p mkdir /application/codis/data/redis_data_6379 -p cp -fr /usr/local/go/work/src/github.com/CodisLabs/codis/bin/* /application/codis/bin/ cp -fr /usr/local/go/work/src/github.com/CodisLabs/codis/config/* /application/codis/conf/ #修改主配置 cd /application/codis/conf/ #主配置 cp redis.conf redis-6379.conf vim redis-6379.conf bind 172.16.1.150 daemonize yes #进程ID文件路径 pidfile /application/codis/proc/redis-6379.pid #绑定端口 port 6379 timeout 86400 tcp-keepalive 60 loglevel notice #日志文件路径 logfile "/application/codis/log/redis-6379.log" databases 16 save “” save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error no rdbcompression yes #dump文件 dbfilename dump-6379.rdb #dump路径 dir /application/codis/data/redis_data_6379 #Master密码(从主同步密码) masterauth "123456" slave-serve-stale-data yes repl-disable-tcp-nodelay no slave-priority 100 #鉴权密码(客户端连接密码) requirepass "123456" maxmemory 10gb maxmemory-policy allkeys-lru appendonly no appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 0 0 0 client-output-buffer-limit pubsub 0 0 0 hz 10 aof-rewrite-incremental-fsync yes repl-backlog-size 33554432 #修改从配置 cp redis-6379.conf redis-example.conf egrep -v "#|^$" redis-example.conf > redis-6380.conf sed -i "[email protected]@[email protected]" redis-6380.conf vim redis-6380.conf bind 172.16.1.150 protected-mode yes port 6380 tcp-backlog 511 timeout 86400 tcp-keepalive 60 daemonize yes supervised no pidfile /application/codis/proc/redis-6380.pid loglevel notice logfile "/application/codis/log/redis-6380.log" databases 16 #save "" #save 900 1 #save 300 10 #save 60 10000 stop-writes-on-bgsave-error no rdbcompression yes rdbchecksum yes dbfilename dump-6380.rdb dir /application/codis/data/redis_data_6380 masterauth 123456 slave-serve-stale-data yes slave-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no repl-backlog-size 33554432 slave-priority 100 requirepass 123456 maxmemory 10gb maxmemory-policy allkeys-lru appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 0 0 0 client-output-buffer-limit pubsub 0 0 0 hz 10 aof-rewrite-incremental-fsync yes #拷贝codis-server程序到其他节点 scp -r codis [email protected]:/application/ scp -r codis [email protected]:/application/ #启动脚本 vim /server/scripts/codis-server.sh if [ $# -eq 0 ] then echo "useage:sh $0 {start|stop}" exit 0 fi case $1 in start) /application/codis/bin/codis-server /application/codis/conf/redis-6379.conf /application/codis/bin/codis-server /application/codis/conf/redis-6380.conf ;; stop) ps -ef|grep codis-server|grep -v grep|awk '{print $2}'|xargs kill ;; esac #拷贝脚本到其他节点 scp /server/scripts/codis-server.sh [email protected]:/server/scripts/ scp /server/scripts/codis-server.sh [email protected]:/server/scripts/ #所有节点启动 sh /server/scripts/codis-server.sh start
4.Codis-dashboard
作用:集群管理工具,支持 codis-proxy、codis-server 的添加、删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard 维护集群下所有 codis-proxy 的状态的一致性。 1)对于同一个业务集群而言,同一个时刻 codis-dashboard 只能有 0个或者1个; 2)所有对集群的修改都必须通过 codis-dashboard 完成。 cd /application/codis/bin/ #生成配置 ./codis-dashboard --default-config | tee ../conf/dashboard.conf vim ../conf/dashboard.conf #外部存储类型 coordinator_name = "zookeeper" #外部存储IP列表 coordinator_addr = "172.16.1.111:2181" #项目名称 product_name = "my-codis" #集群密码(注意:需要与redis配置中的requirepass保持一致) product_auth = "123456" #RESTful API 端口 admin_addr = "0.0.0.0:18080" #为了防止出现dashboard监控页面中OPS始终为0的现象,需要将proxy的IP和主机名写到hosts文件中. 172.16.1.150 codis-porxy #启动程序 nohup ./codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN & #关闭 ./codis-admin --dashboard=172.16.1.150:18080 –auth=123456 --shutdown
5.Codis-proxy
作用:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外(不支持的命令列表),表现的和原生的 Redis 没有区别(就像 Twemproxy)。 1)对于同一个业务集群而言,可以同时部署多个 codis-proxy 实例; 2)不同 codis-proxy 之间由 codis-dashboard 保证状态同步 #修改配置 cd /application/codis/bin/ #生成配置 ./codis-proxy --default-config | tee ../conf/proxy.conf #修改配置 vim ../conf/proxy.conf #设置项目名 product_name = "my-codis" #设置登录dashboard的密码(注意:与redis中requirepass一致) product_auth = "123456" #Redis客户端的登录密码(注意:与redis中requirepass不一致) session_auth = "56789" # Set bind address for admin(rpc), tcp only. admin_addr = "0.0.0.0:11080" proto_type = "tcp4" #绑定端口(Redis客户端连接此端口) proxy_addr = "0.0.0.0:19000" #外部存储类型 jodis_name = "zookeeper" #外部存储列表 jodis_addr = "172.16.1.111:2181" jodis_timeout = "20s" #会话设置 如果不为0可能导致应用程序出现”write: broken pipe”的问题 session_recv_timeout = "0s" #启动程序 nohup ./codis-proxy --ncpu=24 --config=/application/codis/conf/proxy.conf --log=/application/codis/log/proxy.log &
6.Redis-sentinel
作用:Redis官方推荐的高可用性(HA)解决方案。它可以实现对Redis的监控、通知、自动故障转移。如果Master不能工作,则会自动启动故障转移进程,将其中的一个Slave提升为Master,其他的Slave重新设置新的Master服务 #修改配置 其余节点配置相同 vim /application/codis/conf/sentinel.conf bind 0.0.0.0 protected-mode no port 26379 dir /application/codis/data/ scp /application/codis/conf/sentinel.conf [email protected]:/application/codis/conf/ scp /application/codis/conf/sentinel.conf [email protected]:/application/codis/conf/ #启动程序 nohup /application/codis/bin/redis-sentinel /application/codis/conf/sentinel.conf &
7.Codis-fe
作用:集群管理界面。 1)多个集群实例共享可以共享同一个前端展示页面; 2)通过配置文件管理后端codis-dashboard列表,配置文件可自动更新 #生成配置 cd /application/codis/bin/ ./codis-admin --dashboard-list --zookeeper=172.16.1.111:2181 | tee ../conf/codis.json [ { "name": "my-codis", "dashboard": "codis-porxy:18080" }, { "name": "codis-chinasoft", "dashboard": "172.16.1.150:18080" } ] #启动程序 nohup ./codis-fe --ncpu=1 --log=/application/codis/log/fe.log --log-level=WARN --zookeeper=172.16.1.111:2181 --listen=172.16.1.150:8090 &
#访问172.16.1.150:8090设置
添加proxy
添加codis-server
添加redis-sentinels
配置slots
8.开机自启相关设置
#codis-server+Redis-sentinel vim /server/scripts/sentinel.sh if [ $# -eq 0 ] then echo "useage:sh $0 {start|stop}" exit 0 fi case $1 in start) nohup /application/codis/bin/redis-sentinel /application/codis/conf/sentinel.conf & ;; stop) ps -ef|grep redis-sentinel|grep -v grep|awk '{print $2}'|xargs kill ;; esac vim /server/scripts/auto_start_codis.sh sh /server/scripts/codis-server.sh start sh /server/scripts/sentinel.sh start chmod +x /server/scripts/auto_start_codis.sh vim /etc/rc.local /server/scripts/auto_start_codis.sh #Codis-fe + Codis-proxy + Codis-dashboard vim /server/scripts/codis.sh export GO_HOME=/usr/local/go/bin/ if [ $# -eq 0 ] then echo "useage:sh $0 {start|stop}" exit 0 fi case $1 in start) nohup /application/codis/bin/codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN & nohup /application/codis/bin/codis-proxy --ncpu=24 --config=/application/codis/conf/proxy.conf --log=/application/codis/log/proxy.log & nohup /application/codis/bin/codis-fe --ncpu=1 --log=/application/codis/log/fe.log --log-level=WARN --zookeeper=172.16.1.111:2181 --listen=172.16.1.150:8090 & ;; stop) ps -ef|grep codis-proxy|grep -v grep|awk '{print $2}'|xargs kill ps -ef|grep codis-fe|grep -v grep|awk '{print $2}'|xargs kill ps -ef|grep codis-dashboar|grep -v grep|awk '{print $2}'|xargs kill chmod +x /server/scripts/codis.sh vim /etc/rc.local /server/scripts/codis.sh start #由于是测试环境,我经常强制关机,导致codis-dashboard没有正常关闭.直接造成zookeeper里面的状态没有更新,最终新启动的codis-dashboard不能注册进zookeeper,一直提示已存在而被强制关闭. 解决方法如下 删除product /application/codis/bin/codis-admin --remove-lock --product=my-codis --zookeeper=172.16.1.111:2181 #再次启动 nohup /application/codis/bin/codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN &
9.性能测试
redis-benchmark参数解析:
-h ip地址
-p redis端口
-a 认证密码
-c 设定多少个并发连接
-n 总共多少个请求
-q 显示模式:简要模式
#集群测试 /application/codis/bin/redis-benchmark -h 172.16.1.150 -p 19000 -a 56789 -c 500 -n 1000000 -q #单节点测试 /application/codis/bin/redis-benchmark -h 172.16.1.151 -p 6739 -a 56789 -c 500 -n 1000000 -q
10.读写分布测试
vim /server/scripts/test_codis.sh #!/bin/bash hos="172.16.1.150" pot="19000" pawd="56789" cli="/application/codis/bin/redis-cli" keyset="keytest2" valueset="jlasdnfnsdfsdf;sdfhlkjahsdjlkfadfjkasdbbcjhdgasfyuefkbadjkhflk" dbname=2 a=0 for i in `seq 1 5000` do $cli -h $hos -p $pot -a $pawd -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null #echo $a let a++ done sh /server/scripts/test_codis.sh
key基本平均分布在3个组内
11.故障切换测试
#修改一下脚本 vim #!/bin/bash hos="172.16.1.150" pot="19000" pawd="56789" cli="/application/codis/bin/redis-cli" keyset="test2" valueset="asdklalksjdklajsdlkajs" dbname=2 a=0 for i in `seq 1 6000` do $cli -h $hos -p $pot -a $pawd -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null #echo $a let a++ done sh /server/scripts/test_codis.sh
#查找主库进程ss -ntplu | grep codis-server(172.16.1.152) tcp LISTEN 0 128 172.16.1.152:6379 *:* users:(("codis-server",1068,4)) tcp LISTEN 0 128 172.16.1.152:6380 *:* users:(("codis-server",1073,4)) #杀掉主库进程 kill -9 1068
共计5100个KEY
丢KEY的问题是由于redis-sentinel故障切换期间,整个codis集群并不会关闭对此故障redis-server的连接,所以codis-proxy依然会发送数据给当前故障的redis-server,而显然此时的redis-server是无法存储数据的,这就造成了丢key现象了.如果整个主从挂了,就会丢掉所有发送到此redis-server的key了,除非手工剔除故障节点.
虽然codis还自带有一种故障切换程序codis-ha,他属于一个守护进程,会连接codis-dashboard查看各节点状态,
1 2 | #执行一下命令启动codis-ha,端口是codis-dashboard的端口 /usr/local/codis/codis-ha --dashboard=172.16.1.150:18080 --log= /application/codis/log/ha .log --log-level=WARN & |
--dashboard 指定dashboard的地址和端口
--log 指定日志文件
--log-level 指定日志等级,有INFO,WARN,DEBUG,ERROR
但是这个软件也是有缺陷,他会自动连接上dashboard检测各主从结构的健康信息,检测间隔很快(默认3秒,可修改参数--interval),检测到故障后,会将故障主库或者从库强制下线并删除在dashboard登记的信息.
虽然切换速度非常快,只会有很少的丢key现象(3秒还是会丢一些),但是后面会把故障旧主库强制下线,需要手动修改配置并重新启动redis-server(codis-server),还要再在codis-fe界面添加配置才行.
显然这是做不到全自动管理,有点麻烦了,而且也会让redis-sentinel变得没有意义了,所以只能两个方式选其一.
虽然看上去丢key现象是少了,但是依然还是有丢key的情况,只能说是50步笑100步,而且该组内其他 slave 实例是不会自动改变状态的,这些 slave 仍将试图从旧的 master 上同步数据,因而会导致组内新的 master 和其他 slave 之间的数据不一致。因此当出现主从切换时,需要管理员手动创建新的 sync action 来完成新 master 与 slave 之间的数据同步,这样反而增加了手动操作的工作量,各位对于codis-ha和redis-sentinel的集群的选择还是需要多考虑一些实际情况.
所以,说到底就是codis的故障切换没有做好,如果对丢key可以容忍的,就开redis-sentinel就足够了,对于数据一致性要求高的,就开codis-ha加脚本来实现比较好,各取所需.
以上是关于十codis的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介创建消息生产者创建消息消费者自定义消息通道分组与持久化设置 RoutingKey)(代码片段