Redis集群

本文深入探讨了Redis集群的实现原理,包括基于哈希的槽分区策略,如何通过节点间通信保持状态同步,以及如何处理节点故障和恢复。此外,还介绍了使用一致性Hash解决动态扩展和数据迁移的问题,以及RedisCluster的优化措施,如避免重定向错误和调整集群配置以允许部分节点故障时保持可用性。
摘要由CSDN通过智能技术生成

Redis集群方案

Redis集群方案基于分而治之的思想。Redis中数据都是以Key-Value形式存储的,而不同Key的数据之间是相互独立的。因此可以将Key按照某种规则划分成多个分区,将不同分区的数据存放在不同的节点上。这个方案类似数据结构中哈希表的结构。在Redis集群的实现中,使用哈希算法(公式是CRC16(Key) mod 16383)将Key映射到0~16383范围的整数。这样每个整数对应存储了若干个Key-Value数据,这样一个整数对应的抽象存储称为一个槽(slot)。每个Redis Cluster的节点——准确讲是master节点——负责一定范围的槽,所有节点组成的集群覆盖了0~16383整个范围的槽。

据说任何计算机问题都可以通过增加一个中间层来解决。槽的概念也是这么一层。它介于数据和节点之间,简化了扩容和收缩操作的难度。数据和槽的映射关系由固定算法完成,不需要维护,节点只需维护自身和槽的映射关系。

在这里插入图片描述

部署方式比较

普通hash

在正常集群分布时,需要对redis的key进行负载均衡,
简单方案,:

1.假设现在有4台服务器
2.对key进行hash并取余,得到对应的数值找到对应的服务器。
存在问题:如果线上4台服务器无法满足需求时,增加一台变成5台,这时候取余的结果跟之前的数值就存在区别,导致对应的key找不到数据,而且这个可能影响大部分的key都找不到。

Slave

上面的方案只是解决了性能扩展的问题,集群的故障容错能力并没有提升。提高容错能力的方法一般为使用某种备份/冗余手段。负责一定数量的槽的节点被称为master节点。为了增加集群稳定性,每个master节点可以配置若干个备份节点——称为slave节点。Slave节点一般作为冷备份保存master节点的数据,在master节点宕机时替换master节点。在一些数据访问压力比较大的情况下,slave节点也可以提供读取数据的功能,不过slave节点的数据实时性会略差一下。而写数据的操作则只能通过master节点进行。

请求重定向

当Redis节点接收到对某个key的命令时,如果这个key对应的槽不在自己的负责范围内,则返回MOVED重定向错误,通知客户端到正确的节点去访问数据。

如果频繁出现重定向错误,势必会影响访问的性能。由于从key映射到槽的算法是固定公开的,客户端可以在内部维护槽到节点的映射关系,访问数据时可以自己通过key计算出槽,然后找到正确的节点,减少重定向错误。目前大部分开发语言的Redis客户端都会实现这个策略。这个地址https://redis.io/clients可以查看主流语言的Redis客户端。

节点通信

尽管不同节点存储的数据相互独立,这些节点仍然需要相互通信以同步节点状态信息。Redis集群采用P2P的Gossip协议,节点之间不断地通信交换信息,最终所有节点的状态都会达成一致。常用的Gossip消息有下面几种:

  • ping消息:每个节点不断地向其他节点发起ping消息,用于检测节点是否在线和交换节点状态信息。
  • pong消息:收到ping、meet消息时的响应消息。
  • meet消息:新节点加入消息。
  • fail消息:节点下线消息。
  • forget消息:忘记节点消息,使一个节点下线。这个命令必须在60秒内在所有节点执行,否则超过60秒后该节点重新参与消息交换。实践中不建议直接使用forget命令来操作节点下线。

节点下线

当某个节点出现问题时,需要一定的传播时间让多数master节点认为该节点确实不可用,才能标记标记该节点真正下线。Redis集群的节点下线包括两个环节:主观下线(pfail)和客观下线(fail)。

