高并发系统设计(十一):【缓存的正确使用姿势】缓存如何做到高可用?

为了增大缓存系统架构的高可用,增加缓存的命中率,尽量避免请求穿透缓存进入后端数据库,主要选择的方案有客户端方案、中间代理层方案和服务端方案三大类:

  • 客户端方案就是在客户端配置多个缓存的节点,通过缓存写入和读取算法策略来实现分布式,从而提高缓存的可用性。

  • 中间代理层方案是在应用代码和缓存节点之间增加代理层,客户端所有的写入和读取的请求都通过代理层,而代理层中会内置高可用策略,帮助提升缓存系统的高可用。

  • 服务端方案就是Redis 2.4版本后提出的Redis Sentinel方案。

客户端方案

在客户端方案中,你需要关注缓存的写和读两个方面:

  • 写入数据时,需要把被写入缓存的数据分散到多个节点中,即进行数据分片;

  • 读数据时,可以利用多组的缓存来做容错,提升缓存系统的可用性。关于读数据,这里可以使用主从和多副本两种策略,两种策略是为了解决不同的问题而提出的。

1.缓存数据如何分片

单一的缓存节点受到机器内存、网卡带宽和单节点请求量的限制,不能承担比较高的并发,因此我们考虑将数据分片,依照分片算法将数据打散到多个不同的节点上,每个节点上存储部分数据。这样在某个节点故障的情况下,其他节点也可以提供服务,保证了一定的可用性。

用一致性Hash算法可以很好地解决增加和删减节点时,命中率下降的问题。但也存在问题:节点数过多也会增加出问题的概率,推荐4到6个节点为佳!

 

  • 缓存节点在圆环上分布不平均,会造成部分缓存节点的压力较大;当某个节点故障时,这个节点所要承担的所有访问都会被顺移到另一个节点上,会对后面这个节点造成压力。(举例:比如一个有三个节点A、B、C承担整体的访问,每个节点的访问量平均,A故障后,B将承担双倍的压力(A和B的全部请求),当B承担不了流量Crash后,C也将因为要承担原先三倍的流量而Crash,这就造成了整体缓存系统的雪崩。解决:可以在一致性Hash算法中引入虚拟节点的概念。它将一个缓存节点计算多个Hash值分散到圆环的不同位置,这样既实现了数据的平均,而且当某一个节点故障或者退出的时候,它原先承担的Key将以更加平均的方式分配到其他节点上,从而避免雪崩的发生。

  • 一致性Hash算法的脏数据问题。(举例:比方说,在集群中有两个节点A和B,客户端初始写入一个Key为k,值为3的缓存数据到Cache A中。这时如果要更新k的值为4,但是缓存A恰好和客户端连接出现了问题,那这次写入请求会写入到Cache B中。接下来缓存A和客户端的连接恢复,当客户端要获取k的值时,就会获取到存在Cache A中的脏数据3,而不是Cache B中的4。解决:在使用一致性Hash算法时一定要设置缓存的过期时间。)

2.缓存数据库的主从,如Memcache、Redis

3.缓存数服务器的一主多从

4.中间代理层方案

所有缓存的读写请求都是经过代理层完成的。代理层是无状态的,主要负责读写请求的路由功能,并且在其中内置了一些高可用的逻辑,不同的开源中间代理层方案中使用的高可用策略各有不同。比如在Twemproxy中,Proxy保证在某一个Redis节点挂掉之后会把它从集群中移除,后续的请求将由其他节点来完成。

5.服务端方案

Redis在2.4版本中提出了Redis Sentinel模式来解决主从Redis部署时的高可用问题,它可以在主节点挂了以后自动将从节点提升为主节点,保证整体集群的可用性,整体的架构如下图所示:

 

 

 

Redis Sentinel也是集群部署的,这样可以避免Sentinel节点挂掉造成无法自动故障恢复的问题,每一个Sentinel节点都是无状态的。在Sentinel中会配置Master的地址,Sentinel会时刻监控Master的状态,当发现Master在配置的时间间隔内无响应,就认为Master已经挂了,Sentinel会从从节点中选取一个提升为主节点,并且把所有其他的从节点作为新主的从节点。Sentinel集群内部在仲裁的时候,会根据配置的值来决定当有几个Sentinel节点认为主挂掉可以做主从切换的操作,也就是集群内部需要对缓存节点的状态达成一致才行。

Redis Sentinel不属于代理层模式,因为对于缓存的写入和读取请求不会经过Sentinel节点。Sentinel节点在架构上和主从是平级的,是作为管理者存在的,所以可以认为是在服务端提供的一种高可用方案。

 

posted @ 2020-06-27 15:37  温柔的风  阅读(652)  评论(0编辑  收藏  举报