Redis - 高可用集群扩展

Redis - 高可用集群扩展

1.Redis集群原理探讨

1.1 多角度看待集群架构

 对于Redis官方提供的cluster模式虽然我们在现在使用起来并不是十分困难,但是有一些思路是值的我们探讨的。我们知道,Redis是从3.x之后官方才开始推出master-cluster集群支持,这项技术的推出并不是无中生有,肯定是在这之前已经有很多场景需要这种技术去支持。其实在3.x之前一些具备一定能力的公司为了应付这样的场景,会自己去实现一套高可用集群的方案。
 这套自己实现的高可用集群方案有一个很关键的点就是网络通信。对于网络通信的实现很多都是采用了网状网络通信,利用Gossip这种交互方式使多个节点之间保持一个PING/PONG的过程。另一个关键的点就是节点动态扩容或者缩容的问题,节点的扩容缩容都会涉及数据的迁移,数据MIGRATE失败就会导致一个Key数据同时存在于两个节点,并且在4.x版本之前这种数据迁移是会造成主线程阻塞的。

1.2 集群架构原理

 对于集群架构的原理,其实主要的无外乎几点:

  1. 数据拆分:对于数据拆分这个问题几乎也是所有技术集群架构的一个核心点,我们这里主要需要弄清的就是垂直拆分水平拆分
    垂直拆分:这种拆分规则比较简单,其实就是将一个大的数据结构尽可能拆分成一些小的数据结构相组成。特别适合耦合度低的业务,相互之间影响很小,按照业务维度进行拆分为不同的数据结构。
    水平拆分:相比于垂直拆分稍微复杂一点,水平拆分其实就是将一个数据整体拆分开放入不同的数据库中,分片其实就是基于水平拆分的思路将整个数据体拆分为若干个数据片段放在不同的服务器上。
  2. 故障转移:主要通过Gossip节点信息同步实现,实现slave作为master的备份节点,并实现故障剔除master节点采用slave替换,并在替换完之后将结果通知到其他节点。
  3. 数据分片:在之前我们了解到了cluster模式对于节点故障转移、主从同步都可以通过哨兵和主从复制实现。若我们要自己去构造一个分布式集群架构系统,在实现上对于我们来说最关键的一点就是数据如何分片落在不同服务上。下面会介绍一致性哈希算法以及客户端和服务端分片技术。

2.客户端分片技术(一致性Hash算法)

2.1 一致性Hash算法是什么?

 分布式系统中负载均衡的问题,可以通过Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求并维护这些请求的信息,起到负载均衡的作用。

2.2 一致性Hash算法原理

 首先我们将整个节点集群看做一个Hash环,环上顺时针从整数0开始,一直到最大正整数(2的32次方进行hash取模,即0到2的32次方-1)。这里假定我们集群包含四个主节点,根据四个主节点ip计算的Hash值肯定会落到这个hash环上的某一个点,至此我们把服务器的四个ip映射到了一致性Hash环上。
 当客户端进行请求时,首先会根据Hash(Key)计算路由规则(Hash值),然后看Hash值落在Hash环的何处,根据Hash值在环上的位置顺时针找距离最近的节点IP作为路由IP。例如这里我们key2按照顺时针则落在master2节点上,key3落在master3节点上。
Redis - 高可用集群扩展
 当我们master2节点挂掉后,之前master2节点负责的区域则会顺时针顺势交给master3节点,此时key2和key3都由master3节点处理。
Redis - 高可用集群扩展
 当我们新增一个master5节点到集群时,根据对master5节点信息进行Hash后可能落在了master4和master1之间,也就是会对master1负责的区域再次进行切割,在master5节点没加入之前key5属于master1,而master5节点加入后key5则属于master5节点负责。
Redis - 高可用集群扩展
 当数据量越来越大时,整个Hash环上各节点会趋于平衡。当节点挂掉或者新增节点时都可能会导致节点倾斜,例如master2挂了之后key2和key3同时落在master3节点上,无法保证整个Hash环一定保持平衡。对于这些问题其实在设计一致性Hash算法时都是有考虑的,这个下面再介绍。

2.3 一致性Hash算法特性

 上面我们已经了解了一致性Hash算法的基本原理,可以总结出大概有以下几个特点:

  1. 单调性(Monotonicity):单调性是指若已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时候,应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其它服务器上去。
  2. 分散性(Spread):在分布式环境中,客户端请求时未必知道所有服务器信息,可能只知道其中一部分服务器信息。对于客户端来说,会将它自己所知道的部分服务器去作为一个完整的Hash环。如果多个客户端都把部分服务器作为一个完整的Hash环,那可能会导致同一个用户的请求(key)被路由到不同的服务器上处理。这种情况违背了一致性Hash算法的设计原理,应该尽可能避免。所谓分散性是指这种情况发生的严重程度,严格优秀的哈希算法应尽量避免、尽量降低分散性。 一致性Hash算法就具有很低的分散性。
  3. 平衡性(Balance):平衡性即负载均衡,指客户端Hash后的请求能够分散到不同的服务器上。一致性Hash可以做到每个服务器都进行处理请求,但是不能保证每个服务器处理的请求的数量大致相同。

