Java面板题10-中间件

列举一个经常使用的Redis客户端的并发模型

 

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问前端

Redis自己没有锁的概念,Redis对于多个客户端链接并不存在竞争,可是在Jedis客户端对Redis进行并发访问时会发生链接超时、数据转换错误、阻塞、客户端关闭链接等问题,这些问题均是因为客户端链接混乱形成。node

对此有2种解决方法:redis

1.客户端角度,为保证每一个客户端间正常有序与Redis进行通讯,对链接进行池化,同时对客户端读写Redis操做采用内部锁synchronized算法

2.服务器角度,利用setnx实现锁。如某客户端要得到一个名字list的锁,客户端使用下面的命令进行获取:后端

Setnx lock.list  current time + lock timeout数组

 如返回1,则该客户端得到锁,把lock. list的键值设置为时间值表示该键已被锁定,该客户端最后能够经过DEL lock.list来释放该锁。缓存

 如返回0,代表该锁已被其余客户端取得,等对方完成或等待锁超时服务器

 

 

列举一个经常使用的消息中间件,若是消息要保序如何实现

 

 

针对这个问题,经过某种算法,将须要保持前后顺序的消息放到同一个消息队列中(kafka中就是partition, rabbitMq中就是queue)。而后只用一个消费者去消费该队列。网络

 

你的设计如何考虑Hash冲突 

 

1.开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)数据结构

2.再哈希法

3.链地址法(Java hashmap就是这么作的)

4.创建一个公共溢出区

 

一致性hash

 

在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操做是分布式集群管理最基本的功能。若是采用经常使用的hash(object)%N算法,那么在有机器添加或者删除后,不少原有的数据就没法找到了,这样严重的违反了单调性原则

 


一致性哈希算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性哈希算法是对2^32取模,什么意思呢?咱们慢慢聊。

首先,咱们把二的三十二次方想象成一个圆,就像钟表同样,钟表的圆能够理解成由60个点组成的圆,而此处咱们把这个圆想象成由2^32个点组成的圆,示意图以下:

 

圆环的正上方的点表明0,0点右侧的第一个点表明1,以此类推,二、三、四、五、6……直到232-1,也就是说0点左侧的第一个点表明232-1

咱们把这个由2的32次方个点组成的圆环称为hash环。

 

那么,一致性哈希算法与上图中的圆环有什么关系呢?咱们继续聊,仍然以以前描述的场景为例,假设咱们有3台缓存服务器,服务器A、服务器B、服务器C,那么,在生产环境中,这三台服务器确定有本身的IP地址,咱们使用它们各自的IP地址进行哈希计算,使用哈希后的结果对2^32取模,可使用以下公式示意。

hash(服务器A的IP地址) % 2^32

经过上述公式算出的结果必定是一个0到232-1之间的一个整数,咱们就用算出的这个整数,表明服务器A,既然这个整数确定处于0到232-1之间,那么,上图中的hash环上一定有一个点与这个整数对应,而咱们刚才已经说明,使用这个整数表明服务器A,那么,服务器A就能够映射到这个环上,用下图示意

同理,服务器B与服务器C也能够经过相同的方法映射到上图中的hash环中

hash(服务器B的IP地址) % 2^32

hash(服务器C的IP地址) % 2^32

经过上述方法,能够将服务器B与服务器C映射到上图中的hash环上,示意图以下

假设3台服务器映射到hash环上之后如上图所示(固然,这是理想的状况,咱们慢慢聊)。

 

好了,到目前为止,咱们已经把缓存服务器与hash环联系在了一块儿,咱们经过上述方法,把缓存服务器映射到了hash环上,那么使用一样的方法,咱们也能够将须要缓存的对象映射到hash环上。

 

假设,咱们须要使用缓存服务器缓存图片,并且咱们仍然使用图片的名称做为找到图片的key,那么咱们使用以下公式能够将图片映射到上图中的hash环上。

hash(图片名称) % 2^32

映射后的示意图以下,下图中的橘黄色圆形表示图片

好了,如今服务器与图片都被映射到了hash环上,那么上图中的这个图片到底应该被缓存到哪一台服务器上呢?上图中的图片将会被缓存到服务器A上,为何呢?由于从图片的位置开始,沿顺时针方向遇到的第一个服务器就是A服务器,因此,上图中的图片将会被缓存到服务器A上,以下图所示。

