Redis Cluster 提供一种Redis安装方式:数据自动在多个Redis节点间分片。
Redis Cluster 提供一定程度的高可用,在实际的环境中当某些节点失败或者不能通讯的情况下能够继续提供服务。大量节点失败的情况下集群也会停止服务(例如大多数主节点不可用)。
Redis集群提供的能力:
每个Redis集群节点需要打开两个TCP连接。端口6379提供给客户端连接,外加上一个端口16379,记起来也比较容易,在6379的基础上加10000。
端口16379提供给集群总线使用,总线用来集群节点间通信,使用的是二进制协议。集群总线的作用:失败检测、配置升级、故障转移授权等。客户端只能连接6379端口,不能连接端口16379。防火墙需要确保打开这两个端口,否则集群节点之间不能通信。
命令端口和总线端口之间总是相差10000 。
每个节点的端口原则:
集群总线使用二进制协议(不同于跟客户端通信协议)来进行节点之间数据交换,这个协议更适合节点间使用小的带宽和处理时间来交换数据。
Redis集群不是使用一致性哈希,而是使用哈希槽。整个redis集群有16384个哈希槽,决定一个key应该分配到那个槽的算法是:计算该key的CRC16结果再模16834。
集群中的每个节点负责一部分哈希槽,比如集群中有3个节点,则:
节点A存储的哈希槽范围是:0 – 5500
节点B存储的哈希槽范围是:5501 – 11000
节点C存储的哈希槽范围是:11001 – 16384
这样的分布方式方便节点的添加和删除。比如,需要新增一个节点D,只需要把A、B、C中的部分哈希槽数据移到D节点。同样,如果希望在集群中删除A节点,只需要把A节点的哈希槽的数据移到B和C节点,当A节点的数据全部被移走后,A节点就可以完全从集群中删除。
因为把哈希槽从一个节点移到另一个节点是不需要停机的,所以,增加或删除节点,或更改节点上的哈希槽,也是不需要停机的。
集群支持通过一个命令(或事务, 或lua脚本)同时操作多个key。通过"哈希标签"的概念,用户可以让多个key分配到同一个哈希槽。哈希标签在集群详细文档中有描述,这里做个简单介绍:如果key含有大括号"{}",则只有大括号中的字符串会参与哈希,比如"this{foo}"和"another{foo}"这2个key会分配到同一个哈希槽,所以可以在一个命令中同时操作他们。
为了保证在部分节点故障或网络不通时集群依然能正常工作,集群使用了主从模型,每个哈希槽有一(主节点)到N个副本(N-1个从节点)。
在我们刚才的集群例子中,有A,B,C三个节点,如果B节点故障集群就不能正常工作了,因为B节点中的哈希槽数据5501-11000没法操作。
但是,如果我们给每一个节点都增加一个从节点,就变成了:A,B,C三个节点是主节点,A1, B1, C1 分别是他们的从节点,当B节点宕机时,我们的集群也能正常运作。
B1节点是B节点的副本,如果B节点故障,集群会提升B1为主节点,从而让集群继续正常工作。但是,如果B和B1同时故障,集群就不能继续工作了。
Redis集群不能保证强一致性。一些已经向客户端确认写成功的操作,会在某些不确定的情况下丢失。
产生写操作丢失的第一个原因,是因为主从节点之间使用了异步的方式来同步数据。
一个写操作是这样一个流程:
从上面的流程可以看出来,主节点B并没有等从节点B1,B2,B3写完之后再回复客户端这次操作的结果。所以,如果主节点B在通知客户端写操作成功之后,但同步给从节点之前,主节点B故障了,其中一个没有收到该写操作的从节点会晋升成主节点,该写操作就这样永远丢失了。
就像传统的数据库,在不涉及到分布式的情况下,它每秒写回磁盘。为了提高一致性,可以在写盘完成之后再回复客户端,但这样就要损失性能。这种方式就等于Redis集群使用同步复制的方式。
基本上,在性能和一致性之间,需要一个权衡。
cluster-enabled yes : yes: 开启集群功能;此redis实例作为集群的一个节点;
cluster-config-file nodes.conf :集群配置文件,不可以人工编辑,集群中的节点自动维护,主要用于记录集群中有哪些节点、他们的状态以及一些持久化参数等,便于在重启的时候恢复集群状态
cluster-node-timeout 5000 :集群中的节点能够失联的最大时间,超过这个时间,则判定为故障
cluster-slave-validity-factor 0 :如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节点。如果设置成正数,则cluster-node-timeout乘以cluster-slave-validity-factor得到的时间,是从节点与主节点失联后,此从节点数据有效的最长时间,超过这个时间,从节点不会启动故障迁移。假设cluster-node-timeout=5,cluster-slave-validity-factor=10,则如果从节点跟主节点失联超过50秒,此从节点不能成为主节点。注意,如果此参数配置为非0,将可能出现由于某主节点失联却没有从节点能顶上的情况,从而导致集群不能正常工作,在这种情况下,只有等到原来的主节点重新回归到集群,集群才恢复运作。
cluster-migration-barrier 1 :主节点需要的最小从节点数,只有达到这个数,主节点失败时,它从节点才会进行迁移。更详细介绍可以看本教程后面关于副本迁移到部分。
cluster-require-full-coverage no :在部分key所在的节点不可用时,如果此参数设置为"yes"(默认值), 则整个集群停止接受操作;如果此参数设置为"no",则集群依然为可达节点上的key提供读操作
我们采用的6个redis实例进行,搭建一个3主3从的集群, 主从不需要我们自己配置, 在后面进行cluster配置时会自动生成主节点和从节点
cd /usr
mkdir redis-cluster-test
cd redis-cluster-test
// 依次创建文件夹 7000 7001 7002 7003 7004 7005;
mkdir 7000 7001 7002 7003 7004 7005
// 在每一个文件夹中创建配置文件 格式为:XXXX.conf; 文件名和文件夹的名称保持一致, 其实文件夹的名称也就是该redis实例的端口
touch 7000.conf 7001.conf 7002.conf 7003.conf 7004.conf 7005.conf
我们采用简单的配置
每一个配置文件中的内容如下(这里以7000.conf为例):
port 7000 //端口
cluster-enabled yes //开启集群
cluster-config-file nodes.conf // 集群的配置文件
cluster-node-timeout 5000 //主节点最大的失联时间 5000秒
appendonly yes //开启aof日志记录
redis-server 7000.conf //该命令必须在7000文件夹执行,不然找不到配置文件, 也可以在后面指定配置文件的绝对路径(redis-server /usr/redis-cluster-test/7000/7000.conf)
redis-cli --cluster create 127.0.0.1 7000 127.0.0.1 7001 127.0.0.1 7002 127.0.0.1 7003 127.0.0.1 7004 127.0.0.1 7005 --cluster-replicas 1
–cluster-replicas 1 : 表示集群的主节点有一个从节点
4. 输出日志:
连接客户端 redis-cli -p 7000
在添加key的时候回报错,错误信息显示是要移动到到7002节点上,这是因为我们在添加数据的时候,集群会根据算法计算出该键值对要保存到哪个节点上,然后进行重定向,我们连接的是普通客户端7000,不支持重定向到7002节点
我可以通过命令redis-cli -c -p 7000
连接集群客户端,如下:
前面提到: 每一个节点上都保存着整个的槽位的映射关系,再发现自己上没有时,会根据映射关系找出对应的节点进行重定向保存
我们让一组key保存在同一个节点上,在key上进行标记{oo}
会发现都保存在了7002节点上
通过命令redis-cli --cluster help
查询集群的相关命令
redis-cli --cluster help
Cluster Manager Commands:
create host1:port1 ... hostN:portN #创建集群
--cluster-replicas <arg> #从节点个数
check host:port #检查集群
--cluster-search-multiple-owners #检查是否有槽同时被分配给了多个节点
info host:port #查看集群状态
fix host:port #修复集群
--cluster-search-multiple-owners #修复槽的重复分配问题
reshard host:port #指定集群的任意一节点进行迁移slot,重新分slots
--cluster-from <arg> #需要从哪些源节点上迁移slot,可从多个源节点完成迁移,以逗号隔开,传递的是节点的node id,还可以直接传递--from all,这样源节点就是集群的所有节点,不传递该参数的话,则会在迁移过程中提示用户输入
--cluster-to <arg> #slot需要迁移的目的节点的node id,目的节点只能填写一个,不传递该参数的话,则会在迁移过程中提示用户输入
--cluster-slots <arg> #需要迁移的slot数量,不传递该参数的话,则会在迁移过程中提示用户输入。
--cluster-yes #指定迁移时的确认输入
--cluster-timeout <arg> #设置migrate命令的超时时间
--cluster-pipeline <arg> #定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10
--cluster-replace #是否直接replace到目标节点
rebalance host:port #指定集群的任意一节点进行平衡集群节点slot数量
--cluster-weight <node1=w1...nodeN=wN> #指定集群节点的权重
--cluster-use-empty-masters #设置可以让没有分配slot的主节点参与,默认不允许
--cluster-timeout <arg> #设置migrate命令的超时时间
--cluster-simulate #模拟rebalance操作,不会真正执行迁移操作
--cluster-pipeline <arg> #定义cluster getkeysinslot命令一次取出的key数量,默认值为10
--cluster-threshold <arg> #迁移的slot阈值超过threshold,执行rebalance操作
--cluster-replace #是否直接replace到目标节点
add-node new_host:new_port existing_host:existing_port #添加节点,把新节点加入到指定的集群,默认添加主节点
--cluster-slave #新节点作为从节点,默认随机一个主节点
--cluster-master-id <arg> #给新节点指定主节点
del-node host:port node_id #删除给定的一个节点,成功后关闭该节点服务
call host:port command arg arg .. arg #在集群的所有节点执行相关命令
set-timeout host:port milliseconds #设置cluster-node-timeout
import host:port #将外部redis数据导入集群
--cluster-from <arg> #将指定实例的数据导入到集群
--cluster-copy #migrate时指定copy
--cluster-replace #migrate时指定replace
help
命令演示:
创建集群:
redis-cli --cluster create 192.168.163.132:6379 192.168.163.132:6380 192.168.163.132:6381
redis-cli --cluster create 192.168.163.132:6379 192.168.163.132:6380 192.168.163.132:6381 192.168.163.132:6382 192.168.163.132:6383 192.168.163.132:6384 --cluster-replicas 1
redis-cli --cluster add-node 192.168.163.132:6382 192.168.163.132:6379
为一个指定集群添加节点,需要先连到该集群的任意一个节点IP(192.168.163.132:6379),再把新节点加入。该2个参数的顺序有要求:新加入的节点放前
4. 添加从节点
把6382节点加入到6379节点的集群中,并且当做node_id117457eab5071954faab5e81c3170600d5192270 的从节点。如果不指定 --cluster-master-id 会随机分配到任意一个主节点。
redis-cli --cluster add-node 192.168.163.132:6382 192.168.163.132:6379 --cluster-slave --cluster-master-id 117457eab5071954faab5e81c3170600d5192270
redis-cli --cluster del-node 127.0.0.1:7004 cf9d1748cf47e506ed6c28aac062ddecf02d1949
redis-cli --cluster check 127.0.0.1:7000
redis-cli --cluster info 192.168.163.132:6384
9.修复集群(修复集群和槽的重复分配问题)
redis-cli --cluster fix 192.168.163.132:6384 --cluster-search-multiple-owners
redis-cli --cluster reshard 192.168.163.132:6379 --cluster-from 117457eab5071954faab5e81c3170600d5192270 --cluster-to 815da8448f5d5a304df0353ca10d8f9b77016b28 --cluster-slots 10 --cluster-yes --cluster-timeout 5000 --cluster-pipeline 10 --cluster-replace
11.平衡各个节点的槽位数
redis-cli --cluster rebalance 127.0.0.1:7000