2019-11-29

生產(chǎn)事故(MongoDB數(shù)據(jù)分布不均解決方案)

事故集合:

Shard replset_sh1 at replset_sh1/mongodb01:27001,mongodb02:27001

data : 2207.7GiB docs : 2112558418 chunks : 62935

estimated data per chunk : 35.92MiB

estimated docs per chunk : 33567

Shard replset_sh2 at replset_sh2/mongodb02:27002,mongodb03:27002

data : 2193.32GiB docs : 2088697495 chunks : 63267

estimated data per chunk : 35.49MiB

estimated docs per chunk : 33014

Shard replset_sh3 at replset_sh3/mongodb03:27003,mongodb04:27003

data : 5501.55GiB docs : 5470146991 chunks : 101582

estimated data per chunk : 55.45MiB

estimated docs per chunk : 53849

Shard replset_sh4 at replset_sh4/mongodb04:27004,mongodb05:27004

data : 2220.35GiB docs : 2121870478 chunks : 62831

estimated data per chunk : 36.18MiB

estimated docs per chunk : 33771

Shard replset_sh5 at replset_sh5/mongodb01:27005,mongodb05:27005

data : 2295.51GiB docs : 2188687470 chunks : 64778

estimated data per chunk : 36.28MiB

estimated docs per chunk : 33787

Shard replset_sh6 at replset_sh6/mongodb06:27006,mongodb07:27006

data : 212.64GiB docs : 203616005 chunks : 6822

estimated data per chunk : 31.91MiB

estimated docs per chunk : 29846

Shard replset_sh7 at replset_sh7/mongodb07:27007,mongodb08:27007

data : 93.86GiB docs : 91177954 chunks : 2989

estimated data per chunk : 32.15MiB

estimated docs per chunk : 30504

Shard replset_sh8 at replset_sh8/mongodb06:27008,mongodb08:27008

data : 194.38GiB docs : 188053173 chunks : 6168

estimated data per chunk : 32.27MiB

estimated docs per chunk : 30488

Totals

data : 14919.34GiB docs : 14464807984 chunks : 371372

Shard replset_sh1 contains 14.79% data, 14.6% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh2 contains 14.7% data, 14.43% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh3 contains 36.87% data, 37.81% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh4 contains 14.88% data, 14.66% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh5 contains 15.38% data, 15.13% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh6 contains 1.42% data, 1.4% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh7 contains 0.62% data, 0.63% docs in cluster, avg obj size on shard : 1KiB

Shard replset_sh8 contains 1.3% data, 1.3% docs in cluster, avg obj size on shard : 1KiB

可以很明顯可以看到我們這個集合的數(shù)據(jù)嚴重分布不均勻绝骚。

一共有8個分片禀挫,面對這個情況我首先想到的是手動拆分數(shù)據(jù)塊侨把,但這不是解決此問題的根本辦法生真。

? ? ? ? 造成此次生產(chǎn)事故的首要原因就是片鍵選擇上的問題短荐,由于片鍵選擇失誤笛谦,在數(shù)據(jù)量級不大的時候數(shù)據(jù)看起來還是很健康的型雳,但隨著數(shù)據(jù)量的暴漲奕锌,問題就慢慢浮出了水面倡勇,我們使用的組合片鍵并不是無規(guī)律的逞刷,片鍵內(nèi)容是線性增長的,這就導致了數(shù)據(jù)的不正常聚集妻熊。由于數(shù)據(jù)分布不均勻夸浅,我們有兩個分片的磁盤使用率接近80%,數(shù)據(jù)還在持續(xù)增長扔役,這個問題必須盡快解決帆喇。

涉及到此次事故的集合一共有三個,總數(shù)據(jù)量加起來接近30T亿胸,數(shù)據(jù)總量300億左右坯钦。

下面是我解決此問題的解決方案:

方案一:

第一步:創(chuàng)建一個新的分片表,片鍵我選擇_id做hashed分片侈玄,并提前分好了數(shù)據(jù)塊婉刀,降低在恢復期間頻繁切割數(shù)據(jù)造成的服務器壓力。


sh.shardCollection("loan_his.collection",{_id:"hashed"},false,{numInitialChunks:1024})

