不想谈好吉他的撸铁狗,不是好的程序员,欢送微信关注「SH的全栈笔记

前言

上文咱们聊了基于Sentinel的Redis高可用架构,理解了Redis基于读写拆散的主从架构,同时也晓得当Redis的master产生故障之后,Sentinel集群是如何执行failover的,以及其执行failover的原理是什么。

这里大略再提一下,Sentinel集群会对Redis的主从架构中的Redis实例进行监控,一旦发现了master节点宕机了,就会选举出一个Sentinel节点来执行故障转移,从原来的slave节点中选举出一个,将其晋升为master节点,而后让其余的节点去复制新选举进去的master节点。

你可能会感觉这样没有问题啊,甚至可能满足咱们生产环境的应用需要了,那咱们为什么还须要Redis Cluster呢?

为什么须要Redis Cluster

确实,在数据上,有replication正本做保障;可用性上,master宕机会主动的执行failover。

那问题在哪儿呢?

首先Redis Sentinel说白了也是基于主从复制,在主从复制中slave的数据是齐全来自于master。

假如master节点的内存只有4G,那slave节点所能存储的数据下限也只能是4G。而且在之前的追随杠精的视角一起来理解Redis的主从复制文章中也说过,主从复制架构中是读写拆散的,咱们能够通过减少slave节点来扩大主从的读并发能力,然而写能力存储能力是无奈进行扩大的,就只能是master节点可能承载的下限。

所以,当你只须要存储4G的数据时候的,基于主从复制和基于Sentinel的高可用架构是齐全够用的。

然而如果当你面临的是海量的数据的时候呢?16G、64G、256G甚至1T呢?当初互联网的业务外面,如果你的体量足够大,我感觉是必定会面临缓存海量缓存数据的场景的。

这就是为什么咱们须要引入Redis Cluster

Redis Cluster是什么

晓得了为什么须要Redis Cluster之后,咱们就能够来对其一探到底了。

那什么是Redis Cluster呢?

很简略,你就能够了解为n个主从架构组合在一起对外服务。Redis Cluster要求至多须要3个master能力组成一个集群,同时每个master至多须要有一个slave节点。

这样一来,如果一个主从可能存储32G的数据,如果这个集群蕴含了两个主从,则整个集群就可能存储64G的数据。

咱们晓得,主从架构中,能够通过减少slave节点的形式来扩大读申请的并发量,那Redis Cluster中是如何做的呢?尽管每个master下都挂载了一个slave节点,然而在Redis Cluster中的读、写申请其实都是在master上实现的。

slave节点只是充当了一个数据备份的角色,当master产生了宕机,就会将对应的slave节点提拔为master,来从新对外提供服务。

节点负载平衡

晓得了什么是Redis Cluster,咱们就能够持续上面的探讨了。

不晓得你思考过一个问题没,这么多的master节点。我存储的时候,到底该抉择哪个节点呢?个别这种负载平衡算法,会抉择哈希算法。哈希算法是怎么做的呢?

首先就是对key计算出一个hash值,而后用哈希值对master数量进行取模。由此就能够将key负载平衡到每一个Redis节点下来。这就是简略的哈希算法的实现。

那Redis Cluster是采取的下面的哈希算法吗?答案是没有

Redis Cluster其实采取的是相似于一致性哈希的算法来实现节点抉择的。那为什么不必哈希算法来进行实例抉择呢?以及为什么说是相似的呢?咱们持续探讨。

因为如果此时某一台master产生了宕机,那么此时会导致Redis中所有的缓存生效。为什么是所有的?假如之前有3个master,那么之前的算法应该是 hash % 3,然而如果其中一台master宕机了,则算法就会变成 hash % 2,会影响到之前存储的所有的key。而这对缓存前面爱护的DB来说,是致命的打击。

什么是一致性哈希

晓得了通过传统哈希算法来实现对节点的负载平衡的弊病,咱们就须要进一步理解什么是一致性哈希

咱们下面提过哈希算法是对master实例数量来取模,而一致性哈希则是对2^32取模,也就是值的范畴在[0, 2^32 -1]。一致性哈希将其范畴形象成了一个圆环,应用CRC16算法计算出来的哈希值会落到圆环上的某个中央。

而后咱们的Redis实例也散布在圆环上,咱们在圆环上依照顺时针的程序找到第一个Redis实例,这样就实现了对key的节点调配。咱们举个例子。

假如咱们有A、B、C三个Redis实例依照如图所示的地位散布在圆环上,此时计算出来的hash值,取模之后地位落在了地位D,那么咱们依照顺时针的程序,就可能找到咱们这个key应该调配的Redis实例B。同理如果咱们计算出来地位在E,那么对应抉择的Redis的实例就是A。

