Redis系列5:深入分析Cluster 集群模式

news2024/11/20 3:18:39

1 背景

前面我们学习了Redis高可用的两种架构模式:主从模式、哨兵模式。
解决了我们在Redis实例发生故障时,具备主从自动切换、故障转移的能力,终保证服务的高可用。
但是这些其实远远不够,随着我们业务规模的不断扩展,用户量膨胀,并发量持续提升。原有的主从架构,已经远远达不到我们的需求了,这时候会有一些问题出现,比如:

  • 单机的CPU、内存、连接数、计算力都是有极限的,不能无限制的承载流量的扩增。
  • 超额的请求、大规模的数据计算,导致必然的慢响应。
    这时候就需要适当的推进架构的演进,来满足发展的需要。

2 Cluster 模式介绍

2.1 什么是Cluster模式

Cluster 即 集群模式,类似MySQL,Redis 集群也是一种分布式数据库方案,集群通过分片(sharding)模式来对数据进行管理,并具备分片间数据复制、故障转移和流量调度的能力。这种 分治模式很常见,我们在 微服务系列:拆分策略 和 MySQL系列:分库分表 中实践过很多次了。
Redis集群的做法是 将数据划分为 16384(2的14次方)个哈希槽(slots),如果你有多个实例节点,那么每个实例节点将管理其中一部分的槽位,槽位的信息会存储在各自所归属的节点中。以下图为例,该集群有4个 Redis 节点,每个节点负责集群中的一部分数据,数据量可以不均匀。比如性能好的实例节点可以多分担一些压力。

一个Redis集群一共有16384个哈希槽,你可以有1 ~ n个节点来分配这些哈希槽,可以不均匀分配,每个节点可以处理0个 到至多 16384 个槽点。
当16384个哈希槽都有节点进行管理的时候,集群处于online 状态。同样的,如果有一个哈希槽没有被管理到,那么集群处于offline状态。

上面图中4个实例节点组成了一个集群,集群之间的信息通过 Gossip协议 进行交互,这样就可以在某一节点记录其他节点的哈希槽(slots)的分配情况。

2.2 为什么需要Cluster模式

单机的吞吐无法承受持续扩增的流量的时候,好的办法是从横向(scale out) 和 纵向(scale up)两方面进行扩展,这个我们在 MySQL系列 和 微服务系列 的时候已经讨论过了。

  • 纵向扩展(scale up):将单个实例的硬件资源做提升,比如 CPU核数量、内存容量、SSD容量。
  • 横向扩展(scale out):横向扩增 Redis 实例数,这样每个节点只负责一部分数据就可以,分担一下压力,典型的分治思维。
                 那横向扩展和纵向扩展各有什么优缺点呢?
  • scale up 虽然操作起来比较简易。但是没法解决Redis一些瓶颈问题,比如持久化(如轮式RDB快照还是AOF指令),遇到大数据量的时候,照样效率会很低,响应慢。另外,单台服务机硬件扩容也是有限制的,不可能无限操作。
  • scale out 更容易扩展,分片的模式可以解决很多问题,包括单一实例节点的硬件扩容限制、成本限制,还可以分摊压力,精细化治理,精细化维护。但是同时也要面临分布式带来的一些问题
    现实情况下,在面对千万级甚至亿级别的流量的时候,很多大厂都是在千百台的实例节点组成的集群上进行流量调度、服务治理的。所以,使用Cluster模式,是业内广泛采用的模式。

3 Cluster 实现原理

3.1 集群的组群过程

集群是由一个个互相独立的节点(readis node)组成的, 所以刚开始的时候,他们都是隔离,毫无联系的。我们需要通过一些操作,把他们聚集在一起,终才能组成真正的可协调工作的集群。
各个节点的联通是通过 CLUSTER MEET 命令完成的:CLUSTER MEET <ip> <port> 。
具体的做法是其中一个node向另外一个 node(指定 ip 和 port) 发送 CLUSTER MEET 命令,这样就可以让两个节点进行握手(handshake操作) ,握手成功之后,node 节点就会将握手另一侧的节点添加到当前节点所在的集群中。
这样一步步的将需要聚集的节点都圈入同一个集群中,如下图:

3.2 集群数据分片原理

现在的Redis集群分片的做法,主要是使用了官方提供的 Redis Cluster 方案。这种方案就是的核心就是集群的实例节点与哈希槽(slots)之间的划分、映射与管理。下面我们来看看他具体的步骤。

3.2.1 哈希槽(slots)的划分

这个前面已经说过了,我们会将整个Redis数据库划分为16384个哈希槽,你的Redis集群可能有n个实例节点,每个节点可以处理0个 到至多 16384 个槽点,这些节点把 16384个槽位瓜分完成。
而你实际存储的Redis键值信息也必然归属于这 16384 个槽的其中一个。slots 与 Redis Key 的映射是通过以下两个步骤完成的:

  • 使用 CRC16 算法计算键值对信息的Key,会得出一个 16 bit 的值。
  • 将 第1步中得到的 16 bit 的值对 16384 取模,得到的值会在 0 ~ 16383 之间,映射到对应到哈希槽中。
    当然,可能在一些特殊的情况下,你想把某些key固定到某个slot上面,也就是同一个实例节点上。这时候可以用hash tag能力,强制 key 所归属的槽位等于 tag 所在的槽位。
    其实现方式为在key中加个{},例如test_key{1}。使用hash tag后客户端在计算key的crc16时,只计算{}中数据。如果没使用hash tag,客户端会对整个key进行crc16计算。下面演示下hash tag使用:
127.0.0.1:6380> cluster keyslot user:case{1}
(integer) 1024
127.0.0.1:6380> cluster keyslot user:favor
(integer) 1023
127.0.0.1:6380> cluster keyslot user:info{1}
(integer) 1024

如上,使用hash tag 后会对应到通一个hash slot:1024中。

3.2.2 哈希槽(slots)的映射

一种是初始化的时候均匀分配 ,使用 cluster create 创建,会将 16384 个slots 平均分配在我们的集群实例上,比如你有n个节点,那每个节点的槽位就是 16384 / n 个了 。
另一种是通过 CLUSTER MEET 命令将 node1、node2、ndoe3、node4 4个节点联通成一个集群,刚联通的时候因为还没分配哈希槽,还是处于offline状态。我们使用 cluster addslots 命令来指定。
指定的好处就是性能好的实例节点可以多分担一些压力。

可以通过 addslots 命令指定哈希槽范围,比如下图中,我们哈希槽是这么分配的:实例 1 管理 0 ~ 7120 哈希槽,实例 2 管理 7121~9945 哈希槽,实例 3 管理 9946 ~ 13005 哈希槽,实例 4 管理 13006 ~ 16383 哈希槽。

redis-cli -h 192.168.0.1 –p 6379 cluster addslots ,7120
redis-cli -h 192.168.0.2 –p 6379 cluster addslots 7121,9945
redis-cli -h 192.168.0.3 –p 6379 cluster addslots 9946,13005
redis-cli -h 192.168.0.4 –p 6379 cluster addslots 13006,16383

slots 和 Redis 实例之间的映射关系如下:

key testkey_1 和 testkey_2 经过 CRC16 计算后再对slots的总个数 16384 取模,结果分别匹配到了 cache1 和 cache3 上。

3.3 数据复制过程和故障转移

3.3.1 数据复制

Cluster 是具备Master 和 Slave模式,Redis 集群中的每个实例节点都负责一些槽位,比如上图中的四个节点分管了不同的槽位区间。而每个Master至少需要一个Slave节点,Slave 节点是通过《Redis系列3:高可用之主从架构》方式同步主节点数据。 节点之间保持TCP通信,当Master发生了宕机, Redis Cluster自动会将对应的Slave节点选为Master,来继续提供服务。与纯主从模式不同的是,主从节点之间并没有读写分离, Slave 只用作 Master 宕机的高可用备份,所以更合理来说应该是主备模式。
如果主节点没有从节点,那么一旦发生故障时,集群将完全处于不可用状态。 但也允许配置 cluster-require-full-coverage参数,及时部分节点不可用,其他节点正常提供服务,这是为了避免全盘宕机。
主从切换之后,故障恢复的主节点,会转化成新主节点的从节点。这种自愈模式对提高可用性非常有帮助。

