Redis面试热点工程架构篇之数据同步

舒适提示 更佳阅读体验:【决战西二旗】|Redis面试热点之工程架构篇[2]

前言

前面用了3篇文章介绍了一些底层实现和工程架构相关的问题,鉴于Redis的热点问题仍是比较多的,所以今天继续来看工程架构相关的问题,感兴趣的能够先回顾一下以前的3篇文章,以下:
【决战西二旗】|Redis面试热点之底层实现篇
【决战西二旗】|Redis面试热点之底层实现篇(续)
【决战西二旗】|Redis面试热点之工程架构篇面试

经过本文你将了解到如下内容:segmentfault

  • Redis的数据同步机制
    持久化和数据同步的关系、Redis分布式存储的CAP选择、Redis数据同步复制和异步复制、全量复制和增量复制的原理、无盘复制等。

Q:谈谈你对Redis数据同步(复制)的理解吧!后端

持久化和数据同步的关系

理解持久化和数据同步的关系,须要从单点故障和高可用两个角度来分析:数组

单点宕机故障

假如咱们如今只有一台做为缓存的Redis机器,经过持久化将热点数据写到磁盘,某时刻该Redis单点机器发生故障宕机,此期间缓存失效,主存储服务将承受全部的请求压力倍增,监控程序将宕机Redis机器拉起。缓存

重启以后,该机器能够Load磁盘RDB数据进行快速恢复,恢复的时间取决于数据量的多少,通常秒级到分钟级不等,恢复完成保证以前的热点数据还在,这样存储系统的CacheMiss就会下降,有效下降了缓存击穿的影响。服务器

在单点Redis中持久化机制很是有用,只写文字容易让你们睡着,我画了张图网络

高可用的Redis系统

做为一个高可用的缓存系统单点宕机是不容许的,所以就出现了主从架构,对主节点的数据进行多个备份,若是主节点挂点,能够马上切换状态最好的从节点为主节点,对外提供写服务,而且其余从节点向新主节点同步数据,确保整个Redis缓存系统的高可用。架构

如图展现了一个一主两从读写分离的Redis系统主节点故障迁移的过程,整个过程并无中止正常工做,大大提升了系统的高可用:并发

从上面的两点分析能够得出个小结论【划重点】:
持久化让单点故障再也不可怕,数据同步为高可用插上翅膀。异步

咱们理解了数据同步对Redis的重要做用,接下来继续看数据同步的实现原理和过程、重难点等细节问题吧!

Redis系统中的CAP理论

对分布式存储有了解的读者必定知道CAP理论,说来惭愧笔者在2018年3月份换工做的时候,去Face++旷视科技面后端开发岗位时就遇到了CAP理论,除了CAP理论问题以外其余问题都在射程内,因此最终仍是拿了Offer。

可是印象很深T大毕业的面试官说前面的问题答得都不错,为啥CAP问题答得这么菜…其实我当时只知道CAP理论就像高富帅同样,不那么容易达到...细节不清楚...各位吃瓜读者,笔者前面说这个小事情的目的是想表达:CAP理论对于理解分布式存储很是重要,下回大家面试被问到CAP别怪我没提醒。

 

在理论计算机科学中,CAP定理又被称做布鲁尔定理Brewer's theorem,这个定理起源于加州大学伯克利分校的计算机科学家埃里克·布鲁尔在2000年的分布式计算原理研讨会PODC上提出的一个猜测

在2002年麻省理工学院的赛斯·吉尔伯特和南希·林奇发表了布鲁尔猜测的证实,使之成为一个定理。它指出对于一个分布式计算系统来讲,不可能同时知足如下三点:

  1. C Consistent 一致性 连贯性
  2. A Availability 可用性
  3. P Partition Tolerance 分区容忍性

来看一张阮一峰大佬画的图:

举个简单的例子,说明一下CP和AP的兼容性:
CP和AP问题
理解CP和AP的关键在于分区容忍性P,网络分区在分布式存储中再日常不过了,即便机器在一个机房,也不可能全都在一个机架或一台交换机。

这样在局域网就会出现网络抖动,笔者作过1年多DPI对于网络传输中最深入的三个名词:丢包、乱序、重传。因此咱们看来风平浪静的网络,在服务器来讲多是风大浪急,一不当心就不通了,因此当网络出现断开时,这时就出现了网络分区问题。


对于Redis数据同步而言,假设从结点和主结点在两个机架上,某时刻发生网络断开,若是此时Redis读写分离,那么从结点的数据必然没法与主继续同步数据。在这种状况下,若是继续在从结点读取数据就形成数据不一致问题,若是强制保证数据一致从结点就没法提供服务形成不可用问题,从而看出在P的影响下C和A没法兼顾。

其余几种状况就不深刻了,从上面咱们能够得出结论:当Redis多台机器分布在不一样的网络中,若是出现网络故障,那么数据一致性和服务可用性没法兼顾,Redis系统对此必须作出选择,事实上Redis选择了可用性,或者说Redis选择了另一种最终一致性。

最终一致性
Redis选择了最终一致性,也就是不保证主从数据在任什么时候刻都是一致的,而且Redis主从同步默认是异步的,亲爱的盆友们不要晕!不要蒙圈!

我来一下解释同步复制和异步复制(注意:考虑读者的感觉 我并无写成同步同步和异步同步 哈哈)

一图胜千言,看红色的数字就知道同步复制和异步复制的区别了:

  • 异步复制:当客户端向主结点写了hello world,主节点写成功以后就向客户端回复OK,这样主节点和客户端的交互就完成了,以后主节点向从结点同步hello world,从结点完成以后向主节点回复OK,整个过程客户端不须要等待从结点同步完成,所以整个过程是异步实现的。
  • 同步复制:当客户端向主结点写了hello world,主节点向从结点同步hello world,从结点完成以后向主节点回复OK,以后主节点向客户端回复OK,整个过程客户端须要等待从结点同步完成,所以整个过程是同步实现的。

Redis选择异步复制能够避免客户端的等待,更符合现实要求,不过这个复制方式能够修改,根据本身需求而定吧。

从从复制
假如Redis高可用系统中有一主四从,若是四个从同时向主节点进行数据同步,主节点的压力会比较大,考虑到Redis的最终一致性,所以Redis后续推出了从从复制,从而将单层复制结构演进为多层复制结构,笔者画了个图看下:

全量复制和增量复制

全量复制是从结点由于故障恢复或者新添加从结点时出现的初始化阶段的数据复制,这种复制是将主节点的数据所有同步到从结点来完成的,因此成本大但又不可避免。

增量复制是主从结点正常工做以后的每一个时刻进行的数据复制方式,涓涓细流同步数据,这种同步方式又轻又快,优势确实很多,不过若是没有全量复制打下基础增量复制也没戏,因此两者不是矛盾存在而是相互依存的。

全量复制过程分析

Redis的全量复制过程主要分三个阶段:

  • 快照阶段:从结点向主结点发起SYNC全量复制命令,主节点执行bgsave将内存中所有数据生成快照并发送给从结点,从结点释放旧内存载入并解析新快照,主节点同时将此阶段所产生的新的写命令存储到缓冲区。
  • 缓冲阶段:主节点向从节点同步存储在缓冲区的操做命令,这部分命令主节点是bgsave以后到从结点载入快照这个时间段内的新增命令,须要记录要否则就出现数据丢失。
  • 增量阶段:缓冲区同步完成以后,主节点正常向从结点同步增量操做命令,至此主从保持基本一致的步调。

借鉴参考1的一张图表,写的很好,我就再也不重复画图了:

考虑一个多从并发全量复制问题
若是此时有多个从结点同时向主结点发起全量同步请求会怎样?
Redis主结点是个聪明又诚实的家伙,好比如今有3个从结点A/B/C陆续向主节点发起SYNC全量同步请求。

  1. 主节点在对A进行bgsave的同时,B和C的SYNC命令到来了,那么主节点就一锅烩,把针对A的快照数据和缓冲区数据同时同步给ABC,这样提升了效率又保证了正确性。
  2. 主节点对A的快照已经完成而且如今正在进行缓冲区同步,那么只能等A完成以后,再对B和C进行和A同样的操做过程,来实现新节点的全量同步,因此主节点并无偷懒而是重复了这个过程,虽然繁琐可是保证了正确性。

再考虑一个快照复制循环问题
主节点执行bgsave是比较耗时且耗内存的操做,期间从结点也经历装载旧数据->释放内存->装载新数据的过程,内存先升后降再升的动态过程,从而知道不管主节点执行快照仍是从结点装载数据都是须要时间和资源的。

抛开对性能的影响,试想若是主节点快照时间是1分钟,在期间有1w条新命令到来,这些新命令都将写到缓冲区,若是缓冲区比较小只有8k,那么在快照完成以后,主节点缓冲区也只有8k命令丢失了2k命令,那么此时从结点进行全量同步就缺失了数据,是一次错误的全量同步。

无奈之下,从结点会再次发起SYNC命令,从而陷入循环,所以缓冲区大小的设置很重要,二话不说再来一张图:

增量复制过程分析

增量复制过程稍微简单一些,可是很是有用,试想复杂的网络环境下,并非每次断开都没法恢复,若是每次断开恢复后就要进行全量复制,那岂不是要把主节点搞死,因此增量复制算是对复杂网络环境下数据复制过程的一个优化,容许一段时间的落后,最终追上就行。

增量复制是个典型的生产者-消费者模型,使用定长环形数组(队列)来实现,若是buffer满了那么新数据将覆盖老数据,所以从结点在复制数据的同时向主节点反馈本身的偏移量,从而确保数据不缺失。

这个过程很是好理解,kakfa这种MQ也是这样的,因此在合理设置buffer大小的前提下,理论上从的消费能力是大于主的生产能力的,大部分只有在网络断开时间过长时会出现buffer被覆盖,从结点消费滞后的状况,此时只能进行全量复制了。

无盘复制

理解无盘复制以前先看下什么是有盘复制呢?
所谓盘是指磁盘,多是机械磁盘或者SSD,可是不管哪种相比内存都更慢,咱们都知道IO操做在服务端的耗时是占大头的,所以对于全量复制这种高IO耗时的操做来讲,尤为当服务并发比较大且还在进行其余操做时对Redis服务自己的影响是比较大大,以前的模式时这样的:

在Redis2.8.18版本以后,开发了无盘复制,也就是避免了生成的RDB文件落盘再加载再网络传输的过程,而是流式的遍历发送过程,主节点一边遍历内存数据,一边将数据序列化发送给从结点,从结点没有变化,仍然将数据依次存储到本地磁盘,完成传输以后进行内存加载,可见无盘复制是对IO更友好。

小结

时间缘由只能写这么多了,和你们一块儿学习不是把桶填满而是把火点燃

回顾一下:本文主要讲述了持久化和数据同步的关系、Redis分布式存储的CAP选择、Redis数据同步复制和异步复制、全量复制和增量复制的原理、无盘复制等,相信耐心的读者必定会有所收获的。

最后能够思考一个问题:
Redis的数据同步仍然会出现数据丢失的状况,好比主节点往缓冲区写了10k条操做命令,此时主挂掉了,从结点只消费了9k操做命令,那么切主以后从结点的数据就丢失了1k,即便旧主节点恢复也只能做为从节点向新主节点发起全量复制,那么咱们该如何优化这种状况呢?

巨人的肩膀

    1. 钱文品-《Redis深度历险核心原理和应用实践》
相关文章
相关标签/搜索