没错,一致性哈希算法就是经过这种方法,判断一个对象应该被缓存到哪台服务器上的,将缓存服务器与被缓存对象都映射到hash环上之后,从被缓存对象的位置出发,沿顺时针方向遇到的第一个服务器,就是当前对象将要缓存于的服务器,因为被缓存对象与服务器hash后的值是固定的,因此,在服务器不变的状况下,一张图片一定会被缓存到固定的服务器上,那么,当下次想要访问这张图片时,只要再次使用相同的算法进行计算,便可算出这个图片被缓存在哪一个服务器上,直接去对应的服务器查找对应的图片便可。

 

刚才的示例只使用了一张图片进行演示,假设有四张图片须要缓存,示意图以下

1号、2号图片将会被缓存到服务器A上,3号图片将会被缓存到服务器B上,4号图片将会被缓存到服务器C上。

 

一致性哈希算法的优势

通过上述描述,我想兄弟你应该已经明白了一致性哈希算法的原理了,可是话说回来,一致性哈希算法可以解决以前出现的问题吗,咱们说过,若是简单的对服务器数量进行取模,那么当服务器数量发生变化时,会产生缓存的雪崩,从而颇有可能致使系统崩溃,那么使用一致性哈希算法,可以避免这个问题吗?咱们来模拟一遍,便可获得答案。

 

假设,服务器B出现了故障,咱们如今须要将服务器B移除,那么,咱们将上图中的服务器B从hash环上移除便可,移除服务器B之后示意图以下。

在服务器B未移除时,图片3应该被缓存到服务器B中,但是当服务器B移除之后,按照以前描述的一致性哈希算法的规则,图片3应该被缓存到服务器C中,由于从图片3的位置出发,沿顺时针方向遇到的第一个缓存服务器节点就是服务器C,也就是说,若是服务器B出现故障被移除时,图片3的缓存位置会发生改变

可是,图片4仍然会被缓存到服务器C中,图片1与图片2仍然会被缓存到服务器A中,这与服务器B移除以前并无任何区别,这就是一致性哈希算法的优势,若是使用以前的hash算法,服务器数量发生改变时,全部服务器的全部缓存在同一时间失效了,而使用一致性哈希算法时,服务器的数量若是发生改变,并非全部缓存都会失效,而是只有部分缓存会失效,前端的缓存仍然能分担整个系统的压力,而不至于全部压力都在同一时间集中到后端服务器上。

 

这就是一致性哈希算法所体现出的优势。

 

hash环的偏斜

在介绍一致性哈希的概念时,咱们理想化的将3台服务器均匀的映射到了hash环上,以下图所示

可是,理想很丰满,现实很骨感,咱们想象的与实际状况每每不同。

在实际的映射中,服务器可能会被映射成以下模样。

聪明如你必定想到了,若是服务器被映射成上图中的模样,那么被缓存的对象颇有可能大部分集中缓存在某一台服务器上,以下图所示。

上图中,1号、2号、3号、4号、6号图片均被缓存在了服务器A上,只有5号图片被缓存在了服务器B上,服务器C上甚至没有缓存任何图片,若是出现上图中的状况,A、B、C三台服务器并无被合理的平均的充分利用,缓存分布的极度不均匀,并且,若是此时服务器A出现故障,那么失效缓存的数量也将达到最大值,在极端状况下,仍然有可能引发系统的崩溃,上图中的状况则被称之为hash环的偏斜,那么,咱们应该怎样防止hash环的偏斜呢?一致性hash算法中使用"虚拟节点"解决了这个问题,咱们继续聊。

 

虚拟节点

话接上文,因为咱们只有3台服务器,当咱们把服务器映射到hash环上的时候,颇有可能出现hash环偏斜的状况,当hash环偏斜之后,缓存每每会极度不均衡的分布在各服务器上,聪明如你必定已经想到了,若是想要均衡的将缓存分布到3台服务器上,最好能让这3台服务器尽可能多的、均匀的出如今hash环上,可是,真实的服务器资源只有3台,咱们怎样凭空的让它们多起来呢,没错,就是凭空的让服务器节点多起来,既然没有多余的真正的物理服务器节点,咱们就只能将现有的物理节点经过虚拟的方法复制出来,这些由实际节点虚拟复制而来的节点被称为"虚拟节点"。加入虚拟节点之后的hash环以下。

