Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


Mongodb
特定场景性能数十倍提升优化实践
(
记一次
mongodb
核心集群雪崩故障
)



关于作者


滴滴出行技术专家,现任OPPO
文档数据库
mongodb
负责人,负责
oppo
千万级峰值
TPS/
十万亿级数据量文档数据库
mongodb
内核研发及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。
Github
账号地址
:


https://github.com/y123456yz


1.
问题背景


某核心JAVA
长连接服务使用
mongodb
作为主要存储,客户端数百台机器连接同一
mongodb
集群,短期内出现多次性能抖动问题,此外,还出现一次“雪崩”故障,同时流量瞬间跌零,无法自动恢复。本文分析这两次故障的根本原因,包括客户端配置使用不合理、
mongodb
内核链接认证不合理、代理配置不全等一系列问题,最终经过多方努力确定问题根源。


该集群有十来个业务接口访问,每个接口部署在数十台业务服务器上面,访问该mongodb
机器的客户端总数超过数百台,部分请求一次拉取数十行甚至百余行数据。


该集群为2
机房同城多活集群
(
选举节不消耗太多资源,异地的第三机房来部署选举节点
)
,架构图如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


从上图可以看出,为了实现多活,在每个机房都部署有对应代理,对应机房客户端链接对应机房的mongos
代理,每个机房多个代理。代理层部署
IP:PORT
地址列表
(
注意:不是真实
IP
地址
)
如下:

A
机房代理地址列表:
1.1.1.1:111,2.2.2.2:1111,3.3.3.3:1111

B
机房代理地址列表:
4.4.4.4:1111,4.4.4.4:2222

A
机房三个代理部署在三台不同物理机,
B
机房
2
个代理部署在同一台物理机。此外,
A
机房和
B
机房为同城机房,跨机房访问时延可以忽略。


集群存储层和config server
都采用同样的架构:
A
机房
(1
主节点
+1
从节点
) + B
机房
(2
从节点
)+C
机房
(1
个选举节点
arbiter)
,即
2(
数据节点
)+2(
数据节点
)+1(
选举节点
)
模式。


该机房多活架构可以保证任一机房挂了,对另一机房的业务无影响,具体机房多活原理如下:

1. 

如果A
机房挂掉,由于代理是无状态节点,
A
机房挂掉不会影响
B
机房的代理。

2. 

如果A
机房挂掉,同时主节点在
A
机房,这时候
B
机房的
2
个数据节点和
C
机房的选举节点一共三个节点,可以保证新选举需要大于一半以上节点这个条件,于是
B
机房的数据节点会在短时间内选举出一个新的主节点,这样整个存储层访问不受任何影响。


本文重点分析如下6
个疑问点:

1. 


为什么突发流量业务会抖动?

2. 


为什么数据节点没有任何慢日志,但是代理负载缺100%

3. 


为何mongos
代理引起数小时的“雪崩”,并且长时间不可恢复?

4. 


为何一个机房代理抖动,对应机房业务切到另一个机房后,还是抖动?

5. 


为何异常时候抓包分析,客户端频繁建链断链,并且同一个链接建链到断链间隔很短?

6. 


理论上代理就是七层转发,消耗资源更少,相比mongod
存储应该更快,为何
mongod
存储节点无任何抖动,
mongos
代理缺有抖动?


2.
故障过程


2.1
业务偶尔流量高峰,业务抖动?


该集群一段时间内有多次短暂的抖动,当A
机房客户端抖动后,发现
A
机房对应代理负载很高,于是切换
A
机房访问
B
机房代理,但是切换后
B
机房代理同样抖动,也就是多活切换没有作用,具体过程分析如下。


2.1.1
存储节点慢日志分析


首先,分析该集群所有mongod
存储节点系统
CPU

MEM

IO

load
等监控信息,发现一切正常,于是分析每个
mongod
节点慢日志
(
由于该集群对时延敏感,因此慢日志调整为
30ms)
,分析结果如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


从上图可以看出,存储节点在业务抖动的时候没有任何慢日志,因此可以判断存储节点一切正常,业务抖动和mongod
存储节点无关。


2.1.2 Mongos
代理分析


存储节点没有任何问题,因此开始排查mongos
代理节点。由于历史原因,该集群部署在其他平台,该平台对
QPS
、时延等监控不是很全,造成早期抖动的时候监控没有及时发现。抖动后,迁移该平台集群到
oppo
自研的新管控平台,新平台有详细的监控信息,迁移后
QPS
监控曲线如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


