1、Redis Cluster的工作原理
不管是Redis的主从复制,还是基于主从复制环境之上的Redis哨兵(Sentinel)模式,这些都是做到了数据的远程备份,并且在哨兵模式下还可以做到原主节点故障后的新主节点的自动转移,但是还是没办法解决Redis的单机性能瓶颈,为了解决这个问题,提高Redis的性能,我们可以用到分布式集群的方案,也就是Redis Cluster。 早期Redis分布式集群部署方案:
- 客户端分区:由客户端程序决定key写分配和写入的redis node,但是需要客户端自己实现写入分配、高可用管理和故障转移等;
- 代理方案:基于三方软件实现redis proxy,客户端先连接之代理层,由代理层实现key的写入分配,对客户端来说是有比较简单,但是对于集群管节点增减相对比较麻烦,而且代理本身也是单点和性能瓶颈。
在redis 3.0版本之后就推出了无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接起来。 Redis Cluster特点如下:
- 所有Redis节点使用(PING机制)互联;
- 集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效;
- 客户端不需要proxy即可直接连接redis,应用程序中需要配置有全部的redis服务器IP;
- redis cluster把所有的redis node 平均映射到 0-16383个槽位(slot)上,读写需要到指定的redis node上进行操作,因此有多少个redis node相当于redis 并发扩展了多少倍,每个redis node 承担16384/N个槽位;
- Redis cluster预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。
2、Redis Cluster部署架构说明
环境A:3台服务器,每台服务器启动两个实例,这个环境比较适合于测试环境。
环境B:6台服务器,可以分别准备三组master/slave,这个环境较适合于生产环境。
3、部署Redis Cluster
3.1、准备redis cluster的环境
- 每一个节点采用的redis版本需要相同、相同的密码、硬件配置也最好是相同的;
- 需要redis服务器没有任何数据;
这了我准备了8台主机,其中的6台我用来创建redis cluster,后续两台用来扩容的使用,后续的两台可以先不用配置等到扩容的时候在去配置即可。
IP地址 | redis版本 | 主机名 |
---|---|---|
10.0.0.100 | redis-6.2.7 | node1.stars.org |
10.0.0.101 | redis-6.2.7 | node2.stars.org |
10.0.0.102 | redis-6.2.7 | node3.stars.org |
10.0.0.103 | redis-6.2.7 | node4.stars.org |
10.0.0.104 | redis-6.2.7 | node5.stars.org |
10.0.0.105 | redis-6.2.7 | node6.stars.org |
10.0.0.106 | redis-6.2.7 | node7.stars.org |
10.0.0.107 | redis-6.2.7 | node8.stars.org |
3.2、启用redis cluster配置
每个节点修改redis配置,必须开启cluster功能的参数
#手动修改配置文件需要修改的项
bind 0.0.0.0
masterauth wm521314 #建议配置,否则后期的master和slave主从复制无法成功,还需再配置
requirepass wm521314
cluster-enabled yes #取消此行注释,必须开启集群,开启后redis 进程会有cluster标识
cluster-config-file nodes-6379.conf #取消此行注释,此为集群状态文件,记录主从关系及slot范围信息,由redis cluster集群自动创建和维护
cluster-require-full-coverage no #默认值为yes,设为no可以防止一个节点不可用导致整个cluster不可能
#在这里我就使用sed修改配置文件了
root@node1:~# sed -i.bak -e '/masterauth/a masterauth wm521314' -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@node1:~# systemctl restart redis
验证所有节点的Redis服务状态:
3.3、创建redis cluster
查看创建集群命令的帮助
命令说明:
create:用于创建集群,这里需要指定节点的IP和端口号,添加单个节点时需要手动分配槽位和对应从节点,同时添加多个节点时可加上--cluster-replicas指定每个主节点的从节点数量,自动进行槽位分配;
check:用于检查集群信息;
info:用于查看集群节点信息;
fix:用于修复集群;
reshard:用于在线热迁移集群时指定节点的槽位数据;
rebalance:用于平衡集群中各节点的槽位数量;
add-node:用于添加节点至集群中;
del-node:用于从集群中删除节点;
call:用于在集群中的所有节点执行命令;
import:导入外部Redis服务器的数据至集群中。
创建集群
根据上述的redis集群创建命令的相关说明,使用准备好的6个节点创建集群,每个主节点跟上一个从节点(这里的命令只需要在一个节点上执行即可)
3.4、验证redis cluster信息
3.4.1、验证节点槽位信息
使用--cluster参数配合info选项在通过集群中任意一个节点即可查看集群的槽位信息,还可以使用check选项,也是通过任意集群中的节点查看节点槽位信息是否正常,里面也包含了各节点的信息,如果出现异常的话会给出提示信息。
3.4.2、查看主从状态
3.4.3、查看集群的状态
3.5、验证集群中写入key
3.5.1、通过节点写入
3.5.1.1、写入失败
当我在node1节点上写入一个name1的key时,这时会发现报错了,说要转到node3上去写入编号为12933的槽位中。
3.5.1.2、在对应节点写入数据
3.5.1.3、从节点查看数据
在任何从节点上可以查看数据库中有多少key,即key的名称,想要看key的对应值需要到对应的主节点上去看。
3.5.1.4、查看key的对应槽位
查看上面创建的key对应的槽位,并查看其他的key对应的槽位
3.5.2、集群模式写入
通过节点写入key往往会出现无法写入的情况,因此我们可以使用-c选项开启集群模式来进行写入。
3.5.3、脚本批量写入key
#这里需要下载一些相关的包,我这使用的是ubuntu的1804版本系统,系统里面带了python3但是少了一些包需要自己安装
root@node1:~# apt -y install python3 python3-pip
root@node1:~# pip3 install redis-py-cluster
root@node1:~# vim redis_cluster_test.py
#!/usr/bin/env python3
from rediscluster import RedisCluster
if __name__ == '__main__':
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}]
try:
redis_conn= RedisCluster(startup_nodes=startup_nodes,password='wm521314', decode_responses=True)
except Exception as e:
print(e)
for i in range(0, 10000):
redis_conn.set('key'+str(i),'stars'+str(i))
print('key'+str(i)+':',redis_conn.get('key'+str(i)))
root@node1:~# chmod +x redis_cluster_test.py
root@node1:~# ./redis_cluster_test.py
验证数据是否写入成功
4、Redis cluster集群节点维护
当Redis集群运行之后,难免由于硬件故障、网络规划、业务增长等原因对已有集群进行相应的调整, 比如: 增加Redis node节点、减少节点、节点迁移、更换服务器等。增加节点和删除节点会涉及到已有的槽位重新分配及数据迁移;在生产环境的话,master节点是为奇数个的,这样是可以防止出现脑裂的现象的。
4.1、动态添加节点
4.1.1、准备主机
前面我准备好了两个备用的主机,分别是node7和node8,IP地址分别是10.0.0.10610.0.0.107,并已经安装了redis,配置文件我也按照前面的规律设置了。
4.1.2、添加节点到集群中
添加节点到集群的话是需要使用到add-node选项并指定新节点的IP地址和端口,添加节点的命令可以在集群中的任意节点上操作即可。
默认添加进去的节点是主节点,但是主节点上是没有槽位的,这个地方是需要重新重新划分槽位的。
4.1.3、重新分配槽位
当添加新的master节点进来时需要重新分配槽位的,这时就需要使用reshard选项,分配槽位时需要指定分配的槽位数、槽位的节点ID、从哪个节点获取槽位,这个是需要提前就要规划好的。
root@node1:~# redis-cli -a wm521314 --cluster reshard 10.0.0.100:6379
.......
How many slots do you want to move (from 1 to 16384)?4096 #新分配多少个槽位=16384/master个数
What is the receiving node ID? 7f05b5f044a366a190bc9273d7943f2a4de03fb7 #新的master的ID
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: all #输入all,将哪些源主机的槽位分配给新的节点,all是自动在所有的redis node选择划分,如果是从redis cluster删除某个主机可以使用此方式将指定主机上的槽位全部移动到别的redis主机
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes #确认分配
4.1.4、验证信息
当上面的槽位分配完后,我们可以用查看node7节点获得了分配槽位中的数据,在早期的版本的话是有的不支持已写入的数据直接进行槽位的划分。
4.1.5、添加从节点并验证对应关系
4.2、动态删除节点
在删除节点前是要看是删主节点还是从节点,如果是删除从节点的话,是可以直接删除的;如果是需要删除主节点的话,是需要先将要删除节点上的槽位迁移到集群中的其他节点上才可以进行删除。
4.2.1、迁移槽位
这里我就以集群中刚刚添加的node7为例,不过在删除节点之前,是需要先迁移上面槽位的。
4.2.2、删除节点
当迁移完槽位后就可以删除节点了,这是就可以使用del-node选项,并还要指定删除节点的ID。
4.2.3、验证集群信息
当删除完后可以检查一下集群的节点信息,我们这时就会发现只剩下6个节点了,刚刚添加的两个节点已经在集群中删除了。
4.3、模拟某个主节点宕机
从上面的图中可以发现主节点有node1、node2和node3,对应的从节点还是node5、node6和node4
4.3.1、从节点读写验证
这里我在node4节点从验证,node4的主节点是node3,在正常情况下从节点是无法进行读写操作的。
4.3.2、主节点故障
在从节点上查看redis的服务日志,我们会看到会等待一段时间进行故障转移,会把自己升成新的master节点。
4.3.3、验证集群中的信息
这时会发现node4节点上获取了node3节点的槽位和数据
4.3.4、验证写入key
这时成为了master节点就可以正常读写操作了。
4.3.5、恢复故障节点重回集群
这时在查看集群的节点信息时,会发现故障节点会自动加入到集群中,并成为node4节点的从节点。