现场填坑系列:mongodb 复制集跨机房同步网络问题探查

接到现场报告,客户MongoDB间数据延迟愈来愈大,有的已经超过2-3个小时,形成有些打到延迟mongodb上面的数据库请求没法反应数据库的最新更改。这个问题反复出如今高峰期尤为明显,持续近一月。算法

架构

客户为异地双机房架构,两地机房相隔上千千米,带宽250M,光纤,具体链路状况不明mongodb

               F5                              |                    F5数据库

             N中心                           |                   S中心windows

业务服务  ...  业务服务              |          业务服务 .... 业务服务缓存

mongodb4 ...  mongodb6   <----|-----   mongodb1(主) ... mongdb2服务器

 

全部数据库在一个复制集共6台(其中一台不参与选举),使用的是mongodb replicaSet 进行同步。网络

现象

S中心数据库反复产生延迟,其中一次rs.printSlaveReplicationInfo()查询集群状况显示以下,数据库4,5,6三台延迟(此处不是每次都是三台同时延迟,有时只是这三台中的两台或者一台出现延迟,可是1,2从不延迟),延迟时间最多达到2-3个小时,非高峰期能够恢复。架构

  • 客户在两个机房间经过ping命令发现南北网络有延迟现象。
  • 在发生延迟时,有时能够经过切换同步源的方式,暂时解决问题。

插入图app

分析

首先查看有问题的机器,发现4,5,6三台均在N中心,1,2均在S中心,而用rs.status查看,能够发现当延迟时,这三台都以1为同步源,也就是发生跨网络同步。tcp

因为三台出现同步的机器都在N中心,可猜想与链路有关。客户ping命令未显示延迟,说明ping的数据量可能不够或者问题是由某种条件触发的。

是否有可能同步带宽超过了链路限制,咱们和网络方面的人进行了沟通,获得的消息是咱们的应用使用的带宽没有达到上限。最高也就极限带宽的2/3左右。为确认带宽状况,咱们本身也对带宽进行了分析。

带宽使用分析

南北中心业务高峰期正常状况下带宽占用70Mb/s,也没有达到理论高度,并且正常状况下某些瞬时,带宽能够超过150Mb/s,也证实服务远远没有达到带宽上线。咱们进一步对产生延迟的状况下的带宽进行分析,发现了一个奇怪的状况

:在产生延迟的状况下,数据库用来同步的带宽远远不足60Mb/s ,只有不到15Mb/s。也就是说,数据库有大量堆积,产生延迟的时候,数据库同步反而变慢了

同时咱们监控了S中心内未延迟节点与通中心主节点同步时的带宽约为17Mb/s ,因为mongodb每台slave都是复制一样的数据,能够推知其余机器都应该按照这个速率进行同步。而延迟节点只有4.5Mb/s左右。

咱们又查看了延迟节点的监控,查看了延时节点从正常状态转入延迟状态的带宽状况,发现其使用带宽会在某种状况下发生骤降

 

究竟是什么致使这种情况呢?是mongodb自己的问题吗?

这种状况咱们仍是决定围绕核心现象来进行分析:这几台服务器和正常的服务器有什么不一样。咱们一一排查了机器配置,软件配置的问题,确保出问题的服务器和正常服务器没有原则不一样,同时也查了这几台服务器在延迟时的表现,发现延迟时,这几台mongo的指标远远没有到达瓶颈,因此惟一可疑的不一样仍是在网络上,即便ping没有发现问题,咱们仍是决定要进一步抓包。

抓包

由于抓包对性能有显著影响,为了抓出特征包,咱们选在节点开始延迟,而且延迟时间还在增大时进行抓包,抓包时间在1分钟之内。

抓包语句 tcpdump -i eth0 port xxx -w /home/tcpdump.cap

下面是咱们看到的状况(使用Wireshark)

网络中出现了大量的Dup ACK,这个说明了TCP出现了数据丢失致使了重传。

Dup ACK

TCP的流程是面向链接,会尽力保证数据的完整性,因此有失败重传机制,Dup ACK 就是这个机制的一部分。

每一个包都有一个Seq号和一个包长度,正常状况下,某一端全部发送的包的Seq号是连续的,好比

第一个包的Seq是1,长度是2,

则第二个包Seq=1+2=3,长度4,

第三个包的Seq=3+4,长度若干,

以此类推,当接收端收到这个包时会将这个包放到缓冲区,缓冲区里可能有不少从另外一端发来的包,他们必须能连续起来,接收端会向发送端发包时告知会带上我接收到的最后一个连续的包的Seq是多少,这个数据会放在ACK里传送。