每个流量徒增时间点,对应业务监控都有一波超时或者抖动,如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


分析对应代理mongos
日志,发现如下现象:抖动时间点
mongos.log
日志有大量的建链接和断链接的过程,如下图所示:



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

   
从上图可以看出,一秒钟内有几千个链接建立,同时有几千个链接断开,此外抓包发现很多链接短期内即断开链接,现象如下(
断链时间

建链时间
=51ms,
部分
100

ms
断开
)

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

    
对应抓包如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


此外,该机器代理上客户端链接低峰期都很高,甚至超过正常的QPS
值,
QPS
大约
7000-8000
,但是
conn
链接缺高达
13000

mongostat
获取到监控信息如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


2.1.3
代理机器负载分析


每次突发流量的时候,代理负载很高,通过部署脚本定期采样,抖动时间点对应监控图如下图所示:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

     
从上图可以看出,每次流量高峰的时候CPU
负载都非常的高,而且是
sy%
负载,
us%
负载很低,同时
Load
甚至高达好几百,偶尔甚至过千。


2.1.4
抖动分析总结

  
从上面的分析可以看出,某些时间点业务有突发流量引起系统负载很高。



根因真的是因为突发流量吗?其实不然,请看后续分析,这其实是一个错误结论。没过几天,同一个集群雪崩了。


  


于是业务梳理突发流量对应接口,梳理出来后下掉了该接口,QPS
监控曲线如下:



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


为了减少业务抖动,因此下掉了突发流量接口,此后几个小时业务不再抖动。当下掉突发流量接口后,我们还做了如下几件事情:

1. 

由于没找到mongos
负载
100%
真正原因,于是每个机房扩容
mongs
代理,保持每个机房
4
个代理,同时保证所有代理在不同服务器,通过分流来尽量减少代理负载。

2. 

通知A
机房和
B
机房的业务配置上所有的
8
个代理,不再是每个机房只配置对应机房的代理
(
因为第一次业务抖动后,我们分析
mongodb

java sdk
,确定
sdk
均衡策略会自动剔除请求时延高的代理,下次如果某个代理再出问题,也会被自动剔除
)

3. 

通知业务把所有客户端超时时间提高到500ms

 
但是,



心里始终有很多疑惑和悬念,主要在以下几个点:

1. 

存储节点4
个,代理节点
5
个,存储节点无任何抖动 ,反而七层转发的代理负载高?

2. 

为何抓包发现很多新连接几十ms
或者一百多
ms
后就断开连接了?频繁建链断链?

3. 

为何代理QPS
只有几万,这时代理
CPU
消耗就非常高,而且全是
sy%
系统负载? 以我多年中间件代理研发经验,代理消耗的资源很少才对,而且
CPU
只会消耗
us%
,而不是
sy%
消耗。


2.2
同一个业务几天后





雪崩





  


好景不长,业务下掉突发流量的接口没过几天,更严重的故障出现了,机房B
的业务流量在某一时刻直接跌
0
了,不是简单的抖动问题,而是业务直接流量跌
0
,系统
sy%
负载
100%
,业务几乎
100%
超时重连。


2.2.1
机器系统监控分析


机器CPU
和系统负载监控如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


从上图可以看出,几乎和前面的突发流量引起的系统负载过高现象一致,业务CPU sy%
负载
100%

load
很高。登陆机器获取
top
信息,现象和监控一致。

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

 
同一时刻对应网络监控如下:



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


磁盘IO
监控如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


从上面的系统监控分析可以看出,出问题的时间段,系统CPU sy%

load
负载都很高,网络读写流量几乎跌
0
,磁盘
IO
一切正常,可以看出整个过程几乎和之前突发流量引起的抖动问题完全一致。


2.2.2
业务如何恢复

  
第一次突发流量引起的抖动问题后,我们扩容所有的代理到8
个,同时通知业务把所有业务接口配置上所有代理。由于业务接口众多,最终
B
机房的业务没有配置全部代理,只配置了原先的两个处于同一台物理机的代理
(4.4.4.4:1111,4.4.4.4:2222)
,最终触发
mongodb
的一个性能瓶颈
(
详见后面分析
)
,引起了整个
mongodb
集群



雪崩


最终,业务通过重启服务,同时把B
机房的
8
个代理同时配置上,问题得以解决。