第二步:單獨連接各個分片將8個分片的數(shù)據(jù)全量備份:

nohup mongodump -u loan_his -p loan_his --authenticationDatabase loan_his? -h ${replset} --db loan_his --collection ${collectionName} --query '{"txdt": { $lte: "2019-07-09"} }' -o ${bak_dir} &>>? ${log} &

你可能會問為什么不連接mongos,因為我在連接mongos做數(shù)據(jù)備份時出現(xiàn)了以下異常:

2019-07-08T16:10:03.886+0800? ? Failed: error writing data for collection `loan_his.ods_cus_trad` to disk: error reading collection: operation was interrupted

可能是因為集合內(nèi)的數(shù)據(jù)壞塊吧拗馒,此異常信息是我備份了將近70%的數(shù)據(jù)后突然拋出的異常信息路星。

除了這個原因,單獨備份各個分片的數(shù)據(jù)后你能夠自由控制恢復數(shù)據(jù)的時間窗口诱桂,不會因為恢復單個數(shù)據(jù)文件時間較長洋丐,突發(fā)意外情況導致恢復中斷從頭再來的窘境。能夠根據(jù)服務器的狀態(tài)避開高峰期來進行數(shù)據(jù)恢復挥等。

備份期間我發(fā)現(xiàn)了有時候備份出來的總文檔數(shù)和 db.collection.getShardDistribution() 查看的文檔數(shù)不一致友绝,我還以為是備份期間出了問題,但我刪除當前備份文件后重新備份出來的文檔數(shù)還是和之前一樣肝劲。目前不知道是怎么回事迁客,懷疑是壞的數(shù)據(jù)塊引發(fā)的我問題郭宝,備份出來的數(shù)據(jù)一般會比原數(shù)據(jù)量多幾萬條數(shù)據(jù),有時候會少一些掷漱。

第三步:恢復數(shù)據(jù):

mongorestore -u loan_his -p loan_his --authenticationDatabase loan_his -h 10.0.156.9:27017 --db loan_his? --collection? ${collectionName_two}? /mongodb/${collectionName}/replset_sh2/loan_his/${collectionName}.bson? &>>? ${log}

在恢復數(shù)據(jù)前千萬要記得不要創(chuàng)建索引粘室!否則性能極差,速度非常非常慢卜范!在使用mongodump工具備份時衔统,在數(shù)據(jù)文件的同級目錄下會有一個 XXXXX.metadata.json 索引文件,默認會在數(shù)據(jù)恢復完畢后執(zhí)行創(chuàng)建索引的操作海雪。

此處有坑需要注意:因為備份出來的數(shù)據(jù)是由原表備份出來的锦爵,那這個索引文件也是原表的索引,由于原表我使用的是組合片鍵做的分片奥裸,所以在原表內(nèi)會存在一個由片鍵組成的組合索引险掀,并且不是后臺創(chuàng)建的組合索引!M逯妗樟氢!這意味著如果你使用此索引文件來給新表創(chuàng)建索引,會造成這個集群處于阻塞狀態(tài)创倔,無法響應任何操作N撕Α!直至索引創(chuàng)建完畢畦攘。所以你可以將這個索引文件備份到其它目錄以作參考霸妹,然后將原文件刪除就可以了,恢復數(shù)據(jù)時不會有其它的問題知押。

如果恢復期間出現(xiàn)了意外情況導致恢復失敗叹螟,比如節(jié)點宕機什么的,不需要擔心台盯,重新執(zhí)行恢復程序罢绽,數(shù)據(jù)文件不會重復增加,因為備份出來的數(shù)據(jù)文件包含mongodb自帶的 Objectld對象_id ,導入時静盅,如果已存在此ID,將不會插入數(shù)據(jù)良价。注意:在不同集合是允許出現(xiàn)相同ID的,所以在使用方案二恢復數(shù)據(jù)時蒿叠,新產(chǎn)生的數(shù)據(jù)不能通過新表A備份出來匯入新表C明垢,需要通過原始數(shù)據(jù)文件重新導入。

第四步:創(chuàng)建索引:

