【0】代理功能与性能对比
目前市面上主流的代理包含:predixy、twemproxy、codis、redis-cerberus四款,这四款各有各的优势,我们逐个对比进行对比分析。

如上图,我们发现 twemproxy / codis 都不支持 redis-cluster,所以我们放弃使用;(但业界 codis 用的挺多的)
性能测试报告 2017:https://blog.csdn.net/rebaic/article/details/76384028
性能测试测试报告 2020:https://github.com/netease-im/camellia/blob/master/docs/redis-proxy/performance-report-8.md
redis架构发展:https://www.cnblogs.com/crazymakercircle/p/14282108.html
【1】predixy的安装和配置
【1.1】基本介绍
predixy 是高性能的适用于 redis 集群和哨兵的代理。
predixy github 地址:https://github.com/joyieldInc/predixy
predixy 编译安装需要 C++11 版本的编译器,至少需要 CentOS 7及以上版本才能编译安装。
对于 CentOS 6或更低版本,可以直接使用在 github release 中的二进制版本。
【1.2】特性、优点
- 同并轻量级
- 支持多线程
- 多平台支持:Linux、OSX、BSD、Windows( Cygwin )
- 支持Redis Sentinel,可配置一组或者多组redis
- 支持Redis集群
- 支持redis多种类型的命令,包括blpop、brpop、brpoplpush
- 支持扫描命令,无论是单个redis还是多个redis实例都支持
- 多键命令支持:mset/msetnx/mget/del/unlink/touch/exists
- 支持redis的多数据库,即可以使用select命令
- 支持事务,当前验证于Redis Sentinel下组redis组可用
- 支持脚本,包括命令:script load、eval、evalsha
- 支持发布订阅机制,也即Pub/Sub系列命令
- 多数据中心支持,删除支持
- 扩展的AUTH命令,部分的读、写、管理权限控制机制,健空间限制机制
- 日志可按级别输出,记录日志被io实时记录
- 日志文件可以按时间、大小自动切分
- 大量的统计信息,包括CPU、内存、请求、响应等信息
- 延迟监控信息,可以看到整体延迟,分秒还原事件延迟
【2】安装
【2.1】下载解压
tar -xzf predixy-1.0.5-bin-amd64-linux.tar.gz
mv predixy-1.0.5 /data/redis/
cd /data/redis/predixy-1.0.5/conf/
【2.2】修改配置文件 cluster.conf
配置文件官方说明:https://github.com/joyieldInc/predixy/blob/master/doc/config_CN.md
predixy 支持多种架构,由于使用的是 redis cluster,只需配置 redis cluster 对应的配置文件cluster.conf 即可。
内容如下:
##ClusterServerPool {
## [Password xxx] #default no
## [MasterReadPriority [0-100]] #default 50
## [StaticSlaveReadPriority [0-100]] #default 0
## [DynamicSlaveReadPriority [0-100]] #default 0
## [RefreshInterval number[s|ms|us]] #default 1, means 1 second
## [ServerTimeout number[s|ms|us]] #default 0, server connection socket read/write timeout
## [ServerFailureLimit number] #default 10
## [ServerRetryTimeout number[s|ms|us]] #default 1
## [KeepAlive seconds] #default 0, server connection tcp keepalive
# Examples:
ClusterServerPool {
Password 123456
MasterReadPriority 60
StaticSlaveReadPriority 50
DynamicSlaveReadPriority 50
RefreshInterval 1
ServerTimeout 1
ServerFailureLimit 10
ServerRetryTimeout 1
KeepAlive 120
Servers {
+ 192.168.191.176:6381
+ 192.168.191.176:6382
+ 192.168.191.211:6383
+ 192.168.191.211:6384
+ 192.168.191.70:6385
+ 192.168.191.70:6386
}
}
参数说明:
MasterReadPriority,StaticSlaveReadPriority,DynamicSlaveReadPriority 三个参数和 redis 本身配置文件中的 slave-priority 没任何关系的。
如果是自动发现找到的节点,则 DynamicSlaveReadPriority 会起作用,如果是直接配置的节点,则 StaticSlaveReadPriority 会起作用。
Master/SlaveReadPriority |
Master |
Slave1 |
Slave2 |
Fail-over notes |
60/50 |
all requests |
0 requests |
0 requests |
Master dead, read requests deliver to slave until master(maybe new master) alive |
60/0 |
all requests |
0 requests |
0 requests |
Master dead, all requests fail |
50/50 |
all write requests, 33.33%read requests |
33.33% read requests |
33.33% read requests |
- |
0/50 |
all write requests, 0 read requests |
50% read requests |
50% read requests |
all slaves dead, all read requests fail |
10/50 |
all write requests, 0 read requests |
50% read requests |
50% read requests |
all slaves dead, read requests deliver to master |
RefreshInterval : predixy 获取节点信息和集群 hash slot 集群信息的间隔
ServerFailureLimit : predixy 停止路由到节点之前失败的次数
ServerTimeout : 单个命令执行的超时时间
Password: 指定连接redis实例默认的密码,不指定的情况下表示redis不需要密码
【2.3】集群自动发现
在 Servers 部分配置集群中任意一个节点即可,predixy 会自动发现整个集群的信息,即使配置的节点挂掉后,predixy 代理仍然可正常工作。
通过自动发现集群,可以减少 cluster.conf 配置文件的修改及对 predixy 的重启操作。
但 predixy 无法删除曾经自动发现的节点,如果某节点下掉,predixy 仍会看到之前的节点,虽然不影响正常使用,日志则会不断报出错误信息。需重启 predixy 解决。
【2.4】配置 predixy.conf
Name Predixy001
Bind 0.0.0.0:7617
WorkerThreads 4
ClientTimeout 300
Log /data/redis/predixy-1.0.5/predixy.log
LogRotate 1d
LogRotate 200M
Include cluster.conf
注意 Include 部分,只需包括 cluster.conf,其他的则注释掉,否则可能会影响到 predixy的使用。
基本配置文件说明:
- predixy.conf,整体配置文件,会引用下面的配置文件
- cluster.conf,用于Redis Cluster时,配置后端redis信息
- sentinel.conf,用于Redis Sentinel时,配置后端redis信息
- auth.conf,代理中心访问权限控制配置,可以定义多个验证密码,可每个密码指定读、写、管理权限,以及定义可访问的健空间
- dc.conf,多数据中心支持,可以定义读写分离规则,读流量权重分配
- latency.conf, 延迟监控规则定义,可以指定需要监控的命令以及延时时间间隔
- command.conf,自定义命令扩展,用于命令扩展,支持redis 的插件以及自定义数据处理函数等
- standalone.conf,使用单击模式的redis配置
【2.5】启动predixy
cd /data/redis/predixy-1.0.5/bin/
cp predixy /data/redis/bin/ #我的redis 启动命令在这里,已添加进环境比那里
启动
看情况任选一即可
nohup predixy /data/redis/predixy-1.0.5/conf/predixy.conf &
nohup predixy /data/redis/predixy-1.0.5/conf/predixy.conf >/data/redis/predixy-1.0.5/predixy.log 2>&1 &
查看日志
tail -f /data/redis/predixy-1.0.5/predixy.log
如上,我们可以看到,由于配置文件 predixy.conf 配置的确是启动了4个进程,所以我们4个线程都就绪连接到集群所有机器了;对应构建连接池
predixy 添加环境变量
在 /etc/profile 中添加,然后在 /etc/rc.local 中设置开机启动 ,任选一即可
echo 'nohup predixy /data/redis/predixy-1.0.5/conf/predixy.conf &' >> /etc/rc.local
nohup predixy /usr/local/predixy-1.0.5/conf/predixy.conf > /data/redis/predixy-1.0.5/predixy.log 2>&1 &
【3】连接核验
代理连接,直接连 7617 端口就行
redis-cli -p 7617 info
可以看到 mget mset 都是没有问题的
同时代理日志信息如下:
我们通过集群的方式连接,发现key 什么的确实过去了
【4】故障转移测试
【4.1】关闭一个主库
redis-cli -h 192.168.191.70 -p 6385 -a 123456 shutdown
tail -f /data/redis/predixy-1.0.5/predixy.log
我们可以发现,b2 之前是在 6385
故障转移之后,6382 从库,经过故障转移接替 6385 成为主库;
我们继续连接代理查询:
如上图,安稳查询那么,证明故障转移是可以的;程序连接的代理,不会感知到任何东西;
同时我们查看代理日志:
看这,和炸街了一样,一直报;
这就如同【2.3】说的
在 Servers 部分配置集群中任意一个节点即可,predixy 会自动发现整个集群的信息,即使配置的节点挂掉后,predixy 代理仍然可正常工作。
通过自动发现集群,可以减少 cluster.conf 配置文件的修改及对 predixy 的重启操作。
但 predixy 无法删除曾经自动发现的节点,如果某节点下掉,predixy 仍会看到之前的节点,虽然不影响正常使用,日志则会不断报出错误信息。需重启 predixy 解决。
我们连接代理,在 info 中可以发现:
该配置信息依然在,但其状态 CurrentIsFail:1
总结:
代理可用,集群正常故障转移,程序无感;
运维问题:日志会一直报错;forget 也没用
【4.2】下掉一个从节点
我们下一个从节点看看;
我们下掉6383吧;
redis-cli -h 192.168.191.211 -p 6383 -a 123456 shutdown
查看代理日志:
会一直报错,连不上6383,直到去掉配置文件中的这个实例,重启代理
总结:
代理可用,集群正常故障转移,程序无感;
运维问题:日志会一直报错;forget 也没用
【4.3】关闭没有从库的主库(彻底关闭一对主从)
我们关闭 6386和6383这对主从吧,看看代理这时候会发生什么;
redis-cli -h 192.168.191.211 -p 6383 -a 123456 shutdown
redis-cli -h 192.168.191.70 -p 6386 -a 123456 shutdown
我们可以看到,现在redis-cluster 已经有问题了;
我们看看代理操作是什么情况;
我们发现是不能访问的!
集群参数:
集群参数也是没一个开的;
【4.4】代理下的集群参数测试,非全slot 可用性
我们这里就不测那么多了,测一个即可,节点先启动回去
然后我们测试 cluster-allow-reads-when-down yes 这个参数吧
redis-cli -h 192.168.191.176 -p 6381 -a 123456 config set cluster-allow-reads-when-down yes
redis-cli -h 192.168.191.176 -p 6382 -a 123456 config set cluster-allow-reads-when-down yes
redis-cli -h 192.168.191.211 -p 6383 -a 123456 config set cluster-allow-reads-when-down yes
redis-cli -h 192.168.191.211 -p 6384 -a 123456 config set cluster-allow-reads-when-down yes
redis-cli -h 192.168.191.70 -p 6385 -a 123456 config set cluster-allow-reads-when-down yes
redis-cli -h 192.168.191.70 -p 6386 -a 123456 config set cluster-allow-reads-when-down yes
然后继续关闭 6383 6386 一对主从的实例
redis-cli -h 192.168.191.211 -p 6383 -a 123456 shutdown
redis-cli -h 192.168.191.70 -p 6386 -a 123456 shutdown
然后我们看看代理,是否可以如之前测试那样,对现有key 是可以访问的;
我们发现,确实是这样; 直连集群也是如此;
我们上主库实例上去把开关打开;仅剩的 2个 主库 全都开启这个参数;
直接连redis-cluster集群上稳稳的是可以set 了; 如下图:
代理上也可以了 对现有 存在的 slot 的操作、不存在的key 也可以创建了;如下图:
代理日志,一直报,这是常态了,如下图
【5】集群水平扩展、收缩测试
【5.1】新增主节点
(1)新增 6387 主节点
redis-cli --cluster add-node 192.168.191.82:6387 192.168.191.176:6381 -a 123456
(2)自动平衡分配slot 给新空主节点 6387
redis-cli --cluster rebalance --cluster-use-empty-masters 192.168.191.176:6381 -a 123456
(3)check 一下看看现在的集群信息
(4)检查代理日志
如下图:
我们可以发现,新加入的主节点已经被自动发现且识别出来了;
(5)使用代理操作、查阅验证
我们用代理 mset 一下
如下图,我们连接redis-cluster 查阅验证,可以发现新的 key 的get set 已经完成,并且新的key 也分配到了 新加的主库 6387
如下图,我们连接代理,使用Info 查看也可以看到该主库了,由于代理开了4个线程,所以现在的连接数是4,且如果线程不挂,一般会一直保持 connections为4的;
(6)结论
没有任何问题啊,就真如redis-cluster 一样
【5.2】新增从节点
redis-cli --cluster add-node 192.168.191.82:6388 192.168.191.176:6381 --cluster-slave -a 123456
如下图:加入成功
如下图:我们可以看到,代理自动识别出来了新的,木有问题啊
要是挂掉它,我们可以发现,代理的日志依然是会一直报,这表示只要有节点加入进来了,不管你是forget 还是 del-node,也不管你是否是 cluster.conf 文件中配置的集群ip;
反正只要是集群自动发现加入过的,它都会报;如果要去掉,只能重启代理
【5.3】删除一主一从,缩容
先删除从库:
redis-cli --cluster del-node 192.168.191.176:6381 45a9ea5062479aaad68b6a9c4b5cc1942639dcb4 -a 123456
再删主库:
(1)迁移被删除主库上的 slot
把槽位平均非给其他主节点
redis-cli -a 123456 --cluster rebalance --cluster-weight
11ac5cf5004f22a55ee0afa2b221d120ad768f7d=1 f5dc23c602b57f6b09b4909d01289ff4d80220ed=1
4ba0958a0c9aa944962182673058fbc4c27952eb=1 4dfde05a131e9b8900553ef03ef41703737e449f=0
192.168.191.176:6381
(2)把节点从群集中移除,删除主节点
redis-cli -a 123456 --cluster del-node 192.168.191.176:6381 4dfde05a131e9b8900553ef03ef41703737e449f
(3)查看代理:
查看代理日志,如下图:
发现,居然没有报错(删除节点,但节点实例未关闭,所以它并没有报错,依然会连接该实例)
代理查看:
发现这2个都还在,这证明了,代理不会自动更新集群状态的删除信息,它只会自动更新新增的集群节点信息;
关闭这 6387 6388 实例;
我们发现,连不上又报错了;
【5.4】代理因为删除节点报错问题解决:重启代理
关闭:kill 进程
自动:predixy /data/redis/predixy-1.0.5/conf/predixy.conf &
重启后,报错信息没了;
登录代理:info 中的信息也更新了
6387 和 6388 实例就不见了;恢复正常;
【6】读写分离与读负载均衡的测试
Master/SlaveReadPriority |
Master |
Slave1 |
Slave2 |
Fail-over notes |
60/50 |
all requests |
0 requests |
0 requests |
Master dead, read requests deliver to slave until master(maybe new master) alive |
60/0 |
all requests |
0 requests |
0 requests |
Master dead, all requests fail |
50/50 |
all write requests, 33.33%read requests |
33.33% read requests |
33.33% read requests |
Master dead,read requests deliver to slave |
0/50 |
all write requests, 0 read requests |
50% read requests |
50% read requests |
all slaves dead, all read requests fail |
10/50 |
all write requests, 0 read requests |
50% read requests |
50% read requests |
all slaves dead, read requests deliver to master |
如下:我们现在的架构是
6382=>6385 ,6384=>6381 ,6386=>6383
【6.1】60/50 Master/SlaveReadPriority
现在的架构是:
6382=>6385 ,6384=>6381 ,6386=>6383
6350中,只有Ping
如上图,我们发现,发送了5次 a,5次 a 全在主库 6382;所以证明我们之前 60/50 的结论是正确的;
那么我们之前全是这种模式,就不做故障转移测试了,可以直接得出结论了;
结论:
所有的请求,都会发送给主库;
当主库宕机,故障转移期间,读操作会发送给从库;(也会尝试连接主库,连几次无果到阈值后读请求发送到从库)
新主库产生后,所有的请求发给新主库;
【6.2】60/0 Master/SlaveReadPriority
修改 cluster.conf 参数
MasterReadPriority 60
StaticSlaveReadPriority 0
DynamicSlaveReadPriority 0
重启:
现在的架构是:
6382=>6385 ,6384=>6381 ,6386=>6383
关闭 6382主库:
redis-cli -h 192.168.191.176 -p 6382 -a 123456 shutdown
如下:
我们发现故障转移期间,无法访问 a;等故障转移完毕,从库变成主库,就可以访问了;
结论:
所有的请求,都会发送给主库;
当主库宕机,故障转移期间,所有请求都会失败;
新主库产生后,所有的请求发给新主库;
【6.3】50/50
现在的架构是:
6382=>6385 ,6384=>6381 ,6386=>6383
如上面3个图,我们发现真的 50 50 读负载均衡了;
关闭 6382主库:
redis-cli -h 192.168.191.176 -p 6382 -a 123456 shutdown
如上图,我们可以发现,关闭 6382 主库之后,没有任何影响,之前在故障转移切换瞬间失败了一次;
如下图,关闭 6382 ,命令一发起它就收不到任何请求了;
如下图:6385实例的监控,我们发现主库挂了,从库还没有故障转移切换成主库时,read操作依然请求过来了;
结论:
读请求平均分发给所有的主从;
当主库宕机,故障转移期间,读请求都会平均分配到剩余存活的slave;
新主库产生后,读请求平均分发给所有的主从;
后面2个就不测了,知道它有效就行,先这样;