2.2.3 mongos
代理实例监控分析


分析该时间段代理日志,可以看出和2.1
同样得现象,大量的新键连接,同时新连接在几十
ms
、一百多
ms
后又关闭连接。整个现象和之前分析一致,这里不在统计分析对应日志。


此外,分析当时的代理QPS
监控,正常
query
读请求的
QPS
访问曲线如下,故障时间段
QPS
几乎跌零雪崩了:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

Command
统计监控曲线如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

   
从上面的统计可以看出,当该代理节点的流量故障时间点有一波尖刺,同时该时间点的command
统计瞬间飙涨到
22000(
实际可能更高,因为我们监控采样周期
30s,
这里只是平均值
)
,也就是瞬间有
2.2
万个连接瞬间进来了。
Command
统计实际上是
db.ismaster()
统计,客户端
connect
服务端成功后的第一个报文就是
ismaster
报文,服务端执行
db.ismaster()
后应答客户端,客户端收到后开始正式的
sasl
认证流程。


正常客户端访问流程如下:

1. 

客户端发起与mongos
的链接

2. 
Mongos
服务端
accept
接收链接后,链接建立成功

3. 

客户端发送db.isMaster()
命令给服务端

4. 

服务端应答isMaster
给客户端

5. 

客户端发起与mongos
代理的
sasl
认证
(
多次和
mongos
交互
)

6. 

客户端发起正常的find()
流程


客户端SDK
链接建立成功后发送
db.isMaster()
给服务端的目的是为了负载均衡策略和判断节点是什么类型,保证客户端快速感知到访问时延高的代理,从而快速剔除往返时延高的节点,同时确定访问的节点类型。


此外,通过提前部署的脚本,
该脚本在系统负载高的时候自动抓包,从抓包分析结果如下图所示:



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

 
上图时序分析如下:

1. 
 11:21:59.506174
链接建立成功

2. 
 11:21:59.506254
客户端发送
db.IsMaster()
到服务端

3. 
 11:21:59.656479
客户端发送
FIN
断链请求

4. 
 11:21:59.674717
服务端发送
db.IsMaster()
应答给客户端

5. 
 11:21:59.675480
客户端直接
RST

  
3
和第
1
个报文之间相差大约
150ms
,最后和业务确定该客户端
IP
对应的超时时间配置,确定就是
150ms
。此外,其他抓包中有类似
40ms

100ms
等超时配置,通过对应客户端和业务确认,确定对应客户端业务接口超时时间配置的就是
40ms

100ms
等。因此,结合抓包和客户端配置,可以确定当代理超过指定超时时间还没有给客户端
db.isMaster()
返回值,则客户端立马超时,超时后立马发起重连请求。

 



总结:


通过抓包和mongos
日志分析,可以确定链接建立后快速断开的原因是:客户端访问代理的第一个请求
db.isMaster()
超时了,因此引起客户端重连。重连后又开始获取
db.isMaster()
请求,由于负载
CPU 100%,
很高,每次重连后的请求都会超时。其中配置超时时间为
500ms
的客户端,由于
db.isMaster()
不会超时,因此后续会走
sasl
认证流程。

 

    
因此可以看出,系统负载高和反复的建链断链有关,某一时刻客户端大量建立链接(2.2W)
引起负载高,又因为客户端超时时间配置不一,超时时间配置得比较大得客户端最终会进入
sasl
流程,从内核态获取随机数,引起
sy%
负载高,
sy%
负载高又引起客户端超时,这样整个访问过程就成为一个“死循环”,最终引起
mongos
代理雪崩。


 


2.3
线下模拟故障


到这里,我们已经大概确定了问题原因,但是为什么故障突发时间点那一瞬间2
万个请求就会引起
sy%
负载
100%
呢,理论上一秒钟几万个链接不会引起如此严重的问题,毕竟我们机器有
40

CPU
。因此,分析反复建链断链为何引起系统
sy%
负载
100%
就成为了本故障的关键点。


2.3.1
模拟故障过程

  
模拟频繁建链断链故障步骤如下:

1. 

修改mongos
内核代码,所有请求全部延时
600ms

2. 

同一台机器起两个同样的mongos
,通过端口区分

3. 

客户端启用6000
个并发链接,超时时间
500ms

  
通过上面的操作,可以保证所有请求超时,超时后客户端又会立马开始重新建链,再次建链后访问mongodb
还会超时,这样就模拟了反复建链断链的过程。此外,为了保证和雪崩故障环境一致,把
2

