一、Redis Cluster
1、集群
(1)单个redis存在不稳定性。当redis服务宕机了,就没有可用的服务了。
(2)单个redis的读写能力是有限的。
2、数据分布
分布式数据库首先要解决把整个数据集按照分区规则映射到多个节点的问题, 即把数据集划分到多个节点上, 每个节点负责整体数据的一个子集。
常用的分区方式:
顺序分区和哈希分区
哈希分区:
- 节点取余。使用特定的数据,如 Redis 的 键 或 用户 ID,再根据 节点数量 N 使用公式:hash(key)% N 计算出 哈希值,用来决定数据 映射 到哪一个节点上。
优点
这种方式的突出优点是 简单性,常用于 数据库 的 分库分表规则。
缺点
当 节点数量 变化时,如 扩容 或 收缩 节点,数据节点 映射关系 需要重新计算,会导致数据的 重新迁移。建议翻倍扩容。
- 一致性哈希分区 一致性哈希 可以很好的解决 稳定性问题,可以将所有的 存储节点 排列在 首尾相接 的 Hash 环上,每个 key 在计算 Hash 后会 顺时针 找到 临近的 存储节点 存放。而当有节点 加入 或 退出 时,仅影响该节点在 Hash 环上 顺时针相邻 的 后续节点,但还是有数据迁移。
- 虚拟槽分区
槽是集群内数据管理和迁移的基本单位。 采用大范围槽的主要目的是为了方便数据拆分和集群扩展。当前集群有 5 个节点,每个节点平均大约负责 3276 个 槽。由于采用 高质量 的 哈希算法,每个槽所映射的数据通常比较 均匀,将数据平均划分到 5 个节点进行 数据分区。Redis Cluster 就是采用 虚拟槽分区。
这种结构很容易 添加 或者 删除 节点。如果 增加 一个节点 6,就需要从节点 1 ~ 5 获得部分 槽 分配到节点 6 上。如果想 移除 节点 1,需要将节点 1 中的 槽 移到节点 2 ~ 5 上,然后将 没有任何槽 的节点 1 从集群中 移除 即可。
由于从一个节点将 哈希槽 移动到另一个节点并不会 停止服务,所以无论 添加删除或者 改变 某个节点的 哈希槽的数量 都不会造成 集群不可用 的状态.
3、搭建集群
单机架构:
分布式架构:
节点间彼此通信,每个节点都可以读写
节点通信采用P2P的Gossip(流言)协议,原理就是节点之间不断通信交换信息,一段时间以后多有的节点都会知道集群完整的信息。
Gossip消息:
- ping消息
集群内交换最频繁的消息, 集群内每个节点每秒向多个其他节点发送ping消息, 用于检测节点是否在线和交换彼此状态信息。 ping消息发送封装了自身节点和部分其他节点的状态数据。 - pong消息
当接收到ping、 meet消息时, 作为响应消息回复给发送方确认消息正常通信。 pong消息内部封装了自身状态数据。 节点也可以向集群内广播自身的pong消息来通知整个集群对自身状态进行更新。 - meet消息
用于通知新节点加入。 消息发送者通知接收者加入到当前集群, meet消息通信正常完成后, 接收节点会加入到集群中并进行周期性的ping、 pong消息交换。 - fail消息
当节点判定集群内另一个节点下线时, 会向集群内广播一个fail消息, 其他节点接收到fail消息之后把对应节点更新为下线状态。
优点:
①主从复制,每一个主节点都有一个从节点
②高可用,主节点故障后,会自动故障转移
③分片
4、集群伸缩
①伸缩原理
每个节点把一部分槽和数据迁移到新的节点6385, 每个节点负责的槽和数据相比之前变少了从而达到了集群扩容的目的。
扩展:启动一个服务,和其他节点握手(meet),然后进行槽的分配,然后进行槽(slot)的中数据的迁移。
集群伸缩=槽和数据在节点之间的移动。
②扩容集群
- 准备新节点:开启新的redis服务
- 加入集群(meet)>>>cluster meet:上述准备的新节点加入到集群中。
- 迁移槽
槽迁移计划 : 平均槽数量,平均分配16384个槽到各个节点。
- 迁移数据:
迁移数据③缩容集群
步骤:1、下线迁移槽,2、忘记节点(下线的节点和其他节点断开联系,cluster forget {downNodeId}),关闭节点
5、客户端路由
①moved重定向
在集群模式下, Redis接收任何键相关命令时首先计算键对应的槽, 再根据槽找出所对应的节点, 如果节点是自身, 则处理键命令; 否则回复MOVED重定向错误, 通知客户端请求正确的节点。
节点对于不属于它的键命令只回复重定向响应, 并不负责转发。
②ask重定向
moved和ask的区别:两者都是客户端重定向;moved已经确定迁移;ask,槽还在迁移中。
③smart客户端
6、故障转移
redis-cluster不需要使用redis sentinel,redis每个节点之间互相监控。redis集群自身实现了高可用。
1、故障发现
Redis集群内节点通过ping/pong消息实现节点通信, 消息不但可以传播节点槽信息, 还可以传播其他状态如: 主从状态、 节点故障等。 因此故障发现也是通过消息传播机制实现的, 主要环节包括: 主观下线(pfail) 和客观下线(fail) 。
主观下线简单来讲就是, 当cluster-note-timeout时间内某节点无法与另一个节点顺利完成ping消息通信时, 则将该节点标记为主观下线状态。 每个节点内的cluster State结构都需要保存其他节点信息, 用于从自身视角判断其他节点的状态。
当某个节点判断另一个节点主观下线后, 相应的节点状态会跟随消息在集群内传播。 ping/pong消息的消息体会携带集群1/10的其他节点状态数据,当接受节点发现消息体中含有主观下线的节点状态时, 会在本地找到故障节点ClusterNode结构, 保存到下线报告链表中。
通过Gossip消息传播, 集群内节点不断收集到故障节点的下线报告。 当半数以上持有槽的主节点都标记某个节点是主观下线时。 触发客观下线流程。2、故障恢复
步骤:
- 资格检查;
每个从节点检查与故障主节点的断线时间。超过一定时间(默认150s)就取消资格。- 准备选举时间;
对从节点中,偏移量最大的,设置更小的延迟,以便这个从节点称为新的master。意思就是:谁偏移量大,谁提前触发选举流程。- 选举投票;
只有持有槽的主节点才会处理故障选举消息。
投票过程其实是一个领导者选举的过程, 如集群内有N个持有槽的主节点代表有N张选票。 由于在每个配置纪元内持有槽的主节点只能投票给一个从节点, 因此只能有一个从节点获得N/2+1的选票, 保证能够找出唯一的从节点。
- 替换主节点。
1、把当前从节点取消复制变为主节点(slaveof no one)。
2、执行clusterDelSlot撤销故障主节点负责的槽,并执行clusterAddSlot把这些槽分配给自己。
3、向集群广播自己的pong消息,表明已经替换了故障节点。
7、常见问题
1、集群完整性
cluster-require-full-coverage 默认设置为yes,即集群中16384个槽全部可用,才对外提供服务。
建议设置为no
2、带宽消耗
集群内Gossip消息通信本身会消耗带宽, 官方建议集群最大规模在1000以内。单集群不适合部署超大规模的节点。 集群内所有节点通过ping/pong消息彼此交换信息。
3、Pub/Sub广播
在集群模式下内部实现对所有的publish命令都会向所有的节点进行广播, 造成每条publish数据都会在集群内所有节点传播一次, 加重带宽负担。
4、集群倾斜
数据倾斜
- 节点和槽分配不均
- 不同槽对应键值数量差异较大
- 包含bigkey
- 内存相关配置不一致
请求倾斜
- 热点key:重要的key或者bigkey
5、读写分离
集群模式的从节点不接受任何读写请求 。
6、数据迁移
7、集群和单机的比较
集群:批量操作支持有限,例如mget,mset必须在一个slot;不支持多数据库,只有db0;……
单机:
redis cluster,在很多情况下,并不一定需要。很多场景下,redis sentinel已经足够好。
二、redis集群搭建
1、原生命令安装
- 配置开启节点,配置6个,开启6个服务。节点启动
- meet,节点握手
cluster meet ip port 分别握手 redis-cli -p 7000 cluster meet 127.0.0.1 7001 redis-cli -p 7000 cluster meet 127.0.0.1 7002 redis-cli -p 7000 cluster meet 127.0.0.1 7003 redis-cli -p 7000 cluster meet 127.0.0.1 7004 redis-cli -p 7000 cluster meet 127.0.0.1 7005
集群已经互通
- 指派槽
cluster addslots slot [slot ...] shell命令,分配槽 start=$1 end=$2 port=$3 for slot in `seq ${start} ${end}` do redis-cli -p ${port} cluster addslots ${slot} done
- 主从关系,把7003当做7000的从节点,依次
cluster replicate node-id redis-cli -p 7003 cluster replicate node-id #把7003当做某个的从节点
2、官方
1、Ruby环境准备
安装ruby:https://www.cnblogs.com/xuliangxing/p/7132656.html?utm_source=itdadao&utm_medium=referral
安装rubygem redis依赖:
拷贝redis-trib.rb到集群根目录
redis-trib.rb 是 redis 官方推出的管理 redis 集群 的工具,集成在 redis 的源码 src 目录下,将基于 redis 提供的 集群命令 封装成 简单、便捷、实用 的 操作工具。
cp ./redis-trib.rb /usr/local/bin
2、redis-trib进行集群搭建
启动 6 台 redis 节点,配置和手动执行的配置一样。
sudo ./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6389 127.0.0.1:6390 127.0.0.1:6391
集群创建后,redis-trib 会先将 16384 个 哈希槽 分配到 3 个 主节点,即 redis-6379,redis-6380 和 redis-6381。然后将各个 从节点 指向 主节点,进行 数据同步。