高可用的本质都是冗余备份,一个不够就再来一个。Redis也不例外。Redis通过主从来实现高可用,从机可以有一个或多个。当主机出现故障时,Redis哨兵集群会自动进行故障转移,选出一个从机升级为主机继续对外服务,从而实现高可用。这里简要介绍下其流程。

        Redis主从一般是读写分离,主机对外提供读写服务,从机提供只读服务。如果主从同时对外提供读写容易出现脑裂问题造成数据不一致,比如两个客户端通过主从同时写同一个key,此时就会造成不一致。为了避免不一致现象,一般都会读写分离。即便是读写分离,仍然会存在数据不一致情况,因为数据从主机同步到从机需要一定的时间,在此期间,数据仍是不一致。这种情况下,需要业务进行兼容处理,如果业务需要数据强一致,就得继续从主机读取,对数据不敏感的业务则无需关心。

        主从之间需要进行数据同步从而保证数据最终一致性。Redis数据同步方式可以分为两种:全量同步、增量同步。

        全量同步就是将主机所有数据全部打包同步给从机,增量同步是指仅同步主从不一致的数据。Redis全量同步是通过RDB内存快照文件实现,增量同步则是将主机收到的写命令传播给从机。

        当客户端通过replicaof MasterIP Port或者通过配置文件指定主机的时候,会先进行一次全量同步,全量同步完成后,主从中间保有一条连接,后续主机会将新收到的写命令异步传播给从机,与此同时,这些命令会写入到主机的一个环形缓存backlog里面。如果主从之间异常断开,再次重连后,从机会尝试进行增量同步,即从上次断开的地方继续同步。这时候就会用到这个缓存。从机每次发起同步命令会携带backlog的一个偏移量,主机根据这个偏移量查找backlog,找到则只需要同步偏移量之后的部分,找不到只能全量同步,因为全量同步对主机影响比较大,所以要尽可能利用增量同步,backlog的容量配置就很重要,配置太小很容易覆盖,配置太大影响主机内存,具体配置多少,要根据主机写入速度以及主从延迟时间计算出来。

        说完了主从同步,再来看下如何主从切换。

        当主机出现故障的时候,需要在从机中选择一个当主机。这个过程涉及到三个问题:

1. 如何判断主机故障?

2. 如何选择从机?

3. 如何切换?

        判断主机是否故障的机制很简单,就是通过心跳。谁来判断呢,哨兵。哨兵是一个特殊的Redis实例,主要用来监控主从故障并在需要的时候自动进行故障转移。可能有同学会问,如果哨兵自己挂了怎么办?一个不够那就再来一个。多个哨兵组成哨兵集群。哨兵集群的好处除了提高哨兵自身的高可用之外,还能够减少主从故障误判率。比方说,因为网络原因或者主机高负载导致心跳中断,如果只有一个哨兵的话,那么哨兵可能就直接判定主机故障从而进行故障转移。实际上,主机运行正常,这种情况属于误判,误判带来的成本会很高。如果有多个哨兵的话,那么判断主机是否故障就可以通过集体讨论的方式进行,如果大部分哨兵都认为主机故障,那么才进行故障转移,这样就能够减少误判率。

        具体的,哨兵运行的时候会和主机进行连接,同时订阅主机的一个频道,通过这个频道获得其他哨兵的信息并将自己的信息发布出去。然后相互之间建立连接。同时,还通过在主机执行info命令获得从机信息,并于从机建立链接获取从机复制进度等信息。

        哨兵会定时和主机发送心跳,当主机超过一定次数没能正常反应之后(断联或返回错误),哨兵就会将主机状态标记为主观下线,同时会询问其它哨兵主机是否下线。加上自己,如果超过某个指定数量的哨兵都认为主机主观下线,则将主机的状态标记为客观下线,此时就可以发起故障转移了。这个数量通过配置quoram来制定,通常都是半数以上。

        同一时间可能有多个哨兵同时发现主机客观下线,当时发起故障转移的只能有一个。否则,如果同时出现多个哨兵同时进行故障转移,选出的新主机又不一样,那么又会造成很大的问题。因此,需要在哨兵之间选举一个leader来进行故障转移。选举流程和判断主机客观下线状态基本一致,哨兵会询问其它哨兵是否同意自己当leader,如果被询问的哨兵是首次投票,则会同意,否则,则会拒绝。最终,只有当哨兵拿到半数以上的票数才能够当选为leader。假设一个拥有4个哨兵的集群,其中两个哨兵正在发起选举,他俩同时拿到2票,因为不满足大于半数以上(4/2+1=3),选举不成功。针对这种情况,哨兵集群会冷却一定时间,再次发起投票,直到投票成功。

        当选举出leader之后,就可以进行故障转移了,首先leader哨兵需要从从机中选择一个当主机,具体选择哪一个,存在一系列规则:

        1. 从机服务正常,即心跳正常。

        2. 按照从机优先级排序,选择优先级最高的。为啥会存在优先级呢,不同的从机配置可能不一样,可能有的从机配置高,有的低,这个时候优先级配置就会不一样。

        3. 优先级相同则选择复制偏移量最大的一个。

        4. 如果优先级、偏移量都一样,则选择一个id最小的一个。每个redis实例运行时,都会生成一个随机的ID。

        选出合适的从机后,leader哨兵会发送slaveof no one命令,将从机变为主机。当从机状态更改完成后,会通知其它从机从新主机开始复制,最后,当原有故障的主机恢复后,会通知它变为从机,并从新主机复制。如此一来,整个故障转移就完成了。

        哨兵除了监控、故障切换之外,还能够提供一些列通知功能,比如告诉客户端关于主从设备的一些状态等等。

        实际运行过程中,客户端一般对服务器故障转移无感知。比如我们业务使用的腾讯云Redis实例,会存在一个Redis代理服务,业务只需访问代理服务即可,至于主机的变更,则完全有代理服务来负责。

        以上就是Redis高可用的实现过程,原理比较简单,又能够保证较高的可用性。前几年做过一个电信设备的高可用,当时做法是实现了BFD(双向转发检测) 协议,主备机之间通过BFD链接,当备机发现BFD断开后会自动生主,现在看来,这个方案存在很大的缺陷,即很容易误判。如果想减少误判那就得延长检测时间,可这样又会造成故障恢复时间较长。现在看来,如果实现类似Redis哨兵集群的方式,那么误判率将大大减少。

参考资料:

1. 极客课堂.Redis 核心技术与实战 06 | 数据同步:主从库如何实现数据一致?

2. 极客课堂.Redis 核心技术与实战 

3. 极客课堂.Redis 核心技术与实战 08 | 哨兵集群:哨兵挂了,主从库还能切换吗?

4. 《Redis设计与实现》黄健宏

5. High availability with Redis Sentinel High availability with Redis Sentinel | Redis

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: redis