“虚拟节点"是"实际节点”(实际的物理服务器)在hash环上的复制品,一个实际节点能够对应多个虚拟节点。

从上图能够看出,A、B、C三台服务器分别虚拟出了一个虚拟节点,固然,若是你须要,也能够虚拟出更多的虚拟节点。引入虚拟节点的概念后,缓存的分布就均衡多了,上图中,1号、3号图片被缓存在服务器A中,5号、4号图片被缓存在服务器B中,6号、2号图片被缓存在服务器C中,若是你还不放心,能够虚拟出更多的虚拟节点,以便减少hash环偏斜所带来的影响,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的几率就越大。

 

LRU算法

 

LRU是什么?按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个很是著名的计算机操做系统基础理论得来的:最近使用的页面数据会在将来一段时期内仍然被使用,已经好久没有使用的页面颇有可能在将来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据而后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!由于,利用LRU咱们能够解决不少实际开发中的问题,而且很符合业务场景。


利用双向链表实现

双向链表有一个特色就是它的链表是双路的,咱们定义好头节点和尾节点,而后利用先进先出(FIFO),最近被放入的数据会最先被获取。其中主要涉及到添加、访问、修改、删除操做。首先是添加,若是是新元素,直接放在链表头上面(若是超出链表的size,移除最后一个元素);访问的话,在头节点的能够不用管,若是是在中间位置或者尾巴,就要将数据移动到头节点;修改操做也同样,修改原值以后,再将数据移动到头部;删除的话,直接删除;

 

slab分配,如何减小内存碎片

 

缓存失效的几种形式

1 缓存穿透

缓存穿透是指查询一个必定不存在的数据,因为缓存是不命中时被动写的,而且出于容错考虑,若是从存储层查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击咱们的应用,这就是漏洞。 key不存在时,大量的数据进来查询DB

解决方案:有不少种方法能够有效地解决缓存穿透问题,最多见的则是采用布隆过滤器,将全部可能存在的数据哈希到一个足够大的bitmap中,一个必定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(咱们采用的就是这种),若是一个查询返回的数据为空(无论是数 据不存在,仍是系统故障),咱们仍然把这个空结果进行缓存,但它的过时时间会很短,最长不超过五分钟。

2 缓存雪崩(缓存失效)

缓存雪崩是指在咱们设置缓存时采用了相同的过时时间,致使缓存在某一时刻同时失效,请求所有转发到DB,DB瞬时压力太重雪崩。 key是多个

解决方案:缓存失效时的雪崩效应对底层系统的冲击很是可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,好比咱们能够在原有的失效时间基础上增长一个随机值,好比1-5分钟随机,这样每个缓存的过时时间的重复率就会下降,就很难引起集体失效的事件。 关键字: 时间岔开,确保你们的key不会落在同一个expire点上。

3 缓存击穿(缓存并发)

对于一些设置了过时时间的key,若是这些key可能会在某些时间点被超高并发地访问,是一种很是“热点”的数据。这个时候,须要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是不少key。 指同一个key。

解决方案:致使问题的缘由是同一时间查,同一时间写缓存,致使并发下缓存也没用,因此考虑使用单线程等方法将写缓存保证只有一个去查了写,其余的使用缓存。

业界比较经常使用的作法,是使用mutex。简单地来讲,就是在缓存失效的时候(判断拿出来的值为空),不是当即去load db,而是先使用缓存工具的某些带成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操做返回成功时,再进行load db的操做并回设缓存;不然,就重试整个get缓存的方法

 

什么是布隆过滤器,其实现原理是? False positive指的是?

 

本质上布隆过滤器是一种数据结构,比较巧妙的几率型数据结构(probabilistic data structure),特色是高效地插入和查询,能够用来告诉你 “某样东西必定不存在或者可能存在”。

相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,可是缺点是其返回的结果是几率性的,而不是确切的。

 

HashMap的问题

讲述布隆过滤器的原理以前,咱们先思考一下,一般你判断某个元素是否存在用的是什么?应该蛮多人回答 HashMap 吧,确实能够将值映射到 HashMap 的 Key,而后能够在 O(1) 的时间复杂度内返回结果,效率奇高。可是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,一般空间是不能被用满的,而一旦你的值不少例如上亿的时候,那 HashMap 占据的内存大小就变得很可观了。