上面注意:

  • 发送端和接收端是相对的,两边都遵循这个规则。
  • 不是每个包都ACK,这样开销太大。
  • 也不必定有专门用于ACK的包,事实上ACK包每每也多是对上一个或者几个包的回复,顺便就进行了ACK。

插入图

假如丢失了一个包会怎么样?接收端发现缓存里的包丢失了,然后面的包已经到了,就会触发上面的Dup ACK,告知我接收到的连续的数据的序号到哪里为止,也就是DupACK包的ACK。这个请求会反复发送,直到服务端发送缺失包(retransmit)。在收到缺失包前,后续的包即便收到也不会ack。这个是retransmit的流程。

上面的流程在dump中典型的例子用wireshark打开会是下面的样子:注意这里包括【TCP Previous segment not captured】【Dup ACK】 等内容都是wireshark的分析结果。TCP包中并不包含这些标签。

首先从端发现丢包【TCP Previous segment not captured】而后引起从端大量发送dup ack,直到主端重传经过TCP Fast Retransmition 或Retransmition 重传missing package,见下图。重传期间全部有缺失的包会暂存入buffer。

 

在wireshark中能够对重传的包进行过滤  tcp.analysis.retransmission 

过滤结果为32条,占所抓包的0.3%,这个统计能够看作是就是丢包的统计。然而因为这样的丢包,触发tcp进行反复沟通引发的混乱远远大于此,若是统计全部由此引发的dup Ack, Out of Order,Fast Retransmit,Transmit,window_update 等,能够看到这些处理丢包的请求占到了5.5%之多。

同时刚才提到发送端可能发送不少包,可是只是其中一个丢了。这些没有丢掉的包会放在一个缓冲区中,这个缓冲区叫作window,因为后续包不断到来,而失去的包没有补上,因此tcp不能向上层转发,因而就会更改window的大小,这个也是很是消耗资源的行为。

总结来讲:

从库的dump中,共抓包16.81秒10176个包,错误重传形成的dup ack和重传包达到562 占 5.5%;

主库(同步源)的dump中,共抓包12秒 3501个包,错误重传以及dup ack相关的包占到325,占比9.3%;

而同机房内部节点彻底未见丢包与重传,且在跨机房节点处于无延迟正常状态也未见丢包重传。

重传与流量降低间的关系

为了确保这个现象只在跨机房调用中出现,咱们也抓取了同机房同步,以及跨机房无延迟时的状况,这两种状况下均无上述问题。重传错误与流量的关系可见下图,折线为吞吐,柱形为error包数量,可见流量的重大转折均伴随有相关错误,下图也展示了window scaling的状况,展现出因为错误发生,windows size 的修改状况,可见6分钟左右发生了一次大的scaling,正对应了dump中的错误。

结论与解决方法

在丢包率0.3%的状况下,mongodb的replicaSet发生了比较严重的问题。表现为同步速率大幅降低,而后产生延迟。

客户网络状况比较复杂,链路是运营商链路,还有许多第三方厂商的设备,难以在短期内排查缘由,因此再发生同步时,咱们采用rs.syncFrom脚本切换同步源临时解决这个问题:即当脚本监测延迟>10分钟时,马上切换到另一个数据源。

此方法基于在产生延迟后,当即切换另一个数据源能够从新打开同步链路快速同步,瞬间同步时速能够到达160Mb/s,延时数据能很快消失。

可是在执行过程当中,出现过切换同时,mongodb因为大量写入而影响业务的状况,因此后来改成在非高峰先讲须要修改的节点改成hide节点再进行处理。

将来最终解决方案

解决网络延迟:这个是最直接的解决办法,毕竟同机房同步未见问题。

减小replicaSet的量:检查业务中的写入更新删除逻辑,减小生成量。具体分析和处理方法将另文描述。

使用mongoshake等第三方同步工具:因为还没有明晰重传为什么致使复制集处理速度降低,因此不使用复制集也可能能够解决这个问题。且复制集对源的选择有本身的算法,虽然能够短期的切换,可是更多时候是根据mongodb自身的算法进行选择,好比在本案中,三台N节点Mongo都到S节点同步,形成带宽乘以3倍,虽然能够手动制定其中两台从同节点一台复制,但mongodb仍是有可能自动根据本身的算法切换源。而使用第三方同步工具能够解决上面的两个问题。可是要检查第三方工具在0.3%网络丢包下的工做状况。

相关文章
相关标签/搜索