即便这个时候Redis实例B挂了,也不会影响到实例A和C的缓存。

例如此时节点B挂了,那之前计算出来在地位D的key,此时会依照顺时针的程序,找到节点C。相当于主动的把原来节点B的流量给转移到了节点C下来。而其余本来就在节点A和节点C的数据则齐全不受影响。

这就是一致性哈希,可能在咱们后续须要新增节点或者删除节点的时候,不影响其余节点的失常运行。

虚构节点机制

然而一致性哈希也存在本身的小问题,例如当咱们的Redis节点散布如下时,就有问题了。

此时数据落在节点A上的概率显著是大于其余两个节点的,其次落在节点C上的概率最小。这样一来会导致整个集群的数据存储不均衡,AB节点压力较大,而C节点资源利用不充沛。为了解决这个问题,一致性哈希算法引入了虚构节点机制

在圆环中,减少了对应节点的虚构节点,而后实现了虚构节点到实在节点的映射。假如当初计算得出了地位D,那么依照顺时针的程序,咱们找到的第一个节点就是C #1,最终数据理论还是会落在节点C上。

通过减少虚构节点的形式,使ABC三个节点在圆环上的地位更加平均,均匀了落在每一个节点上的概率。这样一来就解决了上文提到的数据存储存在不平均的问题了,这就是一致性哈希的虚构节点机制。

Redis Cluster采纳的什么算法

下面提到过,Redis Cluster采纳的是类一致性哈希算法,之所以是类一致性哈希算法是因为它们实现的形式还稍微有差异。

例如一致性哈希是对2^32取模,而Redis Cluster则是对2^14(也就是16384)取模。Redis Cluster将本人分成了16384个Slot(槽位)。通过CRC16算法计算出来的哈希值会跟16384取模,取模之后失去的值就是对应的槽位,而后每个Redis节点都会负责解决一部分的槽位,就像下表这样。

节点解决槽位
A0 - 5000
B5001 - 10000
C10001 - 16383

每个Redis实例会本人保护一份slot - Redis节点的映射关系,假如你在节点A上设置了某个key,然而这个key通过CRC16计算出来的槽位是由节点B保护的,那么就会提醒你须要去节点B上进行操作。

Redis Cluster如何做到高可用

不晓得你思考过一个问题没,如果Redis Cluster中的某个master节点挂了,它是如何保障集群本身的高可用的?如果这个时候咱们集群须要扩容节点,它该负责哪些槽位呢?咱们一个一个问题的来看一下。

集群如何进行扩容

咱们开篇聊过,Redis Cluster能够很不便的进行横向扩容,那当新的节点退出进来的时候,它是如何获取对应的slot的呢?

答案是通过reshard(从新分片)来实现。reshard能够将曾经调配给某个节点的任意数量的slot迁徙给另一个节点,在Redis外部是由redis-trib负责执行的。你能够了解为Redis其实曾经封装好了所有的命令,而redis-trib则负责向获取slot的节点和被转移slot的节点发送命令来最终实现reshard。

假如咱们须要向集群中退出一个D节点,而此时集群内曾经有A、B、C三个节点了。

此时redis-trib会向A、B、C三个节点发送迁徙出槽位的申请,同时向D节点发送筹备导入槽位的申请,做好筹备之后A、B、C这三个源节点就开始执行迁徙,将对应的slot所对应的键值对迁徙至指标节点D。最初redis-trib会向集群中所有主节点发送槽位的变更信息。

高可用及故障转移

Redis Cluster中保障集群高可用的思路和实现和Redis Sentinel一模一样,感兴趣的能够去看我之前写的对于Sentinel的文章Redis Sentinel-深入浅出原理和实战。

简略来说,针对A节点,某一个节点认为A宕机了,那么此时是主观宕机。而如果集群内超过半数的节点认为A挂了, 那么此时A就会被标记为主观宕机

一旦节点A被标记为了主观宕机,集群就会开始执行故障转移。其余失常运行的master节点会进行投票选举,从A节点的slave节点中选举出一个,将其切换成新的master对外提供服务。当某个slave取得了超过半数的master节点投票,就胜利入选。

入选胜利之后,新的master会执行slaveof no one来让本人进行复制A节点,使本人成为master。而后将A节点所负责解决的slot,全副转移给本人,而后就会向集群发PONG音讯来播送本人的最新状态。

依照一致性哈希的思维,如果某个节点挂了,那么就会沿着那个圆环,依照顺时针的程序找到遇到的第一个Redis实例。

