MongoDB超大塊數(shù)據(jù)問題解決
引言
最近項目在使用MongoDB作為圖片和文檔的存儲數(shù)據(jù)庫,為啥不直接存MySQL里,還要搭個MongoDB集群,麻不麻煩?
讓我們一起,一探究竟,繼續(xù)學(xué)習(xí)解決MongoDB超大塊數(shù)據(jù)問題,實現(xiàn)快速入門,豐富個人簡歷,提高面試level,給自己增加一點談資,秒變面試小達人,BAT不是夢。
一、MongoDB服務(wù)器管理
1、添加服務(wù)器
可以在任何時間添加mongos進程,只要確保,它們的 --configdb選項指定了正確的配置服務(wù)器副本集,并且客戶端可以立即與其建立連接。
2、修改分片中的服務(wù)器
要修改一個分片的成員,需要直接連接到該分片的主節(jié)點,并重新配置副本集。集群配置會檢測到變更并自動更新 config.shards。
3、刪除分片
一般情況下,不應(yīng)該從集群中刪除分片,會給系統(tǒng)帶來不必要的壓力。
刪除分片時,要確保均衡器的打開狀態(tài)。
均衡器的作用是把要刪除分片上的所有數(shù)據(jù)移動到其它分片,這個過程稱為排空。可以通過 removeShard命令執(zhí)行排空操作。
二、均衡器
可以通過 sh.setBalancerState(false)關(guān)閉均衡器。關(guān)閉均衡器不會將正在進行的過程停止,也就是說遷移過程不會立即停止。
通過db.locks.find({"_id","balancer"})["state"]查看均衡器是否關(guān)閉。0表示均衡器已關(guān)閉。
均衡過程會增加系統(tǒng)的負載,目標(biāo)分片必須查詢源分片的所有文檔,并將文檔插入目標(biāo)分片的塊中,然后源分片必須刪除這些文檔。
數(shù)據(jù)遷移是很消耗性能的,此時可以在config.settings集合中為均衡過程指定一個時間窗口。將其指定在一個閑暇時間執(zhí)行。
如果設(shè)置了均衡窗口,應(yīng)該對其進行監(jiān)控,確保mongos能夠在所分配的時間內(nèi)保持集群的均衡。
均衡器使用塊的數(shù)量而不是數(shù)據(jù)的大小作為度量。移動一個塊被稱為遷移,這是MongoDB平衡數(shù)據(jù)的方式??赡軙嬖谝粋€大塊的分片稱為許多小分片遷移的目標(biāo)。
三、修改塊的大小
一個塊可以存放數(shù)百萬個文檔,塊越大,遷移到另一個分片所花費的時間就越長,默認情況下,塊的大小為64MB。
但對于64MB的塊,遷移時間太長了,為了加快遷移速度,可以減少塊的大小。
比如將塊的大小改為32MB。
db.settings.save({"_id","chunksize","value":32})
已經(jīng)存在的塊不會發(fā)生改變,自動拆分僅會在插入或更新時發(fā)生,拆分操作是無法恢復(fù)的,如果增加了塊的大小,那么已經(jīng)存在的塊只會通過插入或更新來增長,直到它們達到新的大小。塊大小的取值范圍在1MB到1024MB。
這是一個集群范圍的設(shè)置,會影響所有的集合和數(shù)據(jù)庫。因此,如果一個集合需要較小的塊,另一個集合需要較大的塊,那么可能需要在這兩個大小間取一個折中的值。
如果MongoDB的遷移過于頻繁或者使用的文檔太大,則可能需要增加塊的大小。
四、超大塊
一個塊的所有數(shù)據(jù)都位于某個特定的分片上。如果最終這個分片擁有的塊比其它分片多,那么MongoDB會將一些塊移動到其它分片上。
當(dāng)一個塊大于 config.settings中所設(shè)置的最大塊大小時,均衡器就不允許移動這個塊了。這些不可拆分、不可移動的塊被稱為超大塊。
1、分發(fā)超大塊
要解決超大塊引起的集群不均衡問題,就必須將超大塊均勻地分配到各個分片中。
2、分發(fā)超大塊步驟:
- 關(guān)閉均衡器
sh.setBalancerState(false); - 因為MongoDB不允許移動超過最大塊大小的塊,所以要暫時先增大塊大小,使其超過現(xiàn)有的最大塊塊大小。記錄下當(dāng)時的塊大小。
db.settings.save({"_id","chunksize","value":maxInteger}); - 使用
moveChunk命令移動分片中的超大塊; - 在源分片剩余的塊上運行
splitChunk命令,直到其塊數(shù)量與目標(biāo)分片塊數(shù)量大致相同; - 將塊大小設(shè)置為其最初值;
- 開啟均衡器

