【Redis】集群

发布于:2024-04-20 ⋅ 阅读:(28) ⋅ 点赞:(0)

  redis集群是一个提供在多个Redis节点间共享数据的程序集,支持多个master。这是由于哨兵加主从复制的方式具有缺陷,由于数据量过大的情况下,单个master的复制集难以承担,因此需要多个复制集进行集群,其作用主要是提供给在多个Redis节点间共享数据的程序集。

一、集群的功能

  • Redis集群支持多个Master,每个Master由可以挂载多个Slave。因此,它也具有读写分离、支持数据高可用和支持海量数据的读写存储操作的特点。
  • 无需使用哨兵功能,集群自带了sentinel的故障转移机制,内置高可用的支持。
  • 客户端与集群的连接只需要与集群中的任一可用节点连接即可。
  • 槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系。

二、Redis集群的槽位slot和分片

2.1、概念

  Redis分成了16384个哈希槽,每个哈希槽都可以存放一个key-value键值对,即设置了16384个主节点的集群上限(但建议大小为1000),每个key通过CRC16校验后对16384取模来决定放置在哪个槽,
  使用Redis集群时将存储的数据分散到多台redis机器上,这就称为分片
  计算当前数据应该放在哪个槽位上的公式为:
H A S H _ S L O T = C R C 16 ( k e y ) m o d 16384 HASH\_SLOT=CRC16(key) mod 16384 HASH_SLOT=CRC16(key)mod16384

使用槽位和分片的优势
  这种结构的最大优势是方便扩缩容和数据分派查找。无论添加删除或者改变某个节点都不会造成集群不可用的情况。

2.2、slot槽位映射的算法

2.2.1 哈希取余分区

  预先确定好机器台数,通过 h a s h ( k e y ) % N 台机器 hash(key)\%N台机器 hash(key)%N台机器,计算哈希值,来决定数据key-value映射到哪一台机器上。
  优点
  简单且有效。使得每一台机器固定处理一部分请求,起到负载均衡+分而治之的作用。
  缺点
  扩缩容比较麻烦,再台数数量变化的情况下,会导致hash取余变化从而使得数据重新洗牌。

2.2.2 一致性hash算法

  一致性hash算法是为了解决分布式缓存数据变动和映射的问题。当服务器数量发生变化的时候,尽量减少影响客户端到服务器的映射关系。
  算法步骤
  1、构建一致性圆环:构建全量集合,即对2^32取模。
  2、Redis服务器IP节点映射:将服务器IP节点映射到环上。
  3、将key值映射到环上:将key值映射到环上,并且从该key值的位置沿着顺时钟方向走,遇到的第一台服务器就是定位到的服务器。

Panda

  优点
  1、容错性,如果上图之中的服务器节点C宕机了,那么只会影响节点B和节点C之间的key,并且这些key也只是转移到了服务器节点D上,不会影响整个数据。
  2、扩展性,如果要添加一个新服务器节点E,那么也只会影响一个区间内的数据,而不会使得整个数据发生转移。

  缺点
  Hash环的数据倾斜问题,一致性Hash容易在服务节点太少,数据太多时发生数据倾斜问题。导致数据大部分集中在一台机器上,从而使得服务器节点发生变化时,发生大规模的数据迁移。如下:

Panda

2.2.3 哈希槽分区

  哈希槽实质是一个由[0, 2^14-1]数组形成的hash slot空间。由于一致性哈希算法存在数据倾斜问题,所以提出了哈希槽分区算法。哈希解决了映射问题,通过使用key的哈希值来计算所在的槽,便于数据分配。槽解决了粒度问题,便于数据移动。
  哈希槽计算
H A S H _ S L O T = C R C 16 ( k e y ) m o d 16384 HASH\_SLOT=CRC16(key) mod 16384 HASH_SLOT=CRC16(key)mod16384

面试题:为什么redis集群的最大槽数是16384?

  CRC16产生的hash值由16bit,即可以产生2^16=65536个值,但我们只用16384个槽就行了,原因如下:
1、槽位越少,节点少的情况下,压缩比高,容易传输
  Redis主节点的配置信息中显示它所负责的哈希槽是通过bitmap来保存的。在传输的过程中会对bitmap进行压缩,如果节点很少但是哈希槽很多的话,bitmap的压缩率就很低。
2、redis的集群主节点数量基本不可能超过1000个
  如果节点超多1000个,会导致心跳包消息体内携带的数据过大而引发网络拥堵。对于节点数在1000以内的redis集群,16384个槽位够用了。
3、如果设置槽位为65536,发送心跳包的消息头达8Kb,发送的心跳包过于庞大。
  消息头中最占空间的是myslot[CLUSTER_SLOTS/8],当槽位为65536是,这部分大小为65538 / 8 / 1024 = 8kb,当槽位为16384时,这部分大小为16384 / 8 / 1024 = 2kb。每秒钟redis节点都要发送一定数量的心跳包,所以如果设置的太大,浪费带宽。

面试题:redis集群会不会写丢失?

  redis集群不保证强一致性,在特定情况下,会丢掉一些系统收到的写入请求命令。