当前位置: 首页 > news >正文

尚硅谷redis7 74-85 redis集群分片之集群是什么

74 redis集群分片之集群是什么

如果主机宕机,那么写操作就被暂时中断,后面就要由哨兵进行投票和选举。那么一瞬间若有大量的数据修改,由于写操作中断就会导致数据流失。

由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展。每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,共作用是提供在多个Redis节点间共享数据的程序集。

75 redis集群分片之集群能干嘛

redis集群是一个提供在多个redis节点间共享数据的程序集

redsi集群可以支持多个master

左图是一个master,右图是多个master

多个master对外是一个集群整体,里面具体是哪个redis实例提供服务和访问的客户端无关。若三个master中有一个挂了,没关系,还有另外两个master可以工作。每个master都有对应的从机,如果m1挂了那么s1可以顶上。

redis集群的作用

  • Redis集群支持多个Master,每个Master又可以挂载多个Slave
  • 由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
  • 客户端与Redis的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可
  • 槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系

76 redis集群分片之槽位slot

在 Redis 集群中,密钥空间(Keyspace) 是指 Redis 用来存储所有键的一个逻辑空间。而集群的密钥空间,则是这个概念在 Redis 集群架构中的具体体现,它决定了数据在集群中如何分布和定位。

分片机制

  • Redis 集群将整个密钥空间划分为 16384 个槽位(slots),编号从 0 到 16383。

  • 每个键根据其名字的哈希值被分配到这 16384 个槽位中的某一个槽。

  • 每个节点(Redis 实例)负责其中的一部分槽位,这样可以实现数据的分布式存储。

槽位计算方式

Redis 使用 CRC16 哈希算法计算键的哈希值,然后对 16384 取模,确定该键属于哪个槽。

slot = CRC16(key) % 16384

密钥空间的划分意义

  • 它决定了键值对的物理存储位置。

  • 客户端在访问一个键时,可以通过这个槽位快速定位到具体负责这个槽的节点。

redis集群的槽位slot

引入了 哈希槽的概念.
Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。
举个例子,比如当前集群有3个节点,那么:

77 redis集群分片之分片

redis集群的分片

分片是什么

使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片。

如何找到给定key的分片

为了找到给定key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后,使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片,我们可以推断将来读取特定key的位置。

槽位是逻辑单位,分片是物理单位。Redis 通过槽位把键分配到分片上。

假设你有 3 个 Redis 节点(A、B、C)组成一个集群:

  • 节点 A:负责槽位 0 ~ 5460

  • 节点 B:负责槽位 5461 ~ 10922

  • 节点 C:负责槽位 10923 ~ 16383

这 3 个节点就是 3 个分片,每个分片负责一部分 槽位,通过这些槽位将键分布到各个节点上。

78 redis集群分片之分片优势

槽位slot和分片的优势

假设系统要扩容,从三主三从变成五主五从。

最大优势,方便扩缩容和数据分派查找

这种结构很易添加或者删除节点,比如如果我想新添加个节点D,并不需要改变所有槽的分布,只需要将部分槽(比如 A 的一部分、B 的一部分)“迁移”到 D 上。比如把 A 的 1000 个槽给 D,B 的 1000 个槽也给 D。如果我想移除节点A.需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可.由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希的数量都不会造成集群不可用的状态。

槽位迁移不会造成集群停机

动态数据迁移(Rebalancing)
  • 在 Redis 集群中,槽位迁移是在线进行的

  • 当槽从 A 迁移到 D 时,Redis 会逐个 key 从 A 发送到 D(带着 key 的值)。

  • 在迁移过程中,如果有客户端访问该 key,Redis 仍然能处理请求(可能会返回 MOVEDASK 重定向,让客户端重试)。

79 reids集群分片之哈希取余分区算法

slot槽位映射,一般业界有3种解决方案:哈希取余分区、一致性哈希算法分区、哈希槽分区

哈希取余分区

2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机,假设有3台机器构成一个集群,用户每次读写操作都是根据公式:
hash(key)% N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。

优点:
简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时问的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。

缺点:

原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key)/?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。
某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌。

一致性哈希算法

一致性Hash算法背景:一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。

提出一致性Hash解决方案。目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系

算法构建一致性哈希环

一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0=2^32),这样让它逻辑上形成了一个环形空问

它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数最进行取模。而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:

整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、 …… 直到2^32-1,也就是说0点左侧的第一个点代表2^32-1,0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。

支持节点的动态增减而“最小代价”地迁移数据

假设原来你有 3 个节点:A、B、C,分布在环上:

数据 "x" 的哈希值在 A 和 B 之间,那么它就会映射到 B。

 如果增加一个新节点 D,映射到 A 和 B 之间:
  • 只有 hash 值落在 A 和 D 之间的数据,才会迁移到 D。

  • 其他数据仍然映射到原来的节点上。

 只影响局部,不影响全局

redis服务器IP节点映射

将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:

key落到服务器的落键规则

当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

优点

一致性哈希算法的容错性

假设Node C宕机,可以看到此时对象A、B、D不会受到影响。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是
B、C之间的数据且这些数据会转移到D进行存储。

一致性哈希算法的扩展性

数据量增加了,需要增加一台节点NodeX,X的位置在A和B之问,那收到影响的也就是A到X之问的数据,重新把A到X的数据录入到X上即可,不会导致hash取余全部数据重新洗牌。

缺点

一致性哈希算法的数据倾斜问题

一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器:

总结

  • 为了在节点数目发生改变时尽可能少的迁移数据
    • 将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到临近的存储节点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。
  • 优点
    • 加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。
  • 缺点
    • 数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。

哈希槽分区

一致性哈希算法的数据倾斜问题

什么是哈希槽

哈希槽实质就是一个数组,数组[0,2^14-1]形成hash slot空间。

哈希槽能干什么


解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配

有多少个哈希槽

一个集群只能有16384个槽,编号0-16383(0-2^14-1),这些槽会分配给集群中的所有主节点,分配策略没有要求。
集群会记录节点和槽的对应关系,解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取视,余数是几key就落入对应的槽里。
HASH_SLOT=CRC16(key)mod 16384.以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

哈希槽的计算

Redis 集群中内置了16384个哈希槽.redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果然后用结果对16384求余数[CRC16(key)% 16384],这样每个key都会对应一个编号在0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A、B在Node2,key之C落在Node3上

为什么“哈希槽”能帮助实现均匀分布

1. 槽数远大于节点数,有助于细粒度均衡

  • 有 16384 个槽,但也许只有 3 个节点。

  • 可以灵活分配槽数来做到负载均衡:比如 5461 个槽一个节点。

  • 增加节点时,只需要重新分配槽 → 不需要重新 hash 所有 key。

 细粒度的槽控制可以最大程度地做到“平衡”数据分布。

2. 使用好的哈希函数能保证槽分布近似均匀

Redis 使用的是 CRC16(key) % 16384

  • CRC16 是一种分布较均匀的哈希函数;

  • 对于大多数 key,它能让结果在 0~16383 之间近似均匀分布

类比:

假如你用 hash(key) % 3 映射 3 台服务器,hash 函数如果分布不均匀,就可能导致大部分 key 落在某一台服务器上。

而:

  • hash(key) % 16384 得到均匀分布的槽;

  • 然后把槽“均匀分配”给节点;

  • 就间接达到了key 的均匀分布

经典面试题

为什么redis集群的最大槽数是16384个?

Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。但为什么哈希槽的数量是16384(2^14)个呢?

CRC16算法产生的hash值有16bit,该算法可以产生2^16=65536个值。
换句话说值是分布在0~65535之间,有更大的65536不用为什么只用16384就够?
作者在做mod运算的时候,为什么不mod65536,而选择mod16384?HASH_SLOT=CRC16(key)mod 65536为什么没启用

(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536÷8÷1024=8kb
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为16384时,这块的大小是:16384÷8÷1024=2kb
因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

前提:Redis 集群的每个节点需要知道哪些节点负责哪些槽(slot)。这就是为什么在节点之间发送心跳(PING/PONG)时,消息头中会包含该节点负责的槽位信息。

(2)redis的集群主节点数量基本不可能超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

(3)槽位越小,节点少的情况下,压缩比来,容易传输
Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots/N很高的话(N表示节点数)。bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

85 redis集群分片之不保证强一致性

Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统收到的写入请求命令

什么是“强一致性”?

  • 强一致性(Strong Consistency)意味着:一旦系统对外确认写入成功,所有节点(或客户端)随后读取到的都是这个值,永远不会丢失。

  • 而 Redis 集群遵循的是 最终一致性(Eventual Consistency),强调的是“最终节点状态会一致”,但在中间阶段可能不同步或丢失数据

Redis 集群中可能丢数据的典型场景

1. 主从复制延迟(Replication Lag)

  • Redis 集群采用异步复制:主节点执行写操作后,不会等待从节点确认再响应客户端。

  • 如果主节点刚写完数据就宕机:

    • 数据还未复制到从节点;

    • Redis 集群选了一个从节点晋升为新的主节点;

    • 这个新主节点上 可能没有那条写入的数据,就相当于“数据丢失”。

 这是一种典型的“已确认但未持久”的写丢失


2. 脑裂(Split-Brain)或网络分区

  • 如果集群节点之间发生网络故障,某些节点无法感知彼此状态,可能会:

    • 重复选举主节点;

    • 有两个主节点接收写入;

    • 最后产生数据不一致或写入丢失。

相关文章:

  • Java ThreadLocal 应用指南:从用户会话到数据库连接的线程安全实践
  • dis css port brief 命令详细解释
  • UDS TP层参数
  • AXI 协议补充(二)
  • HarmonyOS开发:Image使用详解
  • 全志V853挂载sd卡
  • Spring Boot测试框架全面解析
  • hgdb删除正在使用的用户(app)
  • Vue-06(“$emit”和事件修饰符)
  • 【动态规划:斐波那契数列模型】第 N 个泰波那契数
  • JavaScript 中的 BigInt:当普通数字不够“大“时的救星
  • #Js篇:两个前端应用通过postMessage传递file对像 URL.createObjectURL+fetch
  • Blaster - Multiplayer P117-PXXX: 匹配状态
  • 怒更一波免费声音克隆和AI配音功能
  • qlora
  • MTK平台-- 如何在屏幕关闭时过滤组播和广播的数据包
  • Java开发经验——阿里巴巴编码规范实践解析7
  • 【stm32开发板】原理图设计(电源部分)附:设计PCB流程
  • sql查询中in不生效的问题
  • 【SQL Server Management Studio 连接时遇到的一个错误】
  • thinkphp5来做网站吗/百家号自媒体平台注册
  • 手机网站好还是h5好/网络营销方案的制定
  • 上海建站网站的企业/深圳做网站
  • 在360上做网站多少钱/广告推广方案怎么写
  • 北京杰诚 做网站/抖音seo招商
  • 西安网站建设公/有道搜索引擎入口