MongoDB超大塊數據問題解決
引言
最近項目在使用MongoDB作為圖片和文檔的存儲數據庫,為啥不直接存MySQL裡,還要搭個MongoDB集群,麻不麻煩?
讓我們一起,一探究竟,繼續學習解決MongoDB超大塊數據問題,實現快速入門,豐富個人簡歷,提高面試level,給自己增加一點談資,秒變面試小達人,BAT不是夢。
一、MongoDB服務器管理
1、添加服務器
可以在任何時間添加mongos進程,隻要確保,它們的 --configdb
選項指定瞭正確的配置服務器副本集,並且客戶端可以立即與其建立連接。
2、修改分片中的服務器
要修改一個分片的成員,需要直接連接到該分片的主節點,並重新配置副本集。集群配置會檢測到變更並自動更新 config.shards
。
3、刪除分片
一般情況下,不應該從集群中刪除分片,會給系統帶來不必要的壓力。
刪除分片時,要確保均衡器的打開狀態。
均衡器的作用是把要刪除分片上的所有數據移動到其它分片,這個過程稱為排空。可以通過 removeShard
命令執行排空操作。
二、均衡器
可以通過 sh.setBalancerState(false)
關閉均衡器。關閉均衡器不會將正在進行的過程停止,也就是說遷移過程不會立即停止。
通過db.locks.find({"_id","balancer"})["state"]
查看均衡器是否關閉。0表示均衡器已關閉。
均衡過程會增加系統的負載,目標分片必須查詢源分片的所有文檔,並將文檔插入目標分片的塊中,然後源分片必須刪除這些文檔。
數據遷移是很消耗性能的,此時可以在config.settings
集合中為均衡過程指定一個時間窗口。將其指定在一個閑暇時間執行。
如果設置瞭均衡窗口,應該對其進行監控,確保mongos能夠在所分配的時間內保持集群的均衡。
均衡器使用塊的數量而不是數據的大小作為度量。移動一個塊被稱為遷移,這是MongoDB平衡數據的方式。可能會存在一個大塊的分片稱為許多小分片遷移的目標。
三、修改塊的大小
一個塊可以存放數百萬個文檔,塊越大,遷移到另一個分片所花費的時間就越長,默認情況下,塊的大小為64MB。
但對於64MB的塊,遷移時間太長瞭,為瞭加快遷移速度,可以減少塊的大小。
比如將塊的大小改為32MB。
db.settings.save({"_id","chunksize","value":32})
已經存在的塊不會發生改變,自動拆分僅會在插入或更新時發生,拆分操作是無法恢復的,如果增加瞭塊的大小,那麼已經存在的塊隻會通過插入或更新來增長,直到它們達到新的大小。塊大小的取值范圍在1MB到1024MB。
這是一個集群范圍的設置,會影響所有的集合和數據庫。因此,如果一個集合需要較小的塊,另一個集合需要較大的塊,那麼可能需要在這兩個大小間取一個折中的值。
如果MongoDB的遷移過於頻繁或者使用的文檔太大,則可能需要增加塊的大小。
四、超大塊
一個塊的所有數據都位於某個特定的分片上。如果最終這個分片擁有的塊比其它分片多,那麼MongoDB會將一些塊移動到其它分片上。
當一個塊大於 config.settings
中所設置的最大塊大小時,均衡器就不允許移動這個塊瞭。這些不可拆分、不可移動的塊被稱為超大塊。
1、分發超大塊
要解決超大塊引起的集群不均衡問題,就必須將超大塊均勻地分配到各個分片中。
2、分發超大塊步驟:
- 關閉均衡器
sh.setBalancerState(false)
; - 因為MongoDB不允許移動超過最大塊大小的塊,所以要暫時先增大塊大小,使其超過現有的最大塊塊大小。記錄下當時的塊大小。
db.settings.save({"_id","chunksize","value":maxInteger})
; - 使用
moveChunk
命令移動分片中的超大塊; - 在源分片剩餘的塊上運行
splitChunk
命令,直到其塊數量與目標分片塊數量大致相同; - 將塊大小設置為其最初值;
- 開啟均衡器
3、避免出現超大塊
更改片鍵,使其擁有更細粒度的分片。
通過db.currentOp()
查看當前操作,“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、輸出內容詳解:
- opid,操作的唯一標識,可以使用這個字段來終止操作;
- active,操作是否正在進行,如果為false,意味著此操作已經讓出或者正在等待其它操作交出鎖;
- secs_running,操作的持續時間,可以使用這個字段查詢耗時過長的操作;
- op,操作類型,通常為query、insert、update、remove;
- desc,客戶端的標識符,可以與日志中的消息相關聯;
- locks,描述操作所涉及的鎖類型;
- waitingForLock,當前操作是否處於阻塞中並等待獲取鎖;
- numYields,操作釋放鎖以允許其它操作進行的次數。一個操作隻有在其它操作進入隊列並等待獲取它的鎖時才會讓出自己的鎖,如果沒有操作處於
waitingForLock
狀態,則當前操作不會讓出鎖; - lockStats.timeAcquiringMiros,操作為瞭獲取鎖所花費的時間;
通過“db.currentOp()找到慢查詢後,可以通過db.killOp(opid)“`的方式將其終止。
並不是所有操作都可以被終止,隻有當操作讓出時,才能終止,因此,更新、查找、刪除操作都可以被終止,但持有或等待鎖的操作不能被終止。
如果MongoDB中的請求發生瞭堆積,那麼這些寫操作將堆積在操作系統的套接字緩沖區,當終止MongoDB正在運行的寫操作時,MongoDB依舊會處理緩沖區的寫操作。可以通過開啟寫入確認機制,保證每次寫操作都要等前一個寫操作完成後才能執行,而不是僅僅等到前一個寫操作處於數據庫服務器的緩沖區就開始下一次寫入。
五、系統分析器
系統分析器可以提供大量關於耗時過長操作的信息,但系統分析器會嚴重的降低MongoDB的效率,因為每次寫操作都會將其記錄在system.profile
中記錄一下。每次讀操作都必須等待system.profile
寫入完畢才行。
開啟分析器:
MongoDB Enterprise > db.setProfilingLevel(2) { "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
slowms
決定瞭在日志中打印慢速操作的閾值。比如slowms
設置為100,那麼每個耗時超過100毫秒的操作都會被記錄在日志中,即使分析器是關閉的。
查詢分析級別:
MongoDB Enterprise > db.getProfilingLevel() 2
重新啟動MongoDB數據庫會重置分析級別。
六、一些常見的輔助命令
通過Object.bsonsize
函數獲取其在磁盤中存儲大小,單位是字節。
> Object.bsonsize(db.worker.find()) 65194
使用mongotop
統計哪些集合最繁忙。
使用mongotop --locks
統計每個數據庫的鎖信息。
mongostat
提供瞭整個服務器范圍的信息。
以上就是MongoDB超大塊數據問題解決的詳細內容,更多關於MongoDB超大塊數據的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- mongodb清除連接和日志的正確方法分享
- MongoDB balancer的使用詳解
- MongoDB卸載安裝的詳細安裝教程
- MongoDB日志切割的三種方式總結
- Window環境下配置Mongodb數據庫