mongos
代理部署在同一台物理机。

 


2.3.2
故障模拟测试结果


为了保证和故障的mongos
代理硬件环境一致,因此选择故障同样类型的服务器,并且操作系统版本一样
(2.6.32-642.el6.x86_64)
,程序都跑起来后,问题立马浮现:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

   
由于出故障的服务器操作系统版本linux-2.6
过低,因此怀疑可能和操作系统版本有问题,因此升级同一类型的一台物理机到
linux-3.10
版本,测试结果如下:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)


从上图可以看出,客户端6000
并发反复重连,服务端压力正常,所有
CPU
消耗在
us%

sy%
消耗很低。用户
CPU
消耗
3

CPU
,内核态
CPU
消耗几乎为
0
,这是我们期待的正常结果,因此觉得该问题可能和操作系统版本有问题。


为了验证更高并反复建链断链在Linux-3.10
内核版本是否有
2.6
版本同样的
sy%
内核态
CPU
消耗高的问题,因此把并发从
6000
提升到
30000
,验证结果如下:



测试结果:


通过修改mongodb
内核版本故意让客户端超时反复建链断链,在
linux-2.6
版本中,
1500
以上的并发反复建链断链系统
CPU sy% 100%
的问题即可浮现。但是,在
Linux-3.10
版本中,并发到
10000
后,
sy%
负载逐步增加,并发越高
sy%
负载越高。



总结:

linux-2.6
系统中,
mongodb
只要每秒有几千的反复建链断链,系统
sy%
负载就会接近
100%

Linux-3.10
,并发
20000
反复建链断链的时候,
sy%
负载可以达到
30%
,随着客户端并发增加,
sy%
负载也相应的增加。
Linux-3.10
版本相比
2.6
版本针对反复建链断链的场景有很大的性能改善,但是不能解决根本问题。


2.4
客户端反复建链断链引起
sy% 100%
根因


为了分析%sy
系统负载高的原因,安装
perf
获取系统
top
信息,发现所有
CPU
消耗在如下接口:

Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

    
perf
分析可以看出,
cpu
消耗在
_spin_lock_irqsave
函数,继续分析内核态调用栈,得到如下堆栈信息:

    
– 89.81% 89.81% [kernel] [k] _spin_lock_irqsave ▒



    
– _spin_lock_irqsave
 ▒



    
– mix_pool_bytes_extract ▒



    
– extract_buf ▒



    
extract_entropy_user ▒



    
urandom_read
 ▒



    
vfs_read ▒



    
sys_read ▒



    
system_call_fastpath ▒



    
0xe82d


上面的堆栈信息说明,mongodb
在读取
 /dev/urandom
,并且由于多个线程同时读取该文件,导致消耗在一把
spinlock
上。


到这里问题进一步明朗了,故障root case
不是每秒几万的连接数导致
sys
过高引起。根本原因是每个
mongo
客户端的新链接会导致
mongodb
后端新建一个线程,该线程在某种情况下会调用
urandom_read
去读取随机数
/dev/urandom
,并且由于多个线程同时读取,导致内核态消耗在一把
spinlock
锁上,出现
cpu
高的现象。


2.5 mongodb
内核随机数优化


2.5.1 mongodb
内核源码定位分析


上面的分析已经确定,问题根源是mongodb
内核多个线程读取
/dev/urandom
随机数引起,走读
mongodb
内核代码,发现读取该文件的地方如下:



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)





上面是生成随机数的核心代码,每次获取随机数都会读取


/dev/urandom


系统文件,所以只要找到使用该接口的地方即可即可分析出问题。


继续走读代码,发现主要在如下地方:

//
服务端收到客户端
sasl
认证的第一个报文后的处理,这里会生成随机数

//
如果是
mongos
,这里就是接收客户端
sasl
认证的第一个报文的处理流程

Sasl_scramsha1_server_conversation::_firstStep(…) {

    … …

    unique_ptr sr(SecureRandom::create());

    binaryNonce[0] = sr->nextInt64();

    binaryNonce[1] = sr->nextInt64();

    binaryNonce[2] = sr->nextInt64();

    … …

}

//mongos
相比
mongod
存储节点就是客户端,
mongos
作为客户端也需要生成随机数

