一年前搭了個MongoDB集羣,跑得還算不錯,可是有幾回遇到過服務卡死的問題。處理起來已經駕輕就熟了,拿來跟你們分享一下:
html
故障現象:服務器
業務查詢緩慢,並且會有鏈接異常:socket
{ "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也是能夠接受的。可是業務查詢卻會卡死,致使服務不可用。post
故障緣由:spa
能經過本地鏈接上mongo,切到業務db,經過「db.currentOp()」查看到執行的操做,發現操做數已經開始積累,呈阻塞狀態。並且經過觀察能夠發現通常操做累積的都是同一個分片下的任務,估計是這個分片出現了問題,有幾種可能性:日誌
一、磁盤IO異常code
二、任務參數不合理,查詢確實很慢server
總之,不可能由於一個分片問題,致使整個集羣不可用。htm
故障恢復:blog
若是是線上可用性,通常都會很急的,如今知道了緣由,應當即恢復。這裏有兩種辦法:
一、一個一個地用db.killOp("opid")去殺掉某個操做(mongo沒有羣殺,即便你重啓了路由,那些操做還在配置服務器裏存着),可是這個不大合理,由於它的增加阻塞很快,並且極可能你連mongo都登不上,整個服務都癱瘓掉了;
二、暴力重啓分片,這個是目前我在使用的,也是比較快速有效的方法
具體重啓服務,也不是全部服務器都要重啓,只須要把引發阻塞的分片重啓便可:
一、經過db.currentOp()或分片mongd日誌確承認疑分片
二、直接上分片機器,kill掉mongod進程
三、再啓動mongod進程
四、等待1分鐘左右,路由服務器恢復正常
此時,應用裏那些阻塞的操做應該都沒了,能夠經過在路由服務上執行db.xxx.find()來確認是否集羣可用。