还好比说你的数据集存储在远程服务器上,本地服务接受输入,而数据集很是大不可能一次性读进内存构建 HashMap 的时候,也会存在问题

 

布隆过滤器是一个 bit 向量或者说 bit 数组,长这样:


若是咱们要映射一个值到布隆过滤器中,咱们须要使用多个不一样的哈希函数生成多个哈希值,并对每一个生成的哈希值指向的 bit 位置 1,例如针对值 “baidu” 和三个不一样的哈希函数分别生成了哈希值 一、四、7,则上图转变为:

 

 

Ok,咱们如今再存一个值 “tencent”,若是哈希函数返回 三、四、8 的话,图继续变为:

 

 

 

值得注意的是,4 这个 bit 位因为两个值的哈希函数都返回了这个 bit 位,所以它被覆盖了。如今咱们若是想查询 “dianping” 这个值是否存在,哈希函数返回了 一、五、8三个值,结果咱们发现 5 这个 bit 位上的值为 0,说明没有任何一个值映射到这个 bit 位上,所以咱们能够很肯定地说 “dianping” 这个值不存在。而当咱们须要查询 “baidu” 这个值是否存在的话,那么哈希函数必然会返回 一、四、7,而后咱们检查发现这三个 bit 位上的值均为 1,那么咱们能够说 “baidu” 存在了么?答案是不能够,只能是 “baidu” 这个值可能存在。

这是为何呢?答案跟简单,由于随着增长的值愈来愈多,被置为 1 的 bit 位也会愈来愈多,这样某个值 “taobao” 即便没有被存储过,可是万一哈希函数返回的三个 bit 位都被其余值置位了 1 ,那么程序仍是会判断 “taobao” 这个值存在

 

支持删除么

目前咱们知道布隆过滤器能够支持 add 和 isExist 操做,那么 delete 操做能够么,答案是不能够,例如上图中的 bit 位 4 被两个值共同覆盖的话,一旦你删除其中一个值例如 “tencent” 而将其置位 0,那么下次判断另外一个值例如 “baidu” 是否存在的话,会直接返回 false,而实际上你并无删除它。

如何解决这个问题,答案是计数删除。可是计数删除须要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。这样的话,增长一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0

 

如何选择哈希函数个数和布隆过滤器长度

很显然,太小的布隆过滤器很快全部的 bit 位均为 1,那么查询任何值都会返回“可能存在”,起不到过滤的目的了。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。

另外,哈希函数的个数也须要权衡,个数越多则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低;可是若是太少的话,那咱们的误报率会变高。

 

 

k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误报率。

至于如何推导这个公式,我在知乎发布的文章有涉及,感兴趣能够看看,不感兴趣的话记住上面这个公式就好了。

最佳实践

常见的适用常见有,利用布隆过滤器减小磁盘 IO 或者网络请求,由于一旦一个值一定不存在的话,咱们能够不用进行后续昂贵的查询请求。

另外,既然你使用布隆过滤器来加速查找和判断是否存在,那么性能很低的哈希函数不是个好选择,推荐 MurmurHash、Fnv 这些。

 

memcache与redis的区别

redis和memecache的不一样在于[2]: 

一、存储方式: 

memecache 把数据所有存在内存之中,断电后会挂掉,数据不能超过内存大小 

redis有部份存在硬盘上,这样能保证数据的持久性,支持数据的持久化(笔者注:有快照和AOF日志两种持久化方式,在实际应用的时候,要特别注意配置文件快照参数,要不就颇有可能服务器频繁满载作dump)。 

二、数据支持类型: 

redis在数据支持上要比memecache多的多。 

三、使用底层模型不一样: 

新版本的redis直接本身构建了VM 机制 ,由于通常的系统调用系统函数的话,会浪费必定的时间去移动和请求。 

四、运行环境不一样: 

redis目前官方只支持LINUX 上去行,从而省去了对于其它系统的支持,这样的话能够更好的把精力用于本系统 环境上的优化,虽而后来微软有一个小组为其写了补丁。可是没有放到主干上

我的总结一下,有持久化需求或者对数据结构和处理有高级要求的应用,选择redis,其余简单的key/value存储,选择memcache。

 

zookeeper有什么功能