3.3.2 故障检测

一个节点认为某个节点宕机不能说明这个节点真的挂起了,无法提供服务了。只有占据多数的实例节点都认为某个节点挂起了,这时候cluster才进行下线和主从切换的工作。
Redis 集群的节点采用 Gossip 协议来广播信息,每个节点都会定期向其他节点发送ping命令,如果接受ping消息的节点在指定时间内没有回复pong,则会认为该节点失联了(PFail),则发送ping的节点就把接受ping的节点标记为主观下线。
如果集群半数以上的主节点都将主节点 xxx 标记为主观下线,则节点 xxx 将被标记为客观下线,然后向整个集群广播,让其它节点也知道该节点已经下线,并立即对下线的节点进行主从切换。

3.3.3 主从故障转移

当一个从节点发现自己正在复制的主节点进入了已下线,则开始对下线主节点进行故障转移,故障转移的步骤如下:

  • 如果只有一个slave节点,则从节点会执行SLAVEOF no one命令,成为新的主节点。

  • 如果是多个slave节点,则采用选举模式进行,竞选出新的Master

    • 集群中设立一个自增计数器,初始值为 0 ,每次执行故障转移选举,计数就会+1。
    • 检测到主节点下线的从节点向集群所有master广播一条CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,所有收到消息、并具备投票权的主节点都向这个从节点投票。
    • 如果收到消息、并具备投票权的主节点未投票给其他从节点(只能投一票哦,所以投过了不行),则返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示支持。
    • 参与选举的从节点都会接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,如果收集到的选票 大于等于 (n/2) + 1 支持,n代表所有具备选举权的master,那么这个从节点就被选举为新主节点。
    • 如果这一轮从节点都没能争取到足够多的票数,则发起再一轮选举(自增计数器+1),直至选出新的master。
  • 新的主节点会撤销所有对已下线主节点的slots指派,并将这些slots全部指派给自己。

  • 新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽。

  • 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。

跟哨兵类似,两者都是基于 Raft 算法来实现的,流程如图所示:

3.4 client 访问 数据集群的过程

3.4.1 定位数据所在节点

我们前面说过了,Redis 中的每个实例节点会将自己负责的哈希槽信息 通过 Gossip 协议广播给集群中其他的实例,实现了slots分配信息的扩散。这样的话,每个实例都知道整个集群的哈希槽分配情况以及映射信息。
所以客户端想要快捷的连接到服务端,并对某个redis数据进行快捷访问,一般是经过以下步骤:

  • 客户端连接任一实例,获取到slots与实例节点的映射关系,并将该映射关系的信息缓存在本地。
  • 将需要访问的redis信息的key,经过CRC16计算后,再对16384 取模得到对应的 Slot 索引。
  • 通过slot的位置进一步定位到具体所在的实例,再将请求发送到对应的实例上。
    下图展示了 Redis 客户端如何定位数据所在节点:

4 总结

  • 哨兵模式已经实现了故障自动转移的能力,但业务规模的不断扩展,用户量膨胀,并发量持续提升,会出现了 Redis 响应慢的情况。
  • 使用 Redis Cluster 集群,主要解决了大数据量存储导致的各种慢问题,同时也便于横向拓展。在面对千万级甚至亿级别的流量的时候,很多大厂的做法是在千百台的实例节点组成的集群上进行流量调度、服务治理的。
  • 整个Redis数据库划分为16384个哈希槽,Redis集群可能有n个实例节点,每个节点可以处理0个 到至多 16384 个槽点,这些节点把 16384个槽位瓜分完成。
  • Cluster 是具备Master 和 Slave模式,Redis 集群中的每个实例节点都负责一些槽位,节点之间保持TCP通信,当Master发生了宕机, Redis Cluster自动会将对应的Slave节点选为Master,来继续提供服务。
  • 客户端能够快捷的连接到服务端,主要是将slots与实例节点的映射关系存储在本地,当需要访问的时候,对key进行CRC16计算后,再对16384 取模得到对应的 Slot 索引,再定位到相应的实例上。实现高效的连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1624339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Golang GMP解读

