Redis系列之Redis Cluster
概述
Redis 2.8版本发布稳定版Redis Sentinel,不过Sentinel集群版存在一些问题:
- 高可用性:Sentinel集群对Redis既有的主从集群提供有限的高可用保障;
- 在线扩容:节点下线,触发选举,选举涉及两个阶段;新增节点,数据迁移过程麻烦。
对比Redis Sentinel
Redis Sentinel,即Redis 哨兵集群,区别如下:
- 集群架构
Redis Sentinel是一主多从, Redis Cluster是多主多从 - 数据一致性
- Redis Sentinel:由于没有分片,Sentinel对数据一致性的保障会更好一些,结构相对简单,脑裂问题会相对少一些,主从之间的数据一致性问题相对简单。主从切换后,存在数据一致性的小概率问题(例如主节点故障前的未同步数据丢失),但整体上保持一致性较好;
- Redis Cluster:由于数据分片,Redis Cluster在发生主从切换和网络分区时,可能存在数据不一致的风险。
- 扩展性
- Redis Sentinel:扩展性差,受限于单机性能和存储能力。尽管可以通过添加从节点分担读请求,但所有写操作仍然只能在主节点进行;
- Redis Cluster:扩展性好,可通过加节点来扩展存储容量和处理能力。每个节点只负责一部分数据,可实现负载均衡。
- 适用场景
- Redis Sentinel:适用于中小型应用,数据量和请求量相对较小的场景,或者不需要水平扩展的情况;
- Redis Cluster:适用于大规模应用,需要处理大数据量和高并发的场景,且需要水平扩展能力。
- 运维
- Redis Sentinel:运维复杂度较低,适合中小规模的Redis部署。需要维护Sentinel实例,并且在节点增加或减少时,配置相对简单;
- Redis Cluster:运维复杂度较高,适合大规模的Redis集群。节点的增删、分片的重新分配、集群状态的维护等都需要较高的运维能力。
简介
从Redis3.0开始,提供Redis Cluster集群支持,用于在多个Redis节点间共享数据,提高服务可用性。Redis Cluster采用去中心化结构,无需proxy代理,应用可以直接访问集群中的数据节点。
Redis Cluster要求至少需要3个Master才能组成一个集群,同时每个Master至少需要有一个Slave节点。各个节点之间保持TCP通信。当Master发生宕机,Redis Cluster自动会将对应的Slave节点提拔为Master,来重新对外提供服务。
Redis Cluster功能:负载均衡,故障切换,主从复制。
Redis Cluster集群,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384
决定。
通信
集群机器等数据信息通常有两种方式:
- 集中式:把集群信息保存在配置中心。好处:元数据的更新和读取,时效性非常好,一旦元数据出现变更,立即就更新到集中式的存储中,其他节点读取时立即就可以感知到。缺点:所有的元数据的跟新压力全部集中在一个地方,可能会导致元数据的存储有压力
- Gossip:好处:元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,降低压力。缺点,元数据更新有延时,可能导致部分操作有滞后。
通信的端口就是本身Redis监听端口+10000。假如监听端口6379,通信端口就是16379。
Gossip
Gossip协议的主要职责就是信息交换,常用的Gossip消息有:ping、pong、meet、fail等。
- meet:用于通知新节点加入。消息发送者通知接收者加入到当前集群,meet消息通信正常完成后,接收节点会加入到集群中并进行周期性的ping、pong消息交换
- ping:集群内交换最频繁的消息,集群内每个节点每秒向多个其他节点发送ping消息,用于检测节点是否在线和交换彼此状态信息。ping消息发送封装自身节点和部分其他节点的状态数据
- pong:当接收到ping、meet消息时,作为响应消息回复给发送方确认消息正常通信。pong消息内部封装了自身状态数据。节点也可以向集群内广播自身的pong消息来通知整个集群对自身状态进行更新
- fail:当节点判定集群内另一个节点下线时,会向集群内广播一个fail消息,其他节点接收到fail消息之后把对应节点更新为下线状态。
当新增一个节点,也就是meet消息过程:
- 节点A会为节点B创建一个clusterNode结构,并将该结构添加到自己的
clusterState.nodes
字典里。节点A根据cluster meet
命令给定的IP地址和端口号,向节点B发送一条meet消息。 - 节点B接收到节点A发送的meet消息,节点B会为节点A创建一个clusterNode结构,并将该结构添加到自己的
clusterState.nodes
字典里面。节点B向节点A返回一条pong消息。 - 节点A将受到节点B返回的pong消息,通过这条pong消息节点A可知节点B已成功接收到自己发送的meet消息。随后节点A将向节点B返回一条ping消息。
- 节点B将接收到节点A返回的ping消息,通过这条ping消息节点B可知节点A已经成功接收到自己返回的pong消息,握手完成。
- 之后,节点A会将节点B的信息通过Gossip协议传播给集群中的其他节点,让其他节点也与节点B进行握手。最终经过一段时间后,节点B会被集群中的所有节点认识。
当一个节点故障,怎么判断下线?
集群中的每个节点都会定期向其他节点发送ping命令,如果接受ping消息的节点在指定时间内没有回复pong,则发送ping的节点就把接受ping的节点标记为主观下线。
如果集群半数以上的主节点都将主节点A标记为主观下线,则节点A将被标记为客观下线(通过节点的广播)即下线。
故障切换
当一个从节点发现自己正在复制的主节点进入已下线状态时,从节点将开始对下线主节点进行故障转移,步骤如下:
- 从节点会执行
SLAVEOF no one
命令,成为新的主节点; - 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己;
- 新的主节点向集群广播一条pong消息,这条pong消息可以让集群中的其他节点立即知道这个节点已经由从节点变成主节点,并且这个主节点已经接管原本由已下线节点负责处理的槽;
- 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。
一致性Hash算法
参考一致性Hash算法。
一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。为了解决此问题,可考虑引入虚拟节点机制,即对每一个节点计算多个Hash,每个计算结果位置都放置一个虚拟节点,以实现数据的均匀分布和负载均衡。
Hash Slot
译为哈希槽,也叫Hash槽。Redis Cluster有16384个哈希槽,对每个Key计算CRC16
值后对16384取模,可获取Key对应的哈希槽。
Redis Cluster中每个Master都会持有部分槽。假如有3个Master,则每个Master持有5000多个哈希槽。哈希槽让节点的增加和移除变得简单,增加一个Master,就将其他Master的哈希槽移动部分过去;减少一个Master,就将它的哈希槽移动到其他Master上去。移动哈希槽的成本非常低。客户端API,可以对指定的数据,让他们走同一个哈希槽,通过hash tag
来实现。
任何一台机器节点宕机,另外几个节点都不受影响。因为Key查找的是哈希槽,而不是机器。
一致性
CAP一致性模型中,Redis Cluster是AP系统,它在网络分区时会优先保证可用性。
参数
提供如下配置项参数:
cluster-enabled
:cluster-config-file
:cluster-node-timeout
:表示当某个节点持续timeout的时间失联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换,即数据的重新复制;cluster-slave-validity-factor
:cluster-require-full-coverage
:推荐设置为no,表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用,如果为yes则集群不可用;cluster-migration-barrier
:数据迁移的副本临界数,这个参数表示的是,一个主节点在拥有多少个好的从节点的时候就要割让一个从节点出来给另一个没有任何从节点的主节点;cluster-allow-reads-when-down
:
问题
Redis Sentinel集群存在的问题(一致性和脑裂),Redis Cluster集群依旧存在。Redis Cluster集群模式的问题如下:
- 一致性:Redis Cluster是AP系统,它在网络分区时会优先保证可用性。在发生网络分区或某个主节点故障的情况下,如果刚提升的主节点还未完全同步旧主节点的数据,可能会出现数据丢失或数据不一致的情况;
- 脑裂问题:如果出现网络分区或通信故障,多个节点可能会认为自己是主节点,导致多个主节点同时接受写请求。这种情况下,不同的主节点可能会保存不同的数据,从而导致数据不一致。当网络恢复后,可能会有一些数据被丢弃或覆盖;
- 运维管理复杂:Redis Cluster需要管理多个节点,包括主从节点的状态、节点的增加和减少、哈希槽的重新分配等;随着集群规模的扩大,网络延迟和管理复杂性也会随之增加;
- 数据迁移:
- 哈希槽迁移:Redis Cluster使用哈希槽来分片和存储数据,但在节点新增或删除时,数据的重新分布可能导致负载不均衡或部分节点的存储压力过大;
- 热点问题:由于数据的分片机制,如果某些键特别热门,可能会导致对应的节点负载过高,出现性能瓶颈;
- 在进行数据迁移或重新分配哈希槽时,可能会对集群性能产生影响,尤其是在大规模数据迁移时,可能导致延迟增加和吞吐量下降;
- 客户端复杂:Redis Cluster需要支持客户端处理集群模式,包括重新连接、节点切换、哈希槽定位等功能。
优化措施
- 最小复制偏移量机制:Redis Cluster通过判断从节点的复制偏移量,确保提升为主节点的从节点具有最新的数据,以此减少数据丢失的风险;
- Quorum机制:Redis Cluster在进行主从切换时会要求多数派投票,这样可以降低脑裂的可能性;
客户端
JedisCluster集群寻址
JedisCluster配置只用指定集群中某一个节点的IP,端口信息即可。JedisCluster初始化时,会基于配置节点获取整个集群的信息(cluster nodes
命令)。拿到集群中所有Master信息,遍历每个Master节点,通过IP端口构建Jedis实例,然后put到一个全局nodes变量里面(Map类型) , key为IP端口,值为Jedis实例,nodes值如下:
nodes={172.19.93.120:6380=redis.clients.jedis.JedisPool@74ad1f1f,.....}
在上面遍历Master过程中,还做一件事,遍历此台Master负责的槽索引,然后又put到一个全局map slots里面。值为上面的Jedis实例, slots值如下:
slots={0=redis.clients.jedis.JedisPool@74ad1f1f,
1=redis.clients.jedis.JedisPool@74ad1f1f,
2=redis.clients.jedis.JedisPool@74ad1f1f,
....
5461 = redis.clients.jedis.JedisPool@65aa1f2f,
..其他Master机器
16383=redis.clients.jedis.JedisPool@756d1afd}
基于上面的slots变量,当有值set时,会先算出slot = get CRC16(key)&(16383-1)
,假如是12182,然后调用slots.get(12182)
得到Jedis实例,然后去操作Redis。如果发生MovedDataException,说明初始化得到的槽位与节点的对应关系有问题,(节点新增或者宕机)就会重置slots。
实战
安装
Redis 5.0之前的版本提供基于Ruby的集群管理工具redis-trib.rb
,需Ruby 2.3+版本。
安装Ruby
wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.2.tar.gz
tar -zxf ruby-2.6.2.tar.gz
cd ruby-2.6.2/
./configure --prefix=/usr/local/ruby
./configure --prefix=/opt/ruby/
make && make install
为redis-trib.rb
安装Redis驱动:gem install redis
Redis 5.X 版本已经将集群管理功能集成到redis-cli里面,不再推荐使用redis-trib.rb
。
命令
创建集群
cluster meet <ip> <port> # 将ip和port指定的redis实例添加到当前集群中,在同一个节点操作添加其他所有的节点
cluster replicate <node_id> # 将当前节点设置为指定节点的从节点,搭建集群时使用
查看集群信息
cluster info # 查看集群信息,包含几个节点,槽位分配和集群状态
cluster nodes # 展示redis集群中所有节点的ip端口,node id,主从关系等
cluster slaves <node_id> # 列出指定node_id从节点信息,node_id必须是Master角色,否则报错
运维集群节点
cluster failover # 手动进行故障转移
cluster forget <node_id> # 从集群中移除指定节点,这样就无法完成握手,过期时为60s,60s后两节点又会继续完成握手
cluster reset [HARD|SOFT] # 重置集群信息,soft是清空其他节点信息,但不修改自己的id,hard会修改自己的id,默认soft
cluster count-failure-reports <node_id> # 列出某个节点的故障报告
cluster SET-CONFIG-EPOCH # 设置节点epoch,只有在节点加入集群前才能设置
槽位相关操作
cluster slots # 列出节点和槽位的关系映射信息
cluster keyslot # 列出key被放置在哪个槽上
cluster countkeysinslot #
cluster getkeysinslot #
cluster setslot <slot> node <node_id> # 将槽指派给指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽,然后再进行指派
cluster setslot <slot> migrating <node_id> # 将本节点的槽迁移到指定的节点中
cluster setslot <slot> importing <node_id> # 从 node_id 指定的节点中导入槽 slot 到本节点
cluster setslot <slot> stable # 取消对槽 slot 的导入(import)或者迁移(migrate)
cluster flushslots # 移除指派给当前节点的所有槽,使当前节点变成一个没有指派任何槽的节点
拓展
16384个槽
为啥设计为16384个槽?
可能有些面试官真的会问出这个面试题。参考:GitHub issue 2576。
翻译:
- 如果槽位为65536,发送心跳信息的消息头达8k,心跳包过于庞大。
在消息头中,最占空间的是myslots[CLUSTER_SLOTS/8]
。Redis节点每秒需要发送一定数量的ping消息作为心跳包。当槽位为65536时,大小为65536÷8=8kb,ping消息头太大,浪费带宽。 - Redis的集群主节点数量基本不可能超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。不建议Redis Cluster节点数量超过1000个。节点数在1000以内的集群,16384个槽位够用 - 槽位越小,节点少的情况下,压缩率高。
Redis主节点的配置信息中,负责的哈希槽是通过bitmap保存。在传输过程中,会对bitmap进行压缩。如果bitmap的填充率,即slots / N
很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。而16384÷8=2kb
相关文章:

