Redis Cluster实现多主写入
使用哨兵sentinel 只能解决Redis高可用问题,实现Redis的自动故障转移,但仍然无法解决Redis Master 单节点的性能瓶颈问题
为了解决单机性能的瓶颈,提高Redis 服务整体性能,可以使用分布式集群的解决方案
Redis 3.0 版本之后推出无中心架构的 Redis Cluster ,支持多个master节点并行写入和故障的自动转移 动能.
Redis Cluster 架构
Redis cluster 需要至少 3个master节点才能实现,slave节点数量不限,当然一般每个master都至少对应的有一个slave节点
如果有三个主节点采用哈希槽 hash slot 的方式来分配16384个槽位 slot
此三个节点分别承担的slot区间可以是如以下方式分配
节点M1 0-5460
节点M2 5461-10922
节点M3 10923-16383
每个key存储时,先经过哈希函数CRC16(key)得到一个整数,然后整数与16384取余,得到槽的数值, 然后找到对应的节点,将数据存放入对应的槽中.
集群通信
集群中节点之间的通信,保证了最多两次就能命中对应槽所在的节点.因为在每个节点中,都保存了其他节点的信息,知道哪个槽由哪个节点负责.这样即使第一次访问没有命中槽,但是会通知客户端, 该槽在哪个节点,这样访问对应节点就能精准命中.
1、节点A对节点B发送一个meet操作,B返回后表示A和B之间能够进行沟通
2、节点A对节点C发送meet操作,C返回后,A和C之间也能进行沟通.
3、然后B根据对A的了解,就能找到C,B和C之间也建立了联系.
4、直到所有节点都能建立联系.,这样每个节点都能互相知道对方负责哪些槽.
Redis集群部署架构说明
注意: 建立Redis Cluster 的节点需要清空数据
测试环境:3台服务器,每台服务器启动6379和6380两个redis 服务实例,适用于测试环境
生产环境:6台服务器,分别是三组master/slave,适用于生产环境
#集群节点
10.0.0.100
10.0.0.101
10.0.0.102
10.0.0.103
10.0.0.104
10.0.0.105
#预留服务器扩展使用
10.0.0.106
10.0.0.107
打通GUK验证,把安装脚本发送到各个主机
修改主机名
hostnamectl set-hostname node0
.
.
.
hostnamectl set-hostname node7
所有机器脚本编译安装redis
每个节点修改redis配置,必须开启cluster功能的参数
第一步:修改redis配置文件
[root@node0 ~]#vim /apps/redis/etc/redis.conf
手动修改redis.conf配置文件
bind 0.0.0.0
masterauth 123456 #建议配置,否则后期的master和slave主从复制无法成功,还需再配置
requirepass 123456
cluster-enabled yes #取消此行注释,必须开启集群,开启后redis进程会有cluster标识
cluster-config-file nodes-6379.conf #取消此行注释,此为集群状态数据文件,记录主从关系及slot范围信息,由redis cluster 集群自动创建和维护
cluster-require-full-coverage no #默认值为yes,设为no可以防止一个节点不可用导致整个cluster不可用
#如果是编译安装可以执行下面操作更改
sed -i.bak -e '/masterauth/a masterauth 123456' -e '/# cluster-enabled yes/a cluster-enabled yes' -e '/# cluster-config-file nodes-6379.conf/a cluster-config-file nodes-6379.conf' -e '/cluster-require-full-coverage yes/c cluster-require-full-coverage no' /apps/redis/etc/redis.conf
重启所有节点
[root@node0 ~]#systemctl restart redis
[root@node0 ~]#ps aux
redis 17:36 0:00 /apps/redis/bin/redis-server 0.0.0.0:6379 [cluster]
出现[cluster]就成功了,并额外增加一个集群内部通讯的端口16379
集群功能只支持0号数据库
创建集群
第二步:命令redis-cli的选项 --cluster-replicas 1 表示每个master对应一个slave节点
在任何一台机器上执行以下命令
redis-cli -a 123456 --cluster create 10.0.0.100:6379 10.0.0.101:6379 10.0.0.102:6379 10.0.0.103:6379 10.0.0.104:6379 10.0.0.105:6379 --cluster-replicas 1 #--cluster-replicas 1 每个主节点配套1个从节点
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.104:6379 to 10.0.0.100:6379
Adding replica 10.0.0.105:6379 to 10.0.0.101:6379
Adding replica 10.0.0.103:6379 to 10.0.0.102:6379
M: 26ab5f3fd31ef3972af895d953d6f66227de8217 10.0.0.100:6379
slots:[0-5460] (5461 slots) master
M: f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0 10.0.0.101:6379
slots:[5461-10922] (5462 slots) master
M: 08d6a31b426a2a7b8b76d829b1b547ba96e0da29 10.0.0.102:6379
slots:[10923-16383] (5461 slots) master
S: a205e64ddb338537d6873324d2f5f4c38bd6783b 10.0.0.103:6379
replicates 08d6a31b426a2a7b8b76d829b1b547ba96e0da29
S: dcaee05eb2e63ca4a8a4046124425108c05d6f2c 10.0.0.104:6379
replicates 26ab5f3fd31ef3972af895d953d6f66227de8217
S: afcaf762f2d5ee4944891a1bd6c77b40268778cd 10.0.0.105:6379
replicates f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0
Can I set the above configuration? (type 'yes' to accept): yes
输入yes后,分槽位
>>> Performing Cluster Check (using node 10.0.0.100:6379)
M: 26ab5f3fd31ef3972af895d953d6f66227de8217 10.0.0.100:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: dcaee05eb2e63ca4a8a4046124425108c05d6f2c 10.0.0.104:6379
slots: (0 slots) slave
replicates 26ab5f3fd31ef3972af895d953d6f66227de8217
M: 08d6a31b426a2a7b8b76d829b1b547ba96e0da29 10.0.0.102:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0 10.0.0.101:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: a205e64ddb338537d6873324d2f5f4c38bd6783b 10.0.0.103:6379
slots: (0 slots) slave
replicates 08d6a31b426a2a7b8b76d829b1b547ba96e0da29
S: afcaf762f2d5ee4944891a1bd6c77b40268778cd 10.0.0.105:6379
slots: (0 slots) slave
replicates f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
第三步:查看主从信息
[root@node0 ~]#cat /apps/redis/data/nodes-6379.confdcaee05eb2e63ca4a8a4046124425108c05d6f2c 10.0.0.104:6379@16379 slave 26ab5f3fd31ef3972af895d953d6f66227de8217 0 1667382573000 1 connected
08d6a31b426a2a7b8b76d829b1b547ba96e0da29 10.0.0.102:6379@16379 master - 0 1667382573000 3 connected 10923-16383
f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0 10.0.0.101:6379@16379 master - 0 1667382573354 2 connected 5461-10922
26ab5f3fd31ef3972af895d953d6f66227de8217 10.0.0.100:6379@16379 myself,master - 0 1667382571000 1 connected 0-5460
a205e64ddb338537d6873324d2f5f4c38bd6783b 10.0.0.103:6379@16379 slave 08d6a31b426a2a7b8b76d829b1b547ba96e0da29 0 1667382570326 3 connected
afcaf762f2d5ee4944891a1bd6c77b40268778cd 10.0.0.105:6379@16379 slave f70ab5aedde31319ba21fe6e44751bfd6a2f5bb0 0 1667382574364 2 connected
vars currentEpoch 6 lastVoteEpoch 0
[root@node0 ~]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> role
1) "master"
2) (integer) 8582
3) 1) 1) "10.0.0.104"
2) "6379"
3) "8582"
集群写入数据
写入数据,先经过哈希函数CRC16(key)得到一个整数,然后整数与16384取余,得到槽的数值, 然后找到对应的节点,将数据存放入对应的槽中. -c是以集群模式链接
[root@node0 ~]#redis-cli -a 123456 -c
127.0.0.1:6379> set k1 v1
-> Redirected to slot [12706] located at 10.0.0.102:6379
OK
10.0.0.102:6379> get k1
"v1"
加-c能写能查,但是keys *只能查到当前节点主从复制的数据,并且不支持mset 多keys写入
且所有的操作读和写都发生在主节点上,备用节点起不到性能分担的效果,就是主坏了,从节点能变成主
模拟故障实现故障转移
模拟node0节点出故障,需要相应的数秒故障转移时间,去node0对应的从节点上观察从节点状态
[root@node0 ~]#systemctl stop redis
[root@node4 ~]#redis-cli -a 123456
127.0.0.1:6379> role
1) "master"
2) (integer) 10848
3) (empty array)
成为主节点边可查可写了,
查看集群信息,显示100节点失败
[root@node4 ~]#cat /apps/redis/data/nodes-6379.conf
26ab5f3fd31ef3972af895d953d6f66227de8217 10.0.0.100:6379@16379 master,fail
恢复node0节点
[root@node0 ~]#systemctl start redis
查看集群信息
[root@node0 ~]#cat /apps/redis/data/nodes-6379.conf
node0自动变为node4的从节点了
python序实现Redis集群访问
范例
[root@ubuntu2004 ~]#apt -y install python3-pip
[root@ubuntu2004 ~]#pip3 install redis-py-cluster
[root@ubuntu2004 ~]#cat redis_cluster_test.py
#!/usr/bin/env python3
from rediscluster import RedisCluster
startup_nodes = [
{"host":"10.0.0.100", "port":6379},
{"host":"10.0.0.101", "port":6379},
{"host":"10.0.0.102", "port":6379},
{"host":"10.0.0.103", "port":6379},
{"host":"10.0.0.104", "port":6379},
{"host":"10.0.0.105", "port":6379}
]
redis_cnotallow= RedisCluster(startup_nodes=startup_nodes,password='123456', decode_respnotallow=True)
for i in range(0, 10000):
redis_conn.set('key'+str(i),'value'+str(i))
print('key'+str(i)+':',redis_conn.get('key'+str(i)))
[root@ubuntu2004 ~]#python3 redis_cluster_test.py
......
key9998: value9998
key9999: value9999
验证数据(数据分在三个主节点上)
[root@node0 ~]#redis-cli -a 123456
10.0.0.101:6379> DBSIZE
(integer) 3331