SaslSCRAMSHA1ClientConversation::_firstStep(…) {

    … …

    unique_ptr sr(SecureRandom::create());

    binaryNonce[0] = sr->nextInt64();

    binaryNonce[1] = sr->nextInt64();

    binaryNonce[2] = sr->nextInt64();

    … …

}


2.5.2 mongodb
内核源码随机数优化


2.5.1
分析可以看出,
mongos
处理客户端新连接
sasl
认证过程都会通过

“/dev/urandom”

生成随机数,从而引起系统sy% CPU
过高,我们如何优化随机数算法就是解决本问题的关键。


继续分析mongodb
内核源码,发现使用随机数的地方很多,其中有部分随机数通过用户态算法生成,因此我们可以采用同样方法,在用户态生成随机数,用户态随机数生成核心算法如下:

    class PseudoRandom {

    … …

    uint32_t _x;

    uint32_t _y;

    uint32_t _z;

    uint32_t _w;

}



Mongodb特定场景性能数十倍提升优化实践(记一次mongodb核心集群雪崩故障)

  
该算法可以保证产生的数据随机分布,该算法原理详见:

   


http://en.wikipedia.org/wiki/Xorshift

  
也可以查看如下git
地址获取算法实现:

   


mongodb
随机数生成算法注释

  


总结:


通过优化sasl
认证的随机数生成算法为用户态算法后,
CPU sy% 100%
的问题得以解决,



同时代理性能在短链接场景下有了数倍/
数十倍的性能提升



3.


问题总结及疑问解答


从上面的分析可以看出,该故障由多种因素连环触发引起,包括客户端配置使用不当、mongodb
服务端内核极端情况异常缺陷、监控不全等。总结如下:

1. 

客户端配置不统一,同一个集群多个业务接口配置千奇百怪,超时配置、链接配置各不相同,增加了抓包排查故障的难度,超时时间设置太小容易引起反复重连。

2. 

客户端需要配全所有mongos
代理,这样当一个代理故障的时候,客户端
SDK
默认会剔除该故障代理节点,从而可以保证业务影响最小,就不会存在单点问题。

3. 

同一集群多个业务接口应该使用同一配置中心统一配置,避免配置不统一。

4. 
Mongodb
内核的新连接随机算法存在严重缺陷,在极端情况下引起严重性能抖动,甚至业务“雪崩”。


分析到这里,我们可以回答第1
章节的
6
个疑问点了,如下:



为什么突发流量业务会抖动?


答:由于业务是java
业务,采用链接池方式链接
mongos
代理,当有突发流量的时候,链接池会增加链接数来提升访问
mongodb
的性能,这时候客户端就会新增链接,由于客户端众多,造成可能瞬间会有大量新连接和
mongos
建链。链接建立成功后开始做
sasl
认证,由于认证的第一步需要生成随机数,就需要访问操作系统
“/dev/urandom”
文件。又因为
mongos
代理模型是默认一个链接一个线程,所以会造成瞬间多个线程访问该文件,进而引起内核态
sy%
负载过高。



为何mongos
代理引起“雪崩”,流量为何跌零不可用?


答:原因客户端某一时刻可能因为流量突然有增加,链接池中链接数不够用,于是增加和mongos
代理的链接,由于是老集群,代理还是默认的一个链接一个线程模型,这样瞬间就会有大量链接,每个链接建立成功后,就开始
sasl
认证,认证的第一步服务端需要产生随机数,
mongos
服务端通过读取

“/dev/urandom”

获取随机数,由于多个线程同时读取该文件触发内核态spinlock

CPU sy% 100%
问题。由于
sy%
系统负载过高,由于客户端超时时间设置过小,进一步引起客户端访问超时,超时后重连,重连后又进入
sasl
认证,又加剧了读取

“/dev/urandom”

文件,如此反复循环持续。


此外,第一次业务抖动后,服务端扩容了8

mongos
代理,但是客户端没有修改,造成
B
机房业务配置的
2
个代理在同一台服务器,无法利用
mongo java sdk
的自动剔除负载高节点这一策略,所以最终造成



雪崩



为什么数据节点没有任何慢日志,但是代理负载却CPU sy% 100%


答:由于客户端java
程序直接访问的是
mongos
代理,所以大量链接只发生在客户端和
mongos
之间,同时由于客户端超时时间设置太短
(
有接口设置位几十
ms
,有的接口设置位一百多
ms
,有的接口设置位
500ms)
,就造成在流量峰值的时候引起连锁反应
(
突发流量系统负载高引起客户端快速超时,超时后快速重连,进一步引起超时,无限死循环
)