概念梳理 1. 1 线程 通常语义中的线程&#xff0c;指的是内核级线程&#xff0c;核心点如下&#xff1a; 是操作系统最小调度单元&#xff1b;创建、销毁、调度交由内核完成&#xff0c;cpu 需完成用户态与内核态间的切换&#xff1b;可充分利用多核&#xff0c;实现并行. …

指标+AI:迈向智能化,让指标应用更高效

近日&#xff0c;以“DataAI&#xff0c;构建新质生产力”为主题的袋鼠云春季发布会圆满落幕&#xff0c;大会带来了一系列“AI”的数字化产品与最新行业沉淀&#xff0c;旨在将数据与AI紧密结合&#xff0c;打破传统的生产力边界&#xff0c;赋能企业实现更高质量、更高效率的…

Java集合框架-Collection-List-vector(遗留类)

目录 一、vector层次结构图二、概述三、底层数据结构四、常用方法五、和ArrayList的对比 一、vector层次结构图 二、概述 Vector类是单列集合List接口的一个实现类。与ArrayList类似&#xff0c;Vector也实现了一个可以动态修改的数组&#xff0c;两者最本质的区别在于——Vec…

hertzbeat 源码阅读记录

关于自定义标签的说明 EmailValid.java HostValid PhoneNumValid 枚举值说明&#xff1a;

TCP协议数据传输过程及报文分析

目录 TCP数据的传输过程 建立连接&#xff08;三次握手&#xff09; 第一次握手 第二次握手 第三次握手 总结 数据传输 断开连接&#xff08;四次挥手&#xff09; 第一次挥手 第二次挥手 第三次挥手 第四次挥手 总结 最后 TCP数据的传输过程 TCP&#xff08;Tra…

在python中,对encodeURIComponent的使用避坑指南

随笔记录 某站点对请求参数加密的时候对键值对都进行了encodeURIComponent。那encodeURIComponent的作用是什么呢&#xff1f;如何在python中进行使用呢&#xff1f;使用过程中如何结合实际情况解决问题呢&#xff1f;以下是避坑指南&#xff0c;会让你少走很多弯路。 作用 en…

NVIDIA CUDA Toolkit

NVIDIA CUDA Toolkit CUDA Toolkit 12.4 Update 1 Downloads | NVIDIA Developer CUDA Toolkit是用于CUDA开发的软件包&#xff0c;主要包括CUDA编译器、运行时库、GPU驱动程序和开发工具等。它允许开发者使用通用编程语言&#xff08;如C、C&#xff09;来利用NVIDIA GPU进行…

mac终端出现bogon原因与解决办法

问题描述 不知道啥原因mac终端的用户名就变成了 xxxbogon &#xff0c;可能是强制关闭终端导致的吧。 问题原因 终端在初始化时&#xff0c;需要确定主机的名字&#xff0c;此时终端会向 DNS 服务器反向查询本机 IP 地址&#xff0c;然后把得到的名字作为自己的主机名。如果…

使用 Rust 后,我​​使用 Python 的方式发生了变化

使用 Rust 后&#xff0c;我​​使用 Python 的方式发生了变化 Using type hints where possible, and sticking to the classic “make illegal state unrepresentable” principle. 尽可能使用类型提示&#xff0c;并坚持经典的“使非法状态不可表示”原则。 近年来&#xff…

LeetCode78:子集

题目描述 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集 &#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 代码 class Solution { public:vector<vector<int>> res;vector<…

xgp怎么取消续费 手把手介绍微软商店xgp关闭自动续费教程