而对于Redis Cluster,某个key它其实并不关怀它最终要去到哪个节点,他只关怀他最终落到哪个slot上,无论你节点怎么去迁徙,最终还是只须要找到对应的slot,而后再找到slot关联的节点,最终就可能找到最终的Redis实例了。

那这个PONG音讯又是什么货色呢?别急,上面就会聊到。

简略理解gossip协定

这就是Redis Cluster各个节点之间替换数据、通信所采纳的一种协定,叫做gossip

gossip: 谰言、八卦、小道消息

gossip是在1989年的论文上提出的,我看了一堆材料都说的是1987年发表的,然而文章里的工夫明确是1989年1月份发表。

感兴趣的能够去看看Epidemic Algorithms for Replicated . Database Maintenance,在过后提出gossip次要是为了解决在分布式数据库中,各个正本节点的数据同步问题。但随着技术的倒退,gossip后续也被宽泛使用于信息扩散、故障探测等等。

Redis Cluster就是利用了gossip来实现本身的信息扩散的。那应用gossip具体是如何通信的呢?

很简略,就像图里这样。每个Redis节点每秒钟都会向其余的节点发送PING,而后被PING的节点会回一个PONG

gossip协定音讯类型

Redis Cluster中,节点之间的音讯类型有5种,别离是MEET、PING、PONG、FAIL和PUBLISH。这些音讯别离传递了什么内容呢?我简略总结了一下。

音讯类型音讯内容
MEET给某个节点发送MEET音讯,申请接管音讯的节点退出到集群中
PING每隔一秒钟,抉择5个最久没有通信的节点,发送PING音讯,检测对应的节点是否在线;同时还有一种策略是,如果某个节点的通信提早大于了cluster-node-time的值的一半,就会立刻给该节点发送PING音讯,防止数据交换提早过久
PONG当节点接管到MEET或者PING音讯之后,会回一个PONG音讯给发送方,代表本人收到了MEET或者PING音讯。同时,节点也能够被动的通过PONG音讯向集群中播送本人的信息,让其余节点获取到本人最新的属性,就像实现了故障转移之后新的master向集群发送PONG音讯一样
FAIL用于播送本人的对某个节点的宕机判断,假如以后节点对A节点判断为宕机,就会立刻向Redis Cluster播送本人对于A节点的判断,所有收到音讯的节点就会对A节点做标记
PUBLISH用于向指定的Channel发送音讯,某个节点收到PUBLISH音讯之后会间接在集群内播送,这样一来,客户端无论连贯到任何节点都可能订阅这个Channel

应用gossip的优劣

既然Redis Cluster抉择了gossip,那必定存在一些gossip的长处,咱们接下来简略梳理一下。

长处形容
扩展性网络能够容许节点的任意减少和缩小,新减少的节点的状态最终会与其余节点统一。
容错性因为每个节点都持有一份残缺元数据,所以任何节点宕机都不会影响gossip的运行
健壮性与容错性相似,因为所有节点都持有数据,位置平台,是一个去中心化的设计,任何节点都不会影响到服务的运行
最终一致性当有新的信息须要传递时,音讯能够疾速的发送到所有的节点,让所有的节点都领有最新的数据

gossip能够在O(logN) 轮就能够将信息流传到所有的节点,为什么是O(logN)呢?因为每次ping,以后节点会带上本人的信息外加整个Cluster的1/10数量的节点信息,一起发送进来。你能够简略的把这个模型形象为:

你转发了一个特地有意思的文章到朋友圈,而后你的敌人们都感觉还不错,于是就一传十、十传百这样的散播进来了,这就是朋友圈的裂变流传

当然,gossip依然存在一些毛病。例如音讯可能最终会通过很多轮能力达到指标节点,而这可能会带来较大的提早。同时因为节点会随机选出5个最久没有通信的节点,这可能会造成某一个节点同时收到n个反复的音讯。

总结

总的来说,Redis Cluster相当于是把Redis的主从架构Sentinel集成到了一起,从Redis Cluster的高可用机制、判断故障转移以及执行故障转移的过程,都和主从、Sentinel相干,这也是为什么我在之前的文章里说,主从是Redis高可用架构的基石。

好了以上就是本篇博客的全部内容了,如果你感觉这篇文章对你有帮忙,还麻烦点个赞关个注分个享留个言

欢送微信搜寻关注【SH的全栈笔记】,查看更多相干文章

举荐浏览:

  • Redis根底-分析根底数据结构及其用法
  • 浅谈JVM和垃圾回收
  • Redis Sentinel-深入浅出原理和实战
  • 追随杠精的视角一起来理解Redis的主从复制
  • 简略理解InnoDB底层原理