主观下线:当节点A在cluster-node-timeout时间内和节点B通信(ping-pong消息)一直失败,则节点A认为节点B不可用,标记为主观下线,并将状态消息传播给其他节点。
客观下线:当一个节点被集群内多数master节点标记为主观下线后,则触发客观下线流程,标记该节点真正下线。
故障恢复
一个持有槽的master节点客观下线后,集群会从slave节点中选出一个提升为master节点来替换它。Redis集群使用选举-投票的算法来挑选slave节点。一个slave节点必须获得包括故障的master节点在内的多数master节点的投票后才能被提升为master节点。假设集群规模为3主3从,则必须至少有2个主节点存活才能执行故障恢复。如果部署时将2个主节点部署到同一台服务器上,则该服务器不幸宕机后集群无法执行故障恢复。

默认情况下,Redis集群如果有master节点不可用,即有一些槽没有负责的节点,则整个集群不可用。也就是说当一个master节点故障,到故障恢复的这段时间,整个集群都处于不可用的状态。这对于一些业务来说是不可忍受的。可以在配置中将cluster-require-full-coverage配置为no,那么master节点故障时只会影响访问它负责的相关槽的数据,不影响对其他节点的访问。

一致性hash

一致性 Hash 算法通过构建环状的 Hash 空间替线性 Hash 空间的方法解决了这个问题,整个 Hash 空间被构建成一个首位相接的环。
在这里插入图片描述
如上图,上方两个图为普通hash环,其具体的构造过程为:

1.先构造一个长度为 2^32 的一致性 Hash 环
2.计算每个缓存服务器的 Hash 值,并记录,这就是它们在 Hash 环上的位置
3.对于每个图片,先根据 key 的 hashcode 得到它在 Hash 环上的位置,然后在 Hash 环上顺时针查找距离这个 Key 的 Hash 值最近的缓存服务器节点,这就是该图片所要存储的缓存服务器。
这时,当服务器扩容时,少部分的缓存会命中到新的节点上,其他的并不会受影响。反之,当服务器节点被删除时,只会影响之前映射到当前节点的key,转移到顺时针方向的下一个节点。

但是以上的普通hash环会存在一个问题,当节点移除时,原有节点的数据会全量打到一个节点上,导致那个节点的数据倍增,同理,如果节点新增时,只会影响其中一个节点,其他节点的压力并不会移除。

这时,引入了包含虚拟节点的hash环,扩展整个环上的节点数量,可以将每台物理缓存服务器虚拟为一组虚拟缓存服务器,使得 Hash 环在空间上的分割更加均匀。
如图中下方图,node1x代表节点1,依次类推,通过寻找虚拟节点,然后找到对应的真实节点,只要虚拟节点足够多,节点会更均匀的分布在环上。

此时,新增一个节点,所影响的key会均匀的从其他节点转移到新的节点上,同理删除一个节点,节点上的缓存会均匀的转移到其他节点上。

一致性hash也有一些不足的地方:

  • 1.节点过多,或者更新频繁,查询效率会比较低下。
  • 2.需要一个服务进行负载均衡。
    针对这两个问题,redis有几个方案:

1.集群方案,hash slot
Redis Cluster 通过分片的方式将整个缓存划分为 16384 个槽,每个缓存节点就相当于 Hash 环上的一个节点,接入集群时,所有实例都将均匀占有这些哈希槽,当需要查询一个 Key 是,首先根据 Key 的 hashcode 对 16384 取余来得到 Key 属于哪个槽,并映射到缓存实例上。
把16384个槽抽象成20个哈希槽位,如果有4个节点,分配的哈希槽为0-4,5-9,10-14,15-19,当新增一个节点时,将每个节点的哈希槽的一部分取出来到第五个节点上,取出0,5,10,15形成新的节点哈希槽。删除也同理
2.中心化
公司使用sentinel的形式,把sentinel当做中心来对redis进行调度

3.去中心化
每个节点都保存完整的哈希槽-节点的映射表。
这样的话,无论向那个节点发出寻找缓存的请求,都会转移到对应的节点上。

hashslot 减少了频繁寻址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值