集群
概述
1、Redis 集群是一个提供在多个 Redis 节点间共享数据的程序集
2、优点
(1)通过分区来提供一定程度的可用性,自动分割数据到不同的节点上
(2)在实际环境中,整个集群的部分节点失败,或不可达的情况下,能够继续处理命令
(3)实现对 Redis 水平扩容,即启动 N 个 Redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N
(4)无中心配置相对简单
4、不足
(1)不支持处理多个 key 的命令,因为这需要在不同的节点间移动数据,从而达不到像 Redis 那样的性能,在高负载的情况下可能会导致不可预料的错误
(2)不支持多键 Redis 事务
(3)不支持 Lua 脚本
(4)已采用其他的集群方案,若代理或客户端分片的方案需要迁移至 Redis Cluster,需要整体迁移而不是逐步过渡,复杂度较大
Redis 集群配置参数
1、该实例是否作为 Redis 集群节点
# cluster-enabled yes
(1)普通的 Redis 实例不能成为 Redis 集群的一部分,只有作为集群节点启动的节点才可以
(2)为了将 Redis 实例作为集群节点启动,启用集群支持,需要取消注释
2、每个集群节点都有一个集群配置文件
# cluster-config-file nodes-6379.conf
(1)这个文件不需要手动编辑,它是由 Redis 节点创建、更新
(2)每个 Redis 集群节点都需要一个不同的集群配置文件
(3)确保在同一系统中运行的实例,没有重复的集群配置文件名称
3、集群节点超时:一个节点在无法到达的情况下,被认为处于失败状态的毫秒数
# cluster-node-timeout 15000
(1)大多数其他内部时间限制,是节点超时时间的几倍
(2)超过该时间(毫秒),集群自动进行主从切换
4、默认情况下,如果 Redis 集群节点检测到至少有一个哈希槽瘫痪(没有可用的节点为其服务),则停止接受查询
# cluster-require-full-coverage yes
(1)yes:如果集群部分瘫痪(例如:一系列的哈希槽不再被覆盖),所有的集群最终会变得不可用,一旦所有的槽恢复,它就会自动恢复可用
(2)no:正在工作的集群的子集,继续接受对未瘫痪的 key 空间部分的查询
搭建集群
1、Redis 集群命令行工具:redis-trib
(1)编写节点配置文件
(2)redis-trib 位于 Redis 源码的 src 文件夹中
(3)一个 Ruby,通过向实例发送特殊命令,完成创建新集群、检查集群、对集群进行重新分片(reshared)等工作
(4)Ruby 语言编写,需要安装 ruby 环境
2、创建一个新的集群(例)
./redis-trib.rb create --replicas 1 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
(1)--replicas 1:表示希望为集群中的每个主节点创建一个从节点
(2)其他参数则是该集群实例的地址列表,3 个 master、3 个 slave,redis-trib 打印出一份预想中的配置,输入 yes 确认,redis-trib 将这份配置应用到集群,让各个节点开始互相通讯
(3)最后可以得到信息:[OK] All 16384 slots covered,表示集群中的 16384 个槽都有至少一个主节点在处理,集群运作正常
(4)分配原则:尽量保证每个主数据库运行在不同 IP 地址,每个从库、主库不在同一个 IP 地址上
3、Redis 5.0 以后,集群管理集成到 redis-cli 中
redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003
(1)redis-cli --cluster 或 ./redis-trib.rb:代表集群操作命令
(2)create:代表是创建集群
(3)--replicas 1 或 --cluster-replicas 1:指定集群中每个 master 副本个数为 1,节点总数 / (replicas + 1) = master 数量
(4)节点列表中的前 n 个是 master,其它节点是 slave 节点,随机分配到不同 master
(5)redis-cli --cluster help:查看集群命令
Reshard 集群(重新分配哈希槽)
1、只需要指定一个节点,redis-cli 会自动找到其他节点
redis-cli --cluster reshard 127.0.0.1:7000
(1)指定重新分配哈希槽的数量
(2)指定接收哈希槽的目标节点
(3)指定被重新分配的源节点:all 表示集群中的全部节点参与重新分配,或指定节点 ID,输入 done 表示已经完成指定源节点
2、分配可以自动进行,而不需要以交互方式手动输入参数
redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
(1)允许建立一些自动化以经常重新分配,然而目前没有办法让 redis-cli 自动重新平衡集群,检查密钥在集群节点上的分布,并根据需要智能地移动插槽,这项功能将在未来被添加
(2)--cluster-yes 选项指示集群管理器对命令的提示自动回答 yes,允许它以非交互式模式运行。注意,这个选项也可以通过设置 REDISCLI_CLUSTER_YES 环境变量来激活
3、扩容后 / 缩容主节点前,必须 reshard
(1)旧节点的哈希槽分区连续,新节点的哈希槽分区不连续
(2)因为重新分配成本太高,所以旧节点各自分出哈希槽到新节点
添加节点
1、添加主节点(空白节点)
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
(1)新节点的地址为第一个参数,第二个参数为集群中的一个随机现有节点的地址
(2)在实际操作中,redis-cli 只是向节点发送了一个 CLUSTER MEET 消息,这也是可以手动完成的。然而,redis-cli 在操作前也会检查集群的状态,通过 redis-cli 执行集群操作是一个好习惯
(3)请注意,由于这个节点已经连接到集群,它已经能够正确地重定向客户端查询,并且一般来说是集群的一部分,然而,与其他主节点相比,它有两个特殊之处
(4)它不持有任何数据,因为它没有分配的哈希槽
(5)因为它是一个没有分配槽的主节点,当一个从节点想成为主节点时,它不参与选举过程
2、添加一个从节点
(1)第一个参数为从节点地址,第二个参数为集群中的随机现有节点,redis-cli 随机地将从节点,添加到从节点数量较少的主节点
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave
(2)指定主节点
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
移除一个节点
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`
1、第一个参数为集群中的一个随机节点,第二个参数为所删除节点的 ID
2、可以直接移除从节点
3、若删除一个主节点,它必须是空的
(1)如果主节点不是空的,需要在之前将数据从它那里转移到所有其他的主节点
(2)移除主节点的另一种方法,是在它的一个从节点上进行手动故障切换,并在它变成新主节点的从节点后移除该节点。显然,当想减少集群中主节点的实际数量时,这并没有帮助,在这种情况下,需要进行重新分配哈希槽
检查集群
redis-cli --cluster check
登录 Redis 集群节点
redis-cli -c -p 集群节点任一端口
1、采用集群策略连接,设置数据会自动切换到相应的写主机
2、Redis unstable 分支中的 redis-cli 程序实现非常基本的集群支持
3、在集群中录入值
(1)redis-cli 每次录入、查询键值,Redis 都会计算出该 key 应该送往的插槽,如果不是该客户端对应服务器的 slot,Redis 会报错,并告知应前往的 Redis 实例地址、端口
(2)redis-cli 客户端提供 –c 参数,实现自动重定向,防止路由失效
(3)不在一个 slot 下的键值,不能使用 mget、mset 等多键操作
(4)可以通过 {} 定义组的概念,从而使 key 中 {} 内相同内容的键值对,放到同一个 slot 中
开启主从关系
1、临时将当前服务器,转变为指定服务器的从属服务器(slave server)
SLAVEOF host port
(1)如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步
(2)对一个从属服务器执行命令 SLAVEOF NO ONE,将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃
(3)SLAVEOF NO ONE 不会丢弃同步所得数据集,可以在主服务器失败时,将从属服务器用作新的主服务器,从而实现无间断运行
2、与 SLAVEOF 相同,临时在线修改当前服务器的复制设置
REPLICAOF host port
(1)执行 REPLIACOF hostname port 会将当前服务器,转变为某一服务器的副本服务器
(2)如果当前服务器已经是某个主服务器(master server)的副本服务器,那么执行 REPLICAOF hostname port 将使当前服务器停止对原主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步
(3)对一个副本服务器执行命令 REPLICAOF NO ONE 将使得这个副本服务器关闭复制,并从副本服务器转变回主服务器,原来同步所得的数据集不会被丢弃
(4)当原主服务器停止服务,可以将该副本服务器切换为主服务器,应用可以使用新主服务器进行读写,原主服务器修复后,可将其设置为新主服务器的副本服务器
3、REPLICATION
(1)永久配置主从复制
# replicaof <masterip> <masterport>
(2)Redis 复制是异步的,但可以配置一个主站,如果其没有与至少一定数量的复制体连接,就停止接受写入
(3)如果复制链接丢失相对较少的时间,Redis 复制能够与主站进行部分重新同步,根据需要,用一个合理的值来配置复制积压的大小
(4)复制是自动的,不需要用户干预,在一个网络分区之后,复制会自动尝试重新连接到主站,并与它们重新同步
4、主从第一次同步是全量同步
5、master 判断 slave 是否为第一次同步数据
(1)Replication Id:简称 replid,是数据集的标记,id 一致,则说明是同一数据集,每一个 master 都有唯一 replid,slave 则会继承 master 节点的 replid
(2)offset:偏移量,随着记录在 repl_baklog 中的数据增多而逐渐增大,slave 完成同步时,也会记录当前同步的 offset,如果 slave 的 offset 小于 master 的 offset,说明 slave 数据落后于 master,需要更新
(3)因此 slave 数据同步,必须向 master 声明自己的 replication id、offset,master 才可以判断需要同步哪些数据
6、全量同步的流程
(1)slave 节点请求增量同步
(2)master 节点判断 replid,发现不一致,拒绝增量同步
(3)master 将完整内存数据生成 RDB,发送 RDB 到 slave
(4)slave 清空本地数据,加载 master 的 RDB
(5)master 将 RDB 期间的命令记录在 repl_baklog,并持续将 log 中的命令发送给 slave
(6)slave 执行接收到的命令,保持与 master 之间的同步
7、如果 slave 重启后同步,则执行增量同步
(1)repl_baklog 有大小上限,写满后会覆盖最早的数据
(2)如果 slave 断开时间过久,导致尚未备份的数据被覆盖,则无法基于 log 做增量同步,只能再次全量同步
8、优化 Redis 主从集群
(1)在 master 中配置 repl-diskless-sync yes,启用无磁盘复制,避免全量同步时的磁盘 I/O
(2)Redis 单节点上的内存占用不要太大,减少 RDB 导致的过多磁盘 I/O
(3)适当提高 repl_baklog 大小,slave 宕机时尽快实现故障恢复,尽可能避免全量同步
(4)限制一个 master 上的 slave 节点数量,过多 slave,则可以采用主-从-从链式结构,减少 master 压力
9、全量同步、增量同步区别
(1)全量同步:master 将完整内存数据生成 RDB,发送 RDB 到 slave,后续命令则记录在 repl_baklog,逐个发送给 slave
(2)增量同步:slave 提交自己的 offset 到 master,master 获取 repl_baklog 中从 offset 之后的命令给 slave
10、执行全量同步时机
(1)slave 节点第一次连接 master 节点时
(2)slave 节点断开时间太久,repl_baklog 中的 offset 已经被覆盖时
11、执行增量同步时机
(1)slave 节点断开又恢复,并且在 repl_baklog 中能找到 offset 时
Redis 提供哨兵(Sentinel)机制
1、实现主从集群的自动故障恢复
2、结构
3、作用
(1)监控:Sentinel 不断检查 master、slave 是否按预期工作
(2)自动故障恢复:如果 master 故障,Sentinel 会将一个 slave 提升为 master,当故障实例恢复后,也以新的 master 为主
(3)通知:Sentinel 充当 Redis 客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给 Redis 客户端
4、服务状态监控
(1)Sentinel 基于心跳机制监测服务状态,每隔 1 秒向集群的每个实例发送 ping 命令
(2)主观下线:如果某 Sentinel 节点发现某实例未在规定时间响应,则认为该实例主观下线
(3)客观下线:若超过指定数量(quorum)的 Sentinel 都认为该实例主观下线,则该实例客观下线,quorum 值最好超过 Sentinel 实例数量的一半
5、选举新的 master
(1)一旦发现 master 故障,sentinel 需要在 salve 中选择一个作为新的 master
(2)首先会判断 slave 节点与 master 节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该 slave 节点
(3)然后判断 slave 节点的 slave-priority 值,越小优先级越高,如果是 0 则永不参与选举
(4)如果 slave-prority 相等,则判断 slave 节点的 offset 值,越大说明数据越新,优先级越高
(5)最后是判断 slave 节点的运行 id 大小,越小优先级越高
6、当选中其中一个 slave 为新的 master 后,故障转移
(1)sentinel 给备选的 slave1 节点发送 slaveof no one 命令,让该节点成为 master
(2)sentinel 给所有其它 slave 发送 slaveof host port 命令,让这些 slave 成为新 master 的从节点,开始从新的 master 上同步数据
(3)最后,sentinel 将故障节点标记为 slave,当故障节点恢复后,会自动成为新的 master 的 slave 节点
7、RedisTemplate 哨兵模式
(1)在 Sentinel 集群监管下的 Redis 主从集群,其节点会因为自动故障转移而发生变化,Redis 客户端必须感知这种变化,及时更新连接信息
(2)Spring 的 RedisTemplate 底层利用 lettuce,实现节点的感知、自动切换
分片集群
1、主从、哨兵的问题
(1)海量数据存储问题
(2)高并发写的问题
(3)解决:分片集群
2、特征
(1)集群中有多个 master,每个 master 保存不同数据
(2)每个 master 都可以有多个 slave 节点
(3)master 之间通过 ping 监测彼此健康状态
(4)客户端请求可以访问集群任意节点,最终都会被转发到正确节点
3、结构
4、散列插槽
(1)Redis 会把每一个 master 节点,映射到 0~16383,共 16384 个插槽(hash slot)上
(2)数据 key 不是与节点绑定,而是与插槽绑定
(3)Redis 根据 key 有效部分,计算插槽值,分两种情况
(4)key 中包含 {},且 {} 中至少包含 1 个字符,{} 中的部分是有效部分
(5)key 中不包含 {},整个 key 都是有效部分
(6)计算方式是利用 CRC16 算法得到一个 hash 值,对 16384 取余,得到的余数就是 slot 值
(7)将同一类数据使用相同的有效部分,固定的保存在同一个 Redis 实例
5、无感知的数据迁移
(1)利用 cluster failover 命令,可以手动让集群中的某个 master 宕机,切换到执行 cluster failover 命令的这个 slave 节点
(2)手动 Failover 支持三种不同模式
(3)默认流程
(4)force:省略对 offset 的一致性校验
(5)takeover:直接执行第 5 步,忽略数据一致性、忽略 master 状态、忽略其它 master 意见
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战