待所有數(shù)據(jù)恢復完畢后再創(chuàng)建索引市咽,一定要記得后臺創(chuàng)建H!施绎!你也可以將索引拆分溯革,一個一個的來贞绳。如果覺得此操作對業(yè)務影響較大,請看本文最后的解決方案致稀。

mongo 10.0.156.2:27017/loan_his -uloan_his -ploan_his -eval 'db.getSiblingDB("loan_his").runCommand({createIndexes: "collection",indexes: [{"v":2,"key":{"_id":1},"name":"_id_","ns":"loan_his.collection"},{"v":2,"key":{"opnode":1.0,"txdt":1.0,"acct":1.0,"crdno":1.0},"name":"opnode_1_txdt_1_acct_1_crdno_1","ns":"loan_his.collection"},{"v":2,"key":{"txdt":1.0,"opnode":1.0,"acct":1.0,"crdno":1.0,"pbknum":1.0},"name":"txdt_1_opnode_1_acct_1_crdno_1_pbknum_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"acct":1.0,"txdt":1.0,"opnode":1.0},"name":"acct_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"crdno":1.0,"txdt":1.0,"opnode":1.0},"name":"crdno_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true},{"v":2,"key":{"pbknum":1.0,"txdt":1.0,"opnode":1.0},"name":"pbknum_1_txdt_1_opnode_1","ns":"loan_his.collection","background":true}]})'

停止失控索引:

一旦你觸發(fā)一個索引冈闭,簡單的重啟服務并不能解決這個問題,因為MongoDB會繼續(xù)重啟前的建索引的工作豺裆。如果之前你運行后臺建索引任務拒秘,在服務重啟后它會變成前臺運行的任務。在這種情況下臭猜,重啟會讓問題變得更糟糕。MongoDB提供了選項“noIndexBuildRetry”押蚤,它會指示MongoDB重啟后不再繼續(xù)沒建完的索引蔑歌。如果不小心在前臺創(chuàng)建了索引導致集群不可用,可以使用--noIndexBuildRetry 參數(shù)重啟各個分片來停止索引的創(chuàng)建過程揽碘,只用重啟主節(jié)點就可以了次屠。如果是在后臺創(chuàng)建索引,重啟時記得加上--noIndexBuildRetry雳刺,否則重啟后創(chuàng)建索引的線程會重新被喚醒劫灶,并由后臺創(chuàng)建變?yōu)榍芭_創(chuàng)建,導致整個集群不可用掖桦。

mongod -f $CONFIGFILE --noIndexBuildRetry

此方案遷移期間不用通知業(yè)務系統(tǒng)做變更本昏,把數(shù)據(jù)遷移完畢后,通知業(yè)務系統(tǒng)將表名變更枪汪,弊端就是在你遷移的過程中數(shù)據(jù)還是會持續(xù)增長的涌穆,問題分片的磁盤容量會越來越少。

方案二:

為了避免在遷移期間數(shù)據(jù)仍在增長雀久,導致數(shù)據(jù)還沒遷移完畢磁盤就爆滿的情況宿稀,可以選擇停止往舊表B內(nèi)寫入數(shù)據(jù),創(chuàng)建一個健康的新表A赖捌,新的數(shù)據(jù)往新表A內(nèi)寫祝沸,具體的查詢方案需要應用系統(tǒng)的配合。然后將舊表B的數(shù)據(jù)遷移至新表C中越庇,最終將新表A的數(shù)據(jù)匯入新表C , 完成數(shù)據(jù)遷移罩锐。此次遷移數(shù)據(jù)耗時共9個月!T没摹唯欣!片鍵一定要慎重選擇,因為我們使用的MongoDB是3.4.7版本的搬味,不支持修改片鍵境氢,最新版本支持片鍵的修改蟀拷。

接下來介紹數(shù)據(jù)量較大時如何構(gòu)建索引--減少業(yè)務最少影響

在數(shù)據(jù)量較大或請求量較大,直接建立索引對性能有顯著影響時,可以利用復制集(數(shù)據(jù)量較大時一般為線上環(huán)境,使用復制集為必然選擇或者使用分片.)中部分機器宕機不影響復制集工作的特性,繼而建立索引。