Redis系列之Redis Cluster
概述 Redis 2.8版本发布稳定版Redis Sentinel,不过Sentinel集群版存在一些问题: 高可用性:Sentinel集群对Redis既有的主从集群提供有限的高可用保障;在线扩容:节点下线,触发选举,选举涉及两个…...

网站证书过期导致WordPress后台无法登录问题解决,页面样式丢失
1、首先打开网站目录文件\wp-includes\functions.php,找到代码,应该就是就在在第8行。 require( ABSPATH . WPINC . /option.php ); 在下面添加以下代码,作用就是把http替换为https add_filter(script_loader_src, agnostic_script_loader…...

LeetCode刷题笔记第191题:位1的个数
LeetCode刷题笔记第191题:位1的个数 题目: 想法: 通过位运算判断二级制形式中有多少个1,代码及解释如下: class Solution:def hammingWeight(self, n: int) -> int:return sum(1 for i in range(32) if n & …...

C语言—函数栈帧
函数,一般都有返回值,函数名,参数,再下来还有什么mian函数,函数写出来就是要被调用的,上面图片上的代码,main函数和myadd函数,都要在自己的栈结构什么形成自己的栈,可以帮…...

IDEA 2022.1.4用前需知
目录 一、配置国内源 二、正确再次创建新项目方式 IDEA 2022.1.4下载地址 一、配置国内源 1、查看本地仓库地址 2、设置国内源-添加Setting.xml文件内容 3、修改目录(考虑到当前硬盘空间大小,英文目录名) 1)创建你要移动过去…...

Python数据可视化案例——折线图
目录 json介绍: Pyecharts介绍 安装pyecharts包 构建一个基础的折线图 配置全局配置项 综合案例: 使用工具对数据进行查看 : 数据处理 json介绍: json是一种轻量级的数据交互格式,采用完全独立于编程语言的文…...

Ubuntu虚拟机安装及汉化
一、安装 1.勾选典型(推荐)(T)——点击下一步 2.点击浏览找到光盘映像文件打开(此文件很重要安装好后安装包不要卸载,放在不容易被删除的地方)——点击下一步 3.将信息补充完整——点击下一步 4.点击浏览选择要将虚拟机安装在哪个路径&…...

记2024-08原生微信小程序开发
继2024.08 最近需要开发一个微信小程序的一个功能模块,但是之前在学的时候都是好几年前的东东了,然后重新快速过了一遍b站大学的教程,这篇文章就是基于教程进行的一些总结,和自己开发过程当中使用到的一些点和一些技巧什么的吧。 …...

嵌入式linux系统镜像制作day1
点击上方"蓝字"关注我们 01、前言 嵌入式设备(例如心电图检测仪,售票系统等)。尽管,嵌入式设备像那些智能手机一样,绝大多数都使用同样的硬件和软件,包括系统芯片SoC、储存、连接和多媒体接口、…...

【相机与图像】2. 相机内外参的标定的代码示例
1 摄像头内参的标定 【相机标定具体操作】 使用将要标定的摄像头,以不同的角度采集棋盘格,要保证视野内出现完整的棋盘格。采集图片数量约15张左右即可。 以11*8的棋盘格为例,具体流程如下: step 1. 设置棋盘格3D点;通…...

重启人生计划-拒绝内耗
🥳🥳🥳 茫茫人海千千万万,感谢这一刻你看到了我的文章,感谢观赏,大家好呀,我是最爱吃鱼罐头,大家可以叫鱼罐头呦~🥳🥳🥳 如果你觉得这个【重启人生…...

盘点电脑开机慢的几大高频原因
常规的话一台电脑正常我们都要用个2年以上的时间,有的可能更长,5年的都有,而电脑目前占多数的主流操作系统就是微软的Windows。那么随着使用年限的增加,无论是系统还是电脑硬件,都会随着使用次数和使用的时间的增加而有损耗,系统软件上就是文件越来越臃肿,空间越来越小,…...

2-64 基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法
基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法,可为异构代理网络上的多代理多任务分配问题提供良好的解决方案。支持具有有效时间窗口的任务、异构代理-任务兼容性要求,以及平衡任务奖励和燃料成本的得分函数。奖励和燃料成本的分数函数。程…...

Win10 去掉桌面右上角 了解有关此图片的信息
1. 进入注册表 Win R运行regedit 2. 找到以下路径 计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel 3. 新建 DWORD(32位)值(D) 右击 NewStartPanel新建 DWORD…...

tcpdump入门——抓取三次握手数据包
1. 使用docker启动一个tcp应用 参考:https://blog.csdn.net/LONG_Yi_1994/article/details/141175526 2. 获取容器id docker ps |grep gochat 3. 获取容器的 PID 首先,你需要获得容器的进程 ID(PID)。可以使用 docker inspect…...

漏洞复现-GitLab任意读取文件(CVE-2023-2825)
1.漏洞描述 GitLab是一个用于仓库管理系统的开源项目,其使用Git作为代码管理工具,可通过Web界面访问公开或私人项目。据悉,该漏洞影响 GitLab社区版(CE)和企业版(EE)的 16.0.0 版本,其它更早的版本几乎都不受影响。 该漏洞存在于GitLab CE/EE版本16.0.0…...

二叉树——9.找树左下角的值
力扣题目链接 给定一个二叉树,在树的最后一行找到最左边的值。 示例: 输出:7 题干很简单,找到树的最后一行,在该行找到最左边的值,结合完整代码进行分析。 完整代码如下: class Solution:d…...

如何用github制作个人网站
这里整理了一些参考资料。总结来说,如果系统学过html网页制作的话,可以不用看这篇博客了;这里适合于小白,就是那种 没有做过网页、打算以别人优秀的个人主页为框架做网页的小白。 一、简单说明 这是利用github.io来制作网页的&a…...

二.PhotoKit - 相册权限(彻底读懂权限管理)
引言 用户的照片和视频算是用户最私密的数据之一,由于内置的隐私保护功能,APP只有在用户明确授权的前提下才能访问用户的照片库。从iOS14 开始,PhotoKit进一步增强了用户的隐私控制,用户可以选择指定的照片或者视频资源的访问权限…...

二叉树------最小堆,最大堆。
什么是最小堆: 堆是一种二叉树,最小堆中所有父亲节点的值都要比自己的子节点的值要小。而根节点称为堆顶。根据定义我们可以得到堆中最小元素就在堆顶。(节点左上角是编号,内部是元素值) 假设该图中的堆顶元素是24呢&a…...

预约功能的知识整理
前置知识 如果项目为小程序的开发项目中: 我们确定数据库中有的字段有: 预约人姓名、手机号、家人名称、预约时间 根据我们的经定一表必须要有的6个字段: 主键、创建时间、修改时间、创建人、修改人、备注 使用我们现在有的字段为: 主键…...

Linux的常用操作-02
一:Linux的系统目录结构 /bin bin是ary的缩写,这个目录存放着最经常用的命令 /boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。 /dev:dev是Device(设备)的缩写,该目录下存放的是Lin…...

Android Studio 连接手机进行调试
总所周知,Android Studio里的虚拟手机下载后又大又难用。不如直接连手机用。本篇文章主要内容为Android Studio怎么连接手机进行程序调试。 1. 在AndroidSDK中下载google USB Driver: 2. 连接手机: 进入电脑设备管理器界面。并点开便携设备,…...

Vue3项目创建及相关配置
Vue是一种用于构建用户界面的JavaScript框架。它采用了一种称为MVVM(Model-View-ViewModel)的架构模式。 MVVM是一种将用户界面与业务逻辑和数据分离的设计模式。它包括三个部分: Model(模型):表示应用程序…...

【Python】Python中一些有趣的用法
Python是一种非常灵活和强大的编程语言,它有很多有趣的用法,以下是一些例子: 一行代码实现FizzBuzz: print(\n.join([FizzBuzz[i%3*4:i%5*8:-1] or str(i) for i in range(1, 101)]))使用列表推导式生成斐波那契数列: …...

RCE复现问题和研究
目录 先了解一些常见的知识点 PHP常见命令执行函数 call_user_func eval() call_user_func_array array_filter 实战演练(RCE)PHP Eval函数参数限制在16个字符的情况下 ,如何拿到Webshell? 1、长度…...

MySQL中的索引——适合创建索引的情况
1.适合创建索引的情况 1、字段的数值有唯一性的限制 2、频繁作为 WHERE 查询条件的字段 某个字段在 SELECT 语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。 …...

5款在线伪原创改写软件,智能改写文章效果好
在这个信息爆炸的时代,内容创作变得愈发重要,而对于创作者来说,有时需要一些得力的伪原创改写工具来辅助我们更好地改写出高质量的内容。今天我要和大家分享5款令人惊喜的在线伪原创改写软件,它们以出色的智能改写效果,…...

opencv-python图像增强四:多曝光融合(方法一)
文章目录 一、简介:二、多曝光融合方案:三、算法实现步骤3.1 读取图像与曝光时间:3.2 计算响应曲线并合并3.3 色调映射 四:整体代码实现五:效果 一、简介: 在摄影和计算机视觉领域,高动态范围&…...

Qt 实战(9)窗体 | 9.2、QDialog
文章目录 一、QDialog1、基本概念2、常用特性2.1、模态与非模态2.2、数据交互 3、总结 前言: Qt框架中的QDialog类是一个功能强大且灵活的对话框控件,广泛应用于各种GUI(图形用户界面)应用程序中,用于处理用户输入、消…...