Mongos

mongod
之间也是链接池模型,但是
mongos
作为客户端访问
mongod
存储节点的超时很长,默认都是秒级别,所以不会引起反复超时建链断链。



为何A
机房代理抖动的时候,
A
机房业务切到
B
机房后,还是抖动?


答:当A
机房业务抖动,业务切换到
B
机房的时候,客户端需要重新和服务端建立链接认证,又会触发大量反复建链断链和读取随机数

“/dev/urandom”

的流程,所以最终造成机房多活失败。



为何异常时候抓包分析,客户端频繁建链断链,并且同一个链接建链到断链间隔很短?


答:频繁建链断链的根本原因是系统sy%
负载高,客户端极短时间内建立链接后又端口的原因是客户端配置超时时间太短。



理论上代理就是七层转发,消耗资源更少,相比mongod
存储应该更快,为何
mongod
存储节点无任何抖动,
mongos
代理却有严重抖动?


答:由于采用分片架构,所有mongod
存储节点前面都有一层
mongos
代理,
mongos
代理作为
mongod
存储节点的客户端,超时时间默认秒级,不会出现超时现象,也就不会出现频繁的建链断链过程。



如果mongodb
集群采用普通复制集模式,客户端频繁建链断链是否可能引起
mongod
存储节点同样的





雪崩






  


答:会。如果客户端过多,操作系统内核版本过低,同时超时时间配置过段,直接访问复制集的mongod
存储节点,由于客户端和存储节点的认证过程和与
mongos
代理的认证过程一样,所以还是会触发引起频繁读取
“/dev/urandom”
文件,引起
CPU sy%
负载过高,极端情况下引起雪崩。

4. 




雪崩





解决办法


从上面的一系列分析,问题在于客户端配置不合理,加上mongodb
内核认证过程读取随机数在极端情况下存在缺陷,最终造成雪崩。如果没有
mongodb
内核研发能力,可以通过规范化客户端配置来避免该问题。当然,如果客户端配置规范化,同时
mongodb
内核层面解决极端情况下的随机数读取问题,这样问题可以得到彻底解决。


4.1 JAVA SDK
客户端配置规范化


在业务接口很多,客户端机器很多的业务场景,客户端配置一定要做到如下几点:

1. 

超时时间设置为秒级,避免超时时间设置过端引起反复的建链断链。

2. 

客户端需要配置所有mongos
代理地址,不能配置单点,否则流量到一个
mongos
很容易引起瞬间流量峰值的建链认证。

3. 

增加mongos
代理数量,这样可以分流,保证同一时刻每个代理的新键链接尽可能的少,客户端在多代理配置时,默认是均衡流量分发的,如果某个代理负载高,客户端会自动剔除。

    


如果没有mongodb
内核源码研发能力,可以参考该客户端配置方法,同时淘汰
linux-2.6
版本内核,采用
linux-3.10
或者更高版本内核,基本上可以规避踩同样类型的坑。


4.2 mongodb
内核源码优化
(
摈弃内核态获取随机数,选择用户态随机数算法
)

  
详见2.5.2
章节。


4.3 PHP
短链接业务,如何规避踩坑

  
由于PHP
业务属于短链接业务,如果流量很高,不可避免的要频繁建链断链,也就会走
sasl
认证流程,最终多线程频繁读取
“/dev/urandom”
文件,很容易引起前面的问题。这种情况,可以采用
4.1 java
客户端类似的规范,同时不要使用低版本的
Linux
内核,采用
3.x
以上内核版本,就可以规避该问题的存在。


5. Mongodb
内核源码设计与实现分析


本文相关的Mongodb线程模型及随机数算法实现相关源码分析如下:


mongodb动态线程模型源码设计与实现分析


mongodb一个链接一个线程模型源码设计与实现分析


mongodb内核态及用户态随机数算法实现分析

 







来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69984922/viewspace-2727671/,如需转载,请注明出处,否则将追究法律责任。

本文由 @崔任远[Vip] 发布于 职涯宝 ,未经作者许可,禁止转载,欢迎您分享文章

发表评论

登录后才能评论
小程序
小程序
微信客服
微信客服
QQ客服 建站服务
分享本页
返回顶部