(1)首先把 secondary server 停止萍聊,再注釋 --replSet 參數(shù)问芬,并且更改 MongoDB port 之后重新啟動 MongoDB,這時候 MongoDB 將進入 standalone 模式寿桨;

(2).在 standalone 模式下運行命令 ensureIndex 建立索引此衅,使用 foreground 方式運行也可以,建議使用background方式運行亭螟;

(3)建立索引完畢之后關(guān)閉 secondary server 按正常方式啟動;

4.根據(jù)上述 1~3 的步驟輪流為 secondary 建立索引挡鞍,最后把 primary server 臨時轉(zhuǎn)換為 secondary server,同樣按 1~3 的方法建立索引预烙,再把其轉(zhuǎn)換為 primary server墨微。

日志內(nèi)容大致如下:

2019-09-24T18:51:39.003+0800 I - ? ? ?? [conn33] ? Index Build: 838416900/876543270 95%

2019-09-24T20:10:08.360+0800 I INDEX ?? [conn33]? done building bottom layer, going to commit

2019-09-24T20:10:26.001+0800 I - ? ? ?? [conn33] ? Index: (2/3) BTree Bottom Up Progress: 11684400/876543270 1%

done building bottom layer, going to commit

?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扁掸,隨后出現(xiàn)的幾起案子翘县,更是在濱河造成了極大的恐慌,老刑警劉巖谴分,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锈麸,死亡現(xiàn)場離奇詭異,居然都是意外死亡牺蹄,警方通過查閱死者的電腦和手機忘伞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钞馁,“玉大人虑省,你說我怎么就攤上這事∩耍” “怎么了探颈?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長训措。 經(jīng)常有香客問我伪节,道長,這世上最難降的妖魔是什么绩鸣? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任怀大,我火速辦了婚禮,結(jié)果婚禮上呀闻,老公的妹妹穿的比我還像新娘化借。我一直安慰自己,他們只是感情好捡多,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布蓖康。 她就那樣靜靜地躺著铐炫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蒜焊。 梳的紋絲不亂的頭發(fā)上倒信,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音泳梆,去河邊找鬼鳖悠。 笑死,一個胖子當著我的面吹牛优妙,可吹牛的內(nèi)容都是我干的乘综。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼鳞溉,長吁一口氣:“原來是場噩夢啊……” “哼瘾带!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起熟菲,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朴恳,沒想到半個月后抄罕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡于颖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年呆贿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片森渐。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡做入,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出同衣,到底是詐尸還是另有隱情竟块,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布耐齐,位于F島的核電站浪秘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏埠况。R本人自食惡果不足惜耸携,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辕翰。 院中可真熱鬧夺衍,春花似錦、人聲如沸喜命。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尝胆,卻和暖如春丧裁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工宏邮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巧婶,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓缓呛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杭隙。 傳聞我的和親對象是個殘疾皇子哟绊,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • [toc] # golang內(nèi)置類型的底層數(shù)據(jù)結(jié)構(gòu) ## slice切片 ```go //[]int16 type...
    荊州關(guān)二爺閱讀 524評論 0 50
  • Java 在new 一個對象的時候,會先查看對象所屬的類有沒有被加載到內(nèi)存痰憎,如果沒有的話票髓,就會先通過類的全限定名來...
    常亞星閱讀 261評論 0 0
  • 什么是多態(tài) 多態(tài)是 C++ 編程時的一種特性,多態(tài)性即是對一個接口的多種實現(xiàn)铣耘,多態(tài)可以分為 靜態(tài)多態(tài)和動態(tài)多態(tài)洽沟,所...
    雪上霜閱讀 186評論 0 0
  • 今天是什么日子——十一月的倒數(shù)第二天 起床:七點四十 就寢:十二點 天氣:陰 心情:normal 紀念日:無 任務...
    星河pluto閱讀 46評論 0 0
  • 搖曳的微光里醒來 膚色澄澈而美好 套上風衣 穿過凌晨三點半被白露沾濕的曠野 赴一場五點鐘開席的盛宴 令人費解的異鄉(xiāng)...
    李飄零閱讀 220評論 0 1