2.4 一致性Hash算法虚拟节点

 在之前我们抛出过一个问题,就是当部分节点挂了之后,原本节点所负责的Hash环区域就会交接给顺时针最近的一个节点,当我们节点数量很少或者挂掉节点过多时都会使每个机器负载不均衡,从而造成Hash倾斜。于是虚拟节点的设计思路就出现了。
Redis - 高可用集群扩展
 为了避免过度Hash倾斜,增设虚拟节点可以很大程度避免这种问题。当我们物理机器(即服务节点)数目为A,虚拟节点设为B时,实际完整Hash环上节点个数为A*(B+1)(例如4个节点,每个节点有3个虚拟节点,则总共会有16个节点存在于Hash环上),若A节点虚拟节点为A1,A2,A3,将A、A1、A2、A3平均分布在环上各个位置,使A服务的节点尽量均匀分配在各个区域。若A节点挂掉之后,则A、A1、A2、A3区域转移至其他不同节点维护,避免了节点区域过于集中造成Hash倾斜。整个环上节点越多,Hash倾斜的可能性越小,但是过多的节点分散也会影响一定的性能。

2.5 客户端分片模式优缺点

 优点:

  1. 基于客户端分片方案是集群方案中最快的,没有任何中间件存在,仅仅需要客户端进行一次哈希计算,无需经过代理,没有官方集群方案的MOVED/ASK转向。
  2. 无需多余的Proxy代理机器,减少Proxy部署与维护带来的成本。
  3. 可灵活选择更适合不同业务和环境的哈希算法。

 缺点:

  1. 各种不同编程语言项目都需要自己实现客户端分片逻辑,维护成本过高。
  2. 对命令的支持不够完善,例如MSETMGET等同时操作多个Key的命令,并且对Redis迭代内容需要做对应的维护更新。
  3. 应用升级困难,若客户端分片逻辑改变则需将所有使用该客户端逻辑应用全部升级重启。
  4. 扩容十分困难,扩容需要中止服务提供对数据进行迁移,并且需要根据一定的规则进行数据迁移。

3.服务端分片技术(Twemproxy)

3.1 Twemproxy是什么?

 在上面我们介绍了数据分片可以通过客户端分片去实现,但是这是基于客户端有足够的分片能力,但是有一个问题是比较难以解决的,那就是扩容和缩容。这里我们介绍的Twemproxy就是服务端分片的一种实现,这是Twtter开源的一个RedisMemcache快速、轻量级代理服务器。Twemproxy是一个快速的单线程代理程序,可支持MemcachedRedisRedis代理中间件Twemproxy是一种利用中间件做分片的技术。Twemproxy处于客户端和服务器之间,将客户端发来请求进行一定规则的处理后(分片sharding),再转发给真正的Redis服务器。另外Codis也是一种服务器分片技术的实现,大家可以自行了解。
Twemproxy通过引入一个代理层,可以将多台RedisMemcached实例进行统一管理与分配,使应用程序只需要在Twemproxy上操作,而无需关心具体的RedisMemcached是如何执行的。

3.2 Twemproxy的特性

Twemproxy能够从各种服务器分片技术中脱颖而出,正式由于它设计的特性:

  1. 支持失败节点自动删除:我们可以设置重新连接该节点的时间以及连接多少次后删除该节点。
  2. 减少客户端直接与服务器连接的数量:自动分片到后端多个Redis实例上。
  3. 多种哈希算法:支持md5、crc16、crc32、crc32a、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur等多种哈希算法。
  4. 多种分片算法:支持random(随机)、ketama(一致性Hash算法)、modula(取模哈希)多种分片算法。

ps:我们在选择使用哪种架构都是需要根据我们实际情况考虑的,对于新项目而言选择Redis官方的cluster集群支持可能更好一些,毕竟官方的会保证迭代支持。但是官方提供集群方案也存在一些我们需要考虑的问题,例如:由于集群内嵌Sentinel功能,节点过多时即使没有进行客户端操作也会产生大量的流量;还有对于Slot存储开销也可能成为一个比较大的开销等问题。所以如何取舍还是需要看大家各自的具体需求。这里推荐一篇博客大家可以学习了解下【知乎Redis平台发展与演进之路】