相关链接:
分布式原理:
集群:
服务器连接的主数据库宕机了,就进行主从切换,服务器连接从数据库,保证可用性(A)
一、cluster集群原理
Redis cluster 将所有数据划分为 16384(2 14 2^{14}214 )个槽位,每个 redis 节点负责其中一部分槽位。
cluster 集群是一种去中心化的集群方式; 如图,该集群由三个 redis
节点组成,每个节点负责整个集群的一部分数据,每个节点负责的数据
多少可能不一样。这三个节点相互连接组成一个对等的集群,它们之间通过一种特殊的二进制协议 交互集群信息; 当 redis cluster
的客户端来连接集群时,会得到一份集群的槽位配置信息。这样当客户端要查找 某个 key时,可以直接定位到目标节点。
客户端为了可以直接定位(对 key 通过 crc16 进行 hash 再对 取余)某个具体的 key 所在节
点,需要缓存槽位相关信息,这样才可以准确快速地定位到相应的节点。同时因为可能会存在客户
端与服务器存储槽位的信息不一致的情况,还需要纠正机制(通过返回 -MOVED 3999
127.0.0.1:6479 ,客户端收到后需要立即纠正本地的槽位映射表)来实现槽位信息的校验调整。 另外,redis cluster 的每个节点会将集群的配置信息持久化到配置文件中,这就要求确保配置文件 是可写的,而且尽量不要依靠人工修改配置文件;
cluster集群中的一致性算法和一致性哈希算法相似,但还是有所不同
1.建立集群
2.分配槽位
1、数据迁移
redis cluster 提供了工具 redis-trib 可以让运维人员手动调整槽位的分配情况,它采用 ruby 语言
开发,通过组合原生的 redis cluster 指令来实现。图中:A 为待迁移的源节点,B 为待迁移的目
标节点;
过程
如上图:redis 迁移的单位是槽,redis 是一个槽一个槽地进行迁移,当一个槽位正在迁移时,这
个槽就处于中间过渡状态。这个槽再源节点的状态为
migrating
,在目标节点的状态为
importing
,表示此时数据正在从源节点流向目标节点。迁移工具 redis-trib 首先在源节点和目标节点设置好中间过渡状态,然后一次性获取源节点槽位的
所有或者部分的 key 列表,再依次将 key 进行迁移。源节点对当前的 key 执行 dump 指令得到序
列化内容,然后向目标节点发送 restore 指令,目标节点将源节点的序列化内容进行反序列化并将
内容应用到目标节点的内容中,然后返回 +ok 给源节点,源节点收到后删除该 key;按照这些步
骤将所有待迁移的 key 进行迁移;
注意:迁移过程是同步的,迁移过程中源节点的主线程处于阻塞状态,直到key被删除;如果迁移
过程中源节点出现网络故障,这两个节点依然处于中间状态,重启后,redis-trib可继续迁移;
所以,redis-trib 迁移的过程是一个一个 key 来进行,如果这个 key 对应 val 内容很大,将会影响
到客户端的正常访问;
2、复制以及故障转移
cluster 集群中节点分为主节点和从节点,其中主节点用于处理槽,而从节点则用于复制该主节
点,并在主节点下线时,代替主节点继续处理命令请求;
故障检测
集群中每个节点都会定期地向集群中的其他节点发送 ping 消息,如果接收 ping 消息的节点没有
在规定时间内回复 pong 消息,那么这个没有回复 pong 消息的节点会被标记为 PFAIL(probable
fail);
集群中各个节点会通过互相发送消息的方式来交换集群中各个节点的状态信息;如果在一个集群
中,半数以上负责处理槽的主节点都将某个主节点 A 报告为疑似下线,那么这个主节点A将被标记
为下线(FAIL);标记主节点 A 为下线状态的主节点会广播这条消息,其他节点(包括A节点的从
节点)也会将A节点标识为 FAIL;
故障转移
当从节点发现自己的主节点进入FAIL状态,从节点将开始对下线主节点进行故障转移;
- 从数据最新的从节点中选举为主节点;
- 该从节点会执行 replica no one 命令,称为新的主节点;
- 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己;
- 新的主节点向集群广播一条 pong 消息,这条 pong 消息可以让集群中的其他节点立即知道 这个节点已经由从节点变成主节点,并且这个主节点已经接管了之前下线的主节点;
- 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移结束;
二、配置cluster集群
上图是,中间3个主数据库,每个主数据库还有1个从数据库
下面配置的时候就采用这种方式
1、创建文件夹
# 创建 6 个文件夹 mkdir -p 7001 7002 7003 7004 7005 7006 cd 7001 vi 7001.conf # 7001.conf 中的内容如下
2、编辑 7001.conf
pidfile "/home/mark/redis-data/7001/7001.pid" logfile "/home/mark/redis-data/7001/7001.log" dir /home/mark/redis-data/7001/ port 7001 daemonize yes cluster-enabled yes cluster-config-file nodes-7001.conf cluster-node-timeout 15000
cluster-enabled yes
是开启cluster集群的意思
3、复制配置
cp 7001/7001.conf 7002/7002.conf cp 7001/7001.conf 7003/7003.conf cp 7001/7001.conf 7004/7004.conf cp 7001/7001.conf 7005/7005.conf cp 7001/7001.conf 7006/7006.conf
4、修改配置
sed -i 's/7001/7002/g' 7002/7002.conf sed -i 's/7001/7003/g' 7003/7003.conf sed -i 's/7001/7004/g' 7004/7004.conf sed -i 's/7001/7005/g' 7005/7005.conf sed -i 's/7001/7006/g' 7006/7006.conf
比如sed -i 's/7001/7002/g' 7002/7002.conf
就是把7002/7002.conf中所有的7001修改成7002,比如pidfile要修改成7002.pid,等。
5、创建启动配置
写成sh文件
#!/bin/bash redis-server 7001/7001.conf redis-server 7002/7002.conf redis-server 7003/7003.conf redis-server 7004/7004.conf redis-server 7005/7005.conf redis-server 7006/7006.conf
启动sh文件,通过ps aux|grep redis-server就可以查看到启动6个的redis-server
6、客户端查看
客户端进入一个redis服务器节点
#-c是以cluster集群方式 redis-cli -c -p 7001
查看集群信息
cluster info
查看节点信息
cluster nodes
发现就一个节点,说集群还没有搭建起来
但是现在仅仅只是启动了6个redis服务器,还没有创建集群
7、创建集群
智能创建集群
redis-cli --cluster help # --cluster-replicas 后面对应的参数 为 一主对应几个从数据库 redis-cli --cluster create host1:port1 ... hostN:portN --cluster-replicas <arg> redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1
--cluster-replicas 1
表示,1个主数据库对应1个从数据库
在执行下面命令后
redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1
让我们确认下面的配置信息。
7001、7002、7003作为主数据库(master)
7004、7005、7006作为从数据库(slaver)
可以看到主数据分配的哈希槽信息slots
还可以看到根据replicates, 从数据库 作为哪个主数据库的从数据库,
如果访问的哈希值(hash(key)%16384),落在的哈希槽对应的数据库上,就去访问该数据库
手动创建集群
# 节点会面 cluster meet ip port # 分配槽位 cluster addslots slot # 分配主从 cluster replicate node-id
注意:以下的例子均以上述只能创建集群的结果演示。
8、测试集群
现在已经启动cluster集群了,可以进行测试
设置值
redis-cli -c -p 7004 set name nbsp
可以看到"name"的哈希槽位为5798,那么它的存放位置为主数据库7002
由于7004是从数据库
因此被重定向到7002(主数据库)了
数据已经在7002了,那么去7005可以查询到吗?
先退出之前的数据库,访问7005
redis-cli -c -p 7005
去查询"name",可以发现,又被重定向到7002了
结论:
从这里也可以理解去中心化是什么意思了,可以从任意一个节点去访问集群,而不是通过一个主的去访问集群。
在从数据库中不能进行读写,执行读写命令,都会重定向到主数据库中去。
比如7006是7002的从数据库,为什么在7002中度数据还会重定向到7002呢?
因此主从是异步复制的,具有最终一致性,因此redis认为主数据的数据比较新,就访问主数据库了,而不是对应的从数据库
主节点宕机
查看当前集群的节点信息
cluster nodes
关闭7002节点(使得主数据库宕机)
redis-cli -p 7002 shutdown
一个主数据库宕机了会发生什么呢?
先随便进一个数据,查看集群节点信息
redis-cli -c -p 7001 cluster nodes
可以看到7002有个fail,就是宕机了。7006多了master,也就是出现主从替换。7006这个从数据库在7002宕机后,换成了主数据库。(myself为当前客户端连接的数据库)
之前在7006中get name会发生跳转到7002,那么先在还会吗?
可以发现没有发生跳转
主节点重启
之前关闭的是7002,现在重启7002
redis-server 7002/7002.conf
可以发现7002变slaver了(从数据库)
扩容和缩容
- redis-server 7007/7007.conf
- redis-cli -cluster add-node 添加了主节点,但此时还不能访问,需要分配槽位
- 分配槽位
下图也就很好理解了,中间部分是集群,生产者放数据,消费者取数据
如果对于同一类数据,有时候想放在同一个节点,并不想分散在不同节点,就可以加一个花括号,以花括号里面的字符串(相近的字符串)做哈希,这样就可以映射到同一个节点中