redis 集群
创建 redis 集群
- 在配置文件中修改
cluster-enabled
配置项为 yes - 启动 redis 实例
- 使用命令互相发现?节点握手(
cluster meet
命令) - 使用
cluster replicate
指定主副节点 - 分配哈希槽(hash slot)
cluster addslots
- 开始使用
数据写入
- 写入请求被发送到随机一个节点
- 该节点通过哈希计算(全字段计算、hashtag 计算),确认数据被放在哪个哈希槽(哪个主节点上)(dummy 客户端、smart 客户端)
- 进行请求转发,将重定向命令发送给客户端
- 客户端将请求发送到正确的主节点上(节点对不属于它的键命令只响应重定向,并不负责转发,由客户端完成转发操作)
- 执行写入操作
- 何时返回写入成功?(直接返回成功,异步写入从节点)
- 如何同步?(直接将写命令发送给从节点)
数据读取
- 读取请求被发送到随机一个节点
- 该节点通过哈希计算,确认数据被放在哪个哈希槽
- 如何判断去哪个节点读取数据(主节点还是对应的从节点)
- 执行读取操作
只有当从节点开启readonly
命令时(默认关闭),从节点才会接收读请求,这时主节点只接收写请求,实现读写分离?
过期数据如何同步过期状态
主节点在进行惰性删除和定期清理的时候,发送 del
命令到从节点。
从节点不会主动清理过期数据。
主从节点数据复制流程
从节点在主线程中每隔 1 秒发送 replconf ack{offset}
命令,给主节点上报当前的复制偏移量。
从节点刚连上主节点时会进行一次全量复制或部分复制,之后通过异步写操作进行数据同步。
复制过程是否会阻塞主线程 ?
如果复制持续失败,偏移量过大,是否有补救措施
如网络闪断,网络恢复后,会尝试采用全量复制(采用RDB方式)或部分复制(读取缓冲区数据)补全故障期间数据。
心跳机制
槽数据迁移过程
- 对目标节点发送
cluster setslot {slot} importing {sourceNodeId}
命令,通知目标节点准备导入数据 - 对源节点发送
cluster setslot {slot} migrating {targetNodeId}
命令,通知源节点准备迁出槽数据 - 源节点循环执行
cluster getkeysinslot {slot} {count}
命令,获取 count 个属于槽 {slot} 的键 - 在源节点上执行
migrate {targetIp} {targetPort}""0{timeout} keys {keys...}
命令,把获取的键通过流水线(pipeline)机制批量迁移到目标节点,批量迁移版本的migrate
命令在 Redis3.0.6 以上版本提供,之前的migrate
命令只能单个键迁移。对于大量 key 的场景,批量键迁移将极大降低节点之间网络 IO 次数 - 重复执行步骤 3 和步骤 4 直到槽下所有的键值数据迁移到目标节点
- 向所有主节点发送
cluster setslot {slot} node {targetNodeId}
命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点,将被迁移的槽指向新节点。
如何处理槽迁移过程中的读请求
当数据从源节点到目标节点迁移过程中,可能出现一部分数据在源节点,而另一部分在目标节点。
- 客户端根据本地 slot 缓存发送命令到源节点,如果存在键对应则直接执行返回结果给客户端。
- 如果节点返回
MOVED
错误,更新本地的 slot 到 Redis 节点的映射关系,然后重新发起请求。 - 如果数据正在迁移中,节点会回复 ASK 重定向异常。格式如下:
( error ) ASK { slot } { targetIP } : { targetPort }
。 - 客户端从 ASK 重定向异常提取出目标节点信息,发送
asking
命令到目标节点打开客户端连接标识,再执行键命令。
主节点故障
- 节点间会不间断地发送 ping-pong 消息进行通信,当通信持续失败时,发送节点会认为对方节点下线(主观下线)
- 当半数以上持有槽的主节点都标记某个节点是主观下线时,触法对该节点的客观下线
- 该主节点会广播一条 fail 消息,让集群内所有节点标记该节点下客观下线,同时通过故障节点的从节点触发故障转移流程。
- 故障节点的从节点根据复制偏移量以不同的优先级发起选举
- 由持有槽的主节点进行投票,超过二分之一得票的从节点当选
- 从节点执行
clusterDelSlot
操作撤销故障主节点负责的槽,并执行clusterAddSlot
把这些槽委派给自己。 - 向集群广播自己的 pong 消息,通知集群内所有节点。
从节点故障
cluster slots风暴
集群模式下哪些命令可能导致异常
- key 批量操作支持有限,如
mset
、mget
等,只支持对具有相同 slot 值的 key 执行批量操作。 - key 事务操作支持有限,只支持同一节点的 key
- 集群模式不支持多数据库空间
- 主从复制结构只支持一层,不支持树状嵌套结构