3、避免出現(xiàn)超大塊
更改片鍵,使其擁有更細粒度的分片。
通過db.currentOp()查看當(dāng)前操作,``db.currentOp()```最常見的用途是查找慢操作。
MongoDB Enterprise > db.currentOp()
{
"inprog" : [
{
"type" : "op",
"host" : "LAPTOP-P6QEH9UD:27017",
"desc" : "conn1",
"connectionId" : 1,
"client" : "127.0.0.1:50481",
"appName" : "MongoDB Shell",
"clientMetadata" : {
"application" : {
"name" : "MongoDB Shell"
},
"driver" : {
"name" : "MongoDB Internal Client",
"version" : "5.0.14"
},
"os" : {
"type" : "Windows",
"name" : "Microsoft Windows 10",
"architecture" : "x86_64",
"version" : "10.0 (build 19044)"
}
},
"active" : true,
"currentOpTime" : "2023-02-07T23:12:23.086+08:00",
"threaded" : true,
"opid" : 422,
"lsid" : {
"id" : UUID("f83e33d1-9966-44a4-87de-817de0d804a3"),
"uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
},
"secs_running" : NumberLong(0),
"microsecs_running" : NumberLong(182),
"op" : "command",
"ns" : "admin.$cmd.aggregate",
"command" : {
"aggregate" : 1,
"pipeline" : [
{
"$currentOp" : {
"allUsers" : true,
"idleConnections" : false,
"truncateOps" : false
}
},
{
"$match" : {
}
}
],
"cursor" : {
},
"lsid" : {
"id" : UUID("f83e33d1-9966-44a4-87de-817de0d804a3")
},
"$readPreference" : {
"mode" : "primaryPreferred"
},
"$db" : "admin"
},
"numYields" : 0,
"locks" : {
},
"waitingForLock" : false,
"lockStats" : {
},
"waitingForFlowControl" : false,
"flowControlStats" : {
}
},
{
"type" : "op",
"host" : "LAPTOP-P6QEH9UD:27017",
"desc" : "Checkpointer",
"active" : true,
"currentOpTime" : "2023-02-07T23:12:23.086+08:00",
"opid" : 3,
"op" : "none",
"ns" : "",
"command" : {
},
"numYields" : 0,
"locks" : {
},
"waitingForLock" : false,
"lockStats" : {
},
"waitingForFlowControl" : false,
"flowControlStats" : {
}
},
{
"type" : "op",
"host" : "LAPTOP-P6QEH9UD:27017",
"desc" : "JournalFlusher",
"active" : true,
"currentOpTime" : "2023-02-07T23:12:23.086+08:00",
"opid" : 419,
"op" : "none",
"ns" : "",
"command" : {
},
"numYields" : 0,
"locks" : {
},
"waitingForLock" : false,
"lockStats" : {
},
"waitingForFlowControl" : false,
"flowControlStats" : {
}
}
],
"ok" : 1
}
4、輸出內(nèi)容詳解:

- opid,操作的唯一標(biāo)識,可以使用這個字段來終止操作;
- active,操作是否正在進行,如果為false,意味著此操作已經(jīng)讓出或者正在等待其它操作交出鎖;
- secs_running,操作的持續(xù)時間,可以使用這個字段查詢耗時過長的操作;
- op,操作類型,通常為query、insert、update、remove;
- desc,客戶端的標(biāo)識符,可以與日志中的消息相關(guān)聯(lián);
- locks,描述操作所涉及的鎖類型;
- waitingForLock,當(dāng)前操作是否處于阻塞中并等待獲取鎖;
- numYields,操作釋放鎖以允許其它操作進行的次數(shù)。一個操作只有在其它操作進入隊列并等待獲取它的鎖時才會讓出自己的鎖,如果沒有操作處于
waitingForLock狀態(tài),則當(dāng)前操作不會讓出鎖; - lockStats.timeAcquiringMiros,操作為了獲取鎖所花費的時間;
通過``db.currentOp()找到慢查詢后,可以通過db.killOp(opid)```的方式將其終止。
并不是所有操作都可以被終止,只有當(dāng)操作讓出時,才能終止,因此,更新、查找、刪除操作都可以被終止,但持有或等待鎖的操作不能被終止。
如果MongoDB中的請求發(fā)生了堆積,那么這些寫操作將堆積在操作系統(tǒng)的套接字緩沖區(qū),當(dāng)終止MongoDB正在運行的寫操作時,MongoDB依舊會處理緩沖區(qū)的寫操作??梢酝ㄟ^開啟寫入確認機制,保證每次寫操作都要等前一個寫操作完成后才能執(zhí)行,而不是僅僅等到前一個寫操作處于數(shù)據(jù)庫服務(wù)器的緩沖區(qū)就開始下一次寫入。
五、系統(tǒng)分析器
系統(tǒng)分析器可以提供大量關(guān)于耗時過長操作的信息,但系統(tǒng)分析器會嚴重的降低MongoDB的效率,因為每次寫操作都會將其記錄在system.profile中記錄一下。每次讀操作都必須等待system.profile寫入完畢才行。
開啟分析器:
MongoDB Enterprise > db.setProfilingLevel(2)
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
slowms決定了在日志中打印慢速操作的閾值。比如slowms設(shè)置為100,那么每個耗時超過100毫秒的操作都會被記錄在日志中,即使分析器是關(guān)閉的。
查詢分析級別:
MongoDB Enterprise > db.getProfilingLevel() 2
重新啟動MongoDB數(shù)據(jù)庫會重置分析級別。
六、一些常見的輔助命令
通過Object.bsonsize函數(shù)獲取其在磁盤中存儲大小,單位是字節(jié)。
> Object.bsonsize(db.worker.find()) 65194
使用mongotop統(tǒng)計哪些集合最繁忙。
使用mongotop --locks統(tǒng)計每個數(shù)據(jù)庫的鎖信息。
mongostat提供了整個服務(wù)器范圍的信息。
以上就是MongoDB超大塊數(shù)據(jù)問題解決的詳細內(nèi)容,更多關(guān)于MongoDB超大塊數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MongoDB 3.4 安裝以 Windows 服務(wù)方式運行的詳細步驟
這篇文章主要介紹了MongoDB 3.4 安裝以 Windows 服務(wù)方式運行的詳細步驟,需要的朋友可以參考下2017-09-09
SpringBoot整合redis及mongodb的詳細過程
這篇文章主要介紹了SpringBoot整合redis及mongodb,本節(jié)我們來把關(guān)注點轉(zhuǎn)向NoSQL,文章結(jié)合示例代碼給大家講解的非常詳細,需要的朋友可以參考下2022-10-10
關(guān)于mongoDB數(shù)據(jù)庫添加賬號的問題
這篇文章主要介紹了mongoDB數(shù)據(jù)庫添加賬號的問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02