Xbox是美国微软公司创建的电子游戏品牌&#xff0c;随2001年11月第一代Xbox游戏机发布而首次推出。其产品和服务包括家用游戏机、游戏制作与发行、线上游戏服务和内容订阅服务。Xbox已发售的家用游戏机有Xbox、Xbox360、Xbox One、Xbox One S、Xbox One X、Xbox Series X、Xbox…

亚服战网安装卡45%的解决方案

解决方案 先ping cn.patch.battlenet.com.cn这个域名&#xff0c;正常来说是一定会失败的&#xff0c;如果成功就不卡45%了然后ping tw.patch.battle.net 这个域名&#xff0c;这个域名应该是能成功的。 去该网址解析一下这个域名的ip&#xff0c;https://site.ip138.com/tw.p…

漏洞修复优先级考虑-不错的思路

权威说法&#xff1a; 漏洞利用预测评分系统 &#xff08;EPSS&#xff09; 是一项数据驱动的工作&#xff0c;用于估计软件漏洞在野外被利用的可能性&#xff08;概率&#xff09; https://www.first.org/epss/ GitHub - TURROKS/CVE_Prioritizer: Streamline vulnerability…

Kubernetes TDengine 系列|安装 TDengine 的 Grafana 插件|Grafana监控TDengine数据

为了让Grafana 能够监控到TDengine 数据&#xff0c;快速集成搭建数据监测报警系统&#xff0c;所以直接安装TDengine 插件。 目录 一、安装 TDengine 的 Grafana 插件1、下载TDengine grafana插件2、解压到指定目录3、配置未签名插件 二、配置数据源&#xff0c;简单查询TDen…

JDK的安装和配置

目录 1.Java 开发工具包在上方已关联资源下载使用2.JAVA_HOME3.CLASSPATH4.PATH5.安装jdk17情况需要将path变量中删除6.包内含有visualvm7.注意&#xff1a;如果安装JDK17在我们安装的时候可能会自动进行环境变量配置&#xff0c;我们需要在环境变量配置PATH中删除如下信息8.验…

汽车信息安全--如何理解TrustZone(1)

目录 1.车规MCU少见TrustZone 2. 什么是TrustZone 2.1 TrustZone隔离了什么&#xff1f; 2.2 处理器寄存器和异常处理 3.小结 1.车规MCU少见TrustZone 在车规MCU里&#xff0c;谈到信息安全大家想到的大多可能都是御三家的HSM方案&#xff1a;英飞凌的HSM\SHE、瑞萨的ICU…

循环神经网络介绍(RNN)

序列模型 定义&#xff1a;自然语言处理、音频、视频以及其他序列数据的模型 类型&#xff1a; 语音识别 情感分析 机器翻译 特点&#xff1a; 序列数据前后之间有很强的关联性 序列数据的输入输出长度不固定 循环神经网络 定义&#xff1a;循环&#xff08;递归&#xff…

revit\navisworks各种安装问题

You have entered a nonvalid serial number &#xff0c;怎么都不给你一个机会输出序列号&#xff0c;怎么办&#xff1f; step1: C:\Program Files (x86)\Common Files\Autodesk Shared\AdskLicensing目录下找到uninstall.exe&#xff0c;右键管理员模式运行&#xff0c;会…

7.MyBatis 操作数据库(初阶)

文章目录 1.什么是MyBatis2.为什么要学习 MyBatis&#xff1f;3.通过spring框架创建MyBatis项目3.1使用MyBatis查询数据库3.2 mysql连接不上报错解决方法 4.MyBatis的基础操作4.1企业建表规范&#xff1a;4.2MyBatis基本实现4.3单元测试4.4使用MyBatis可能遇到的问题4.5配置MyB…

初学python记录:力扣2385. 感染二叉树需要的总时间

题目&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;二叉树中节点的值 互不相同 。另给你一个整数 start 。在第 0 分钟&#xff0c;感染 将会从值为 start 的节点开始爆发。 每分钟&#xff0c;如果节点满足以下全部条件&#xff0c;就会被感染&#xff1a; 节点此…