MongoDB集群卡死问题

时间:2022-05-30 00:45:24

年前搭了个MongoDB集群,跑得还算不错,但是有几次遇到过服务卡死的问题。处理起来已经得心应手了,拿来跟大家分享一下:

故障现象

业务查询缓慢,而且会有连接异常:

{ "serverUsed" : "/10.6.19.80:10013" , "errmsg" : "exception: could not run map command on all shards for ns tloc.fileprops and query { author: { $in: [ \"exception\" ] }, type: { $in: [ 0, 1 ] } } :: caused by :: socket exception [CONNECT_ERROR] for shard2/10.6.19.91:10016" , "code" : 11002 , "ok" : 0.0}
{ "serverUsed" : "/10.6.19.108:10013" , "ok" : 0.0 , "errmsg" : "MR post processing failed: { errmsg: \"exception: could not initialize cursor across all shards because : socket exception [SEND_ERROR] for 10.6.19.91:10016 @ shard2/10.6.19.91:10016\", code: 14827, ok: 0.0 }"}

当时各个Mongo分片、路由、配置服务器进程有在运行,而且查看路由服务的IO也不算高,内存、CPU也是可以接受的。但是业务查询却会卡死,导致服务不可用。

故障原因

能通过本地连接上mongo,切到业务db,通过“db.currentOp()”查看到执行的操作,发现操作数已经开始积累,呈阻塞状态。而且通过观察可以发现一般操作累积的都是同一个分片下的任务,估计是这个分片出现了问题,有几种可能性:

1、磁盘IO异常

2、任务参数不合理,查询确实很慢

总之,不可能因为一个分片问题,导致整个集群不可用。

故障恢复

如果是线上可用性,一般都会很急的,现在知道了原因,应立即恢复。这里有两种办法:

1、一个一个地用db.killOp("opid")去杀掉某个操作(mongo没有群杀,即使你重启了路由,那些操作还在配置服务器里存着),但是这个不大合理,因为它的增长阻塞很快,而且很可能你连mongo都登不上,整个服务都瘫痪掉了;

2、暴力重启分片,这个是目前我在使用的,也是比较快速有效的方法

具体重启服务,也不是所有服务器都要重启,只需要把引起阻塞的分片重启即可:

1、通过db.currentOp()或分片mongd日志确认可疑分片

2、直接上分片机器,kill掉mongod进程

3、再启动mongod进程

4、进入各个路由服务器,依次执行db.shutdownServer(),再启动mongos进程

此时,应用里那些阻塞的操作应该都没了,可以通过在路由服务上执行db.xxx.find()来确认是否集群可用。