正常redis是单机的,这样的话会有一个问题,如果机器出现问题,不能工作了,那么redis就停止提供服务了,这对也业务来说是不可接受的,redis可提供的解决方案有哨兵(sentinel),codis,Cluster集群模型。
主从复制
目前主从同步有两种模式,增量同步和快照同步
-
增量同步
1. redis讲会影响数据库状态的指令记录在内存,然后异步将 buffer 中的指令同步到从节点,从节点一边执行同步的指 令流来达到和主节点一样的状态,一遍向主节点反馈自己同步到哪里了 (偏移量)。
2. 因为内存有限,不能将所有的指令到记录在内存。内存buffer是一个环形数组,如果满了,就从头开始覆盖,如果从节点的同步跟不上覆盖的话,那么就需要全量同步 -
全量同步
全量同步是很消耗性能的
- 首先先需要将内存的数据刷入到磁盘中,再根据内存的数据库生成一份rdb文件,这时候能影响数据库状态的操作也需要记录到内存buffer环形数组中,
- 通知从服务器来主服务器上获取rdb文件,并刷新内存,然后再将内存buffer同步到从服务器上。如果快照同 步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆 盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有 可能会陷入快照同步的死循环。
sentinel(哨兵模式)
主从复制模式下,如果master宕机,那么redis就不再提供写能力了,需要运维人员手动切换。
sentinel提供了对master节点的检测,如果master节点宕机了,可以自动地将从节点升级为master,可以将sentinel提供的能力认为是ZooKeeper
-
检测主观下线
sentinel 会向其他sentinel和redis服务器发送ping消息,如果在配置的时间范围内未服务,则将状态改为主观下线
-
检测客观下线
当一个sentinel检测到redis服务器下线了,这时候会询问其他sentinel服务器,当认为redis下线的机器数量到了配置的数量时,则这台redis服务器就被认为是客观下线了
-
选举领头羊
- 所有在线的sentinel都有资格参与
- 每次选举(可能会选不出结果)后,纪元计数都会+1
- 每个发现主服务器下线的sentinel会要求其他sentinel将自己选为局部领头羊
- 每个sentinel只有一个选择
- 如果有sentinel拥有半数以上的投票,那么他就成为了领头羊
- 如果在限定时间内,没有选举出零头羊,那么就开启第二次选举
-
故障转移
- 从下线的主服务器中挑选一个从服务器,让他成为主服务器
- 让所有其他从服务器从这个服务器中复制
- 设置旧mater成为新master的从服务器
Cluster集群
sentinel虽然提供了一个高可用的模型,但是却并没有提高redis的性能,比如说写性能。
入图所示,cluster提供槽功能,不同的node处理不同的槽,这样可以平摊master的写压力
-
槽指派
redis 集群通过分片的方式来保存数据库中的健值对,集群的整个数据库被16384个槽,每个key属于这些槽中的一个。Cluster 默认会对 key 值使用 crc32 算法进行 hash 得到一个整数值,然后用这个整数 值对 16384 进行取模来得到具体槽位。
-
跳转
当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自 己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端 去连这个节点去获取数据。
-
重新分片
当向redis插入一个新mater-node的时候,会指定槽范围,这时候会有进行槽分配,需要从原先的槽拥有者迁移到新master上。
Redis 迁移的单位是槽,Redis 一个槽一个槽进行迁移,当一个槽正在迁移时,这个槽就 处于中间过渡状态。这个槽在原节点的状态为 migrating,在目标节点的状态为 importing,表 示数据正在从源流向目标。下图就是槽指派和槽中间态定位的过程
- 迁移工具 redis-trib 首先会在源和目标节点设置好中间过渡状态,然后一次性获取源节 点槽位的所有 key 列表(keysinslot 指令,可以部分获取),再挨个 key 进行迁移。每个 key 的迁移过程是以原节点作为目标节点的「客户端」,原节点对当前的 key 执行 dump 指令得 到序列化内容,然后通过「客户端」向目标节点发送指令 restore 携带序列化的内容作为参 数,目标节点再进行反序列化就可以将内容恢复到目标节点的内存中,然后返回「客户端」 OK,原节点「客户端」收到后再把当前节点的 key 删除掉就完成了单个 key 迁移的整个过 程。
- 槽迁移过程中,redis的访问还是继续的,这时候redis会先访问旧节点,因为槽还未迁移完,还是属于旧节点的,如果旧节点上没有key,那么有两种可能性,1:是在新节点上,2:没有这个key,这时候redis会发一个ask命令到新节点上去询问获取数据
-
可能下线 (PFAIL-Possibly Fail) 与确定下线 (Fail)
与sentinel的主观下线和客观下线一样,因为redis-cluster是去中心化的,所以会有可能下线和确定下线。
- 如果一个master节点发现另一个master节点下线了,那么记为pfail,然后广播(用Gossip)
- 如果大部分节点都认为他下线了,那么就确定他下线了,开始故障转移
- 从该节点下的从节点中选择一个节点
- 被选中的节点会成为新的master节点,并且将槽指向自己
- 然后向集群的其他master节点广播
-
选举新master节点
- 节点的选举者是集群中的其他master节点,并且拥有一票选择,通过消息发送选举
- 从节点会接收master的消息(投票),如果票数超过一半,那么就可以晋升成为master