介绍
虽然sentinel已经在replica基础上改进了许多,但是其仍然存在一个巨大问题,就是单个Master往往难以承担大量数据的写入,这就需要多个Master共同协调,由此引出了redis的cluster集群部署。
cluster使用了分片的方式,对原先集中在一个Master中的数据进行拆分(hash+整除),分片后存储到多台机器,以此降低单个Master的压力。图示:
同时,每个Master可以有多个slave,以此就能支持海量数据的读写。
另外,由于有多个master,Cluster自带sentinel的故障转移机制,因此也不需要配置哨兵。
还有,客户端也只需要连接到一个节点,即可将数据存储到整个redis集群中。
总结一下它的优点:
- 支持海量数据读写。
- 支持故障转移。
- 配置简单,客户端连接一个节点即可。
分片算法
在进行实际部署前,我们先讲解一下cluster是如何做到将原先在一个Master上的数据集进行分布式存储的。
目前有3类比较常用的分片算法:
哈希取余分区
第一个方法及其简单:
有几台master,就对一个key计算hash后直接取余几,结果是多少就直接存入哪台Master。
但是缺陷也很大:
- 如果集群扩容或集群缩小,就会需要重新计算所有key的取余结果,会占用大量计算资源,同时导致堵塞。
一致性哈希算法分区
第二种方式需要构建一致性hash环:将hash的取值范围围成一个圈。
构建环的目的是为了让master可以均分上述圆圈的周长:
每个Master负责一段范围,一个key计算hash后就直接根据其值标记到环中,放入负责对应位置的master中。
这样当发生集群扩容和缩小时,就直接更改每个或部分master的负责范围,迁移对应的key即可。
哈希槽分区
该方法是redis实际使用的方法,其思路就是分层。
对key进行hash(key)%16384(CRC16(key)mod16384)的计算,将所有key尽可能的均匀分布在16384个槽(slot)中,再让各个master选择数量近似的槽位,即可完成分片。
当发生集群扩容或集群缩减时,也只需要将适量的hash槽进行移动即可。
为什么是16384个?
首先,CRC16算法的最大取值为65536;redis集群推荐最大数量为1000,所以其取值范围在1000-65536应该均可。
但是考虑到cluster集群中的心跳消息会包含槽的使用范围(位图表示,1为使用,0为不使用),65536个位需要用到8KB,而16384只需要2KB,为了降低心跳消息的大小,所以采用了16384。(实际上会对位图采用压缩算法,但是在小集群中,因为每个master会使用大量的slot,所以压缩效率很差)
搭建集群
预计搭建一个三主三从的机子,每个虚拟机上两个redis服务器(端口是6379、6399)。
先把每个机都启动起来,我的配置文件:
bind 0.0.0.0
daemonize yes
protected-mode no
port 6379
logfile cluster_node6379.log
pidfile ./pid/cluster6379.pid
dir ./
dbfilename dump6379.rdb
appendonly yes
appendfilename "appendonly6379.aof"
requirepass 20030322
masterauth 20030322
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
启动后:
搭建集群:
redis-cli -a 20030322 --cluster create --cluster-replicas 1 192.168.146.128:6379 192.168.146.129:6399 192.168.146.129:6379 192.168.146.130:6399 192.168.146.130:6379 192.168.146.128:6399
然后就可以进入节点查看集群状态了:
集群示意图:
测试:为了保证路由成功,添加-c参数:redis-cli -a 20030322 -p 6379 -c
set会重定向到对应master。
get也会重定向到对应master,如果想要重定向到slave上,需要使用代理,负载均衡器或应用程序级别的分发策略。
查看key对应的槽位的命令:cluster keyslot <key>。
集群故障转移
关闭master2——192.168.146.128:6379。
在129:6379查看集群状态:
已成功变为master。
恢复128:6379:
128:6379变为slave。
可使用CLUSTER FAILOVER恢复原来集群结构。
128:6379变为master,129:6379变为slave。
集群扩容
启动两个新的redis-server,ip为128,端口为6419和6439。
将新增的6419作为master节点加入原有集群:redis-cli -a 20030322 --cluster add-node 192.168.146.128:6419 192.168.146.128:6379
查看集群状态:redis-cli -a 20030322 --cluster check 192.168.146.128:6379
重新分派槽号:redis-cli -a 20030322 --cluster reshard 192.168.146.128:6379
查看结果:
添加从节点:redis-cli -a 20030322 --cluster add-node 192.168.146.128:6439 192.168.146.128:6419 --cluster-slave --cluster-master-id 29236cf866bf38754d1d86d0db6c3fc64b64d95d
添加完成:
查看集群状况:slave添加完成。
集群缩容
删除6419和6439两个节点:
先删除6439:redis-cli -a 20030322 --cluster del-node 192.168.146.128:6439 42edef65dbd78125f5ba10718e5a953bde838f6c
删除完成,查看状态已经没有该slave了。
再删除6419,先清空6419的槽号:redis-cli -a 20030322 --cluster reshard 192.168.146.128:6419
现在查看状态,6419的slot数量就为0了(并且成为了slave):
然后再删除:redis-cli -a 20030322 --cluster del-node 192.168.146.128:6419 29236cf866bf38754d1d86d0db6c3fc64b64d95d
然后就完成了,只剩下最开始的6个机。