简单的说,zookeeper=文件系统+通知机制。

Zookeeper维护一个相似文件系统的数据结构:

                                                         

 

        每一个子目录项如 NameService 都被称做为 znode,和文件系统同样,咱们可以自由的增长、删除znode,在一个znode下增长、删除子znode,惟一的不一样在于znode是能够存储数据的。

有四种类型的znode:

一、PERSISTENT-持久化目录节点

客户端与zookeeper断开链接后,该节点依旧存在

二、 PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点

客户端与zookeeper断开链接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

三、EPHEMERAL-临时目录节点

客户端与zookeeper断开链接后,该节点被删除

四、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

客户端与zookeeper断开链接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

 

监听机制 

        客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增长删除)时,zookeeper会通知客户端。 

 

咱们能用zookeeper作什么

一、 命名服务

        这个彷佛最简单,在zookeeper的文件系统里建立一个目录,即有惟一的path。在咱们使用tborg没法肯定上游程序的部署机器时便可与下游程序约定好path,经过path即能互相探索发现,不见不散了。

 

二、 配置管理

        程序老是须要配置的,若是程序分散部署在多台机器上,要逐个改变配置就变得困难。好吧,如今把这些配置所有放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,而后全部相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每一个应用程序就会收到 Zookeeper 的通知,而后从 Zookeeper 获取新的配置信息应用到系统中就好。

 

三、 集群管理

所谓集群管理无在意两点:是否有机器退出和加入、选举master。

        对于第一点,全部机器约定在父目录GroupMembers下建立临时目录节点,而后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的链接断开,其所建立的临时目录节点被删除,全部其余机器都收到通知:某个兄弟目录被删除,因而,全部人都知道:它上船了。新机器加入 也是相似,全部机器收到通知:新兄弟目录加入,highcount又有了。

 

四、  分布式锁

        有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务能够分为两类,一个是保持独占,另外一个是控制时序

 

五、队列管理

两种类型的队列:

一、 同步队列,当一个队列的成员都聚齐时,这个队列才可用,不然一直等待全部成员到达。

二、队列按照 FIFO 方式进行入队和出队操做。

第一类,在约定目录下建立临时目录节点,监听节点数目是不是咱们要求的数目。

第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。     

 

zk选举算法如何进行

 

 Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫作Zab协议。Zab协议有两种模式,它们分 别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步之后,恢复模式就结束了。状态同步保证了leader和Server具备相同的系统状态。

        为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。全部的提议(proposal)都在被提出的时候加上 了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个 新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

每一个Server在工做过程当中有三种状态:

  • LOOKING:当前Server不知道leader是谁,正在搜寻
  • LEADING:当前Server即为选举出来的leader
  • FOLLOWING:leader已经选举出来,当前Server与之同步

 

选主流程

      当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式须要从新选举出一个新的leader,让全部的 Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:

        1 .选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;

        2 .选举线程首先向全部Server发起一次询问(包括本身);

        3 .选举线程收到回复后,验证是不是本身发起的询问(验证zxid是否一致),而后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(        id,zxid),并将这些信息存储到当次选举的投票记录表中;

        4.  收到全部Server回复之后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;

        5.  线程将当前zxid最大的Server设置为当前Server要推荐的Leader,若是此时获胜的Server得到n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置本身的状态,不然,继续这个过程,直到leader被选举出来。

    经过流程分析咱们能够得出:要使Leader得到多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.

    每一个Server启动后都会重复以上流程。在恢复模式下,若是是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并按期进行快照,方便在恢复时进行状态恢复。选主的具体流程图以下所示:

                                        

      fast paxos流程是在选举过程当中,某Server首先向全部Server提议本身要成为leader,当其它Server收到提议之后,解决epoch和 zxid的冲突,并接受对方的提议,而后向对方发送接受提议完成的消息,重复这个流程,最后必定能选举出Leader。其流程图以下所示:

                        

同步流程

选完leader之后,zk就进入状态同步过程。

        1. leader等待server链接;

        2 .Follower链接leader,将最大的zxid发送给leader;

        3 .Leader根据follower的zxid肯定同步点;

        4 .完成同步后通知follower 已经成为uptodate状态;

        5 .Follower收到uptodate消息后,又能够从新接受client的请求进行服务了。

流程图以下所示:

                                

相关文章
相关标签/搜索