MongoDB在數據導入期間每n秒寫一次鎖
我在分片集群中遇到數據導入問題,我需要一些幫助來調查並可能找到我集群中的瓶頸所在。
所以我在 AWS EC2(不是 Atlas)上託管了一個分片集群(3 個分片)。
每個分片是一個 3 個成員的副本集,其中包含 1 個主 (r4.xlarge) 和 2 個輔助 (r4.large)。配置伺服器是 c4.large,當然也是副本集。
- r4.xlarge 是 30,5G 記憶體,4vCPU
- r4.large 是 15,5G 記憶體,2vCPU
WiredTiger 記憶體設置是預設設置,因此主伺服器和輔助伺服器都有 50% 的 RAM。
輔助節點不如主節點強大,優先級為 5(主節點的優先級為 10),因為它們僅用作數據副本以實現持久性(幾乎不讀取它們,除非在一天中的給定時間進行度量計算)。
在每個分片成員上,數據、日誌和日誌目錄分別安裝在不同的 EBS 卷 (GP2) 上:
- 數據:600 iops
- 日誌:200 iops
- 日誌:100 iops
我在 EC2 (m4.large) 上有另一台機器,在 python 中執行 ETL 程序(處理 85M 行的 CSV),並在 10M+ 文件的集合中成組導入它們。這不是一個 mongoimport 或 mongorestore 程序,而是一個自定義腳本(在插入之前對數據應用轉換),我沒有使用多個執行緒或程序並行進行導入。
MongoDB 版本為 3.4.10,儲存引擎為 WiredTiger,啟用日誌,預設寫入關注為 {w:1}。
平衡和平衡器已停止,我沒有並行執行任何其他操作。
更新是批量完成的(一次 1000 次操作),使用 $addToSet,一切正常,但是每 n 次操作,都有某種鎖,它減慢了整個過程。
我的應用程序記錄每個寫操作,這裡是一個範例:
2018-04-26 20:58:12,704 [INFO] Batch #15916 | 0.93s | 1076r/s [Ins:0, Fnd:1000, Mdf:1000, Ups:0] 2018-04-26 20:58:13,352 [INFO] Batch #15917 | 0.65s | 1543r/s [Ins:0, Fnd:1000, Mdf:1000, Ups:0] 2018-04-26 20:58:14,627 [INFO] Batch #15918 | 1.27s | 784r/s [Ins:0, Fnd:1000, Mdf:1000, Ups:0] <<< this happens every 10 or 15 chunks, roughly every 12 to 15 seconds 2018-04-26 20:58:15,601 [INFO] Batch #15919 | 0.97s | 1026r/s [Ins:0, Fnd:1000, Mdf:1000, Ups:0] 2018-04-26 20:58:16,556 [INFO] Batch #15920 | 0.95s | 1047r/s [Ins:0, Fnd:1000, Mdf:1000, Ups:0]
當我更改寫入問題並將其設置為 {w:0} 時,情況更糟(相同的批量大小,相同的腳本):
2018-04-26 21:24:11,280 [INFO] Batch #0014 | 0.34s | 2899r/s 2018-04-26 21:24:11,624 [INFO] Batch #0015 | 0.34s | 2909r/s 2018-04-26 21:24:11,981 [INFO] Batch #0016 | 0.36s | 2794r/s 2018-04-26 21:24:12,331 [INFO] Batch #0017 | 0.35s | 2863r/s 2018-04-26 21:24:20,281 [INFO] Batch #0018 | 7.95s | 125r/s <<<< Here 2018-04-26 21:24:20,642 [INFO] Batch #0019 | 0.36s | 2771r/s 2018-04-26 21:24:20,991 [INFO] Batch #0020 | 0.35s | 2869r/s 2018-04-26 21:24:21,335 [INFO] Batch #0021 | 0.34s | 2906r/s 2018-04-26 21:24:21,683 [INFO] Batch #0022 | 0.35s | 2876r/s 2018-04-26 21:24:30,176 [INFO] Batch #0023 | 8.49s | 117r/s <<<< Here 2018-04-26 21:24:30,524 [INFO] Batch #0024 | 0.35s | 2876r/s 2018-04-26 21:24:30,866 [INFO] Batch #0025 | 0.34s | 2925r/s 2018-04-26 21:24:31,221 [INFO] Batch #0026 | 0.35s | 2819r/s 2018-04-26 21:24:31,567 [INFO] Batch #0027 | 0.35s | 2891r/s 2018-04-26 21:24:39,747 [INFO] Batch #0028 | 8.18s | 122r/s <<<< Here 2018-04-26 21:24:40,100 [INFO] Batch #0029 | 0.35s | 2830r/s 2018-04-26 21:24:40,444 [INFO] Batch #0030 | 0.34s | 2908r/s 2018-04-26 21:24:40,783 [INFO] Batch #0031 | 0.34s | 2950r/s 2018-04-26 21:24:41,135 [INFO] Batch #0032 | 0.35s | 2844r/s 2018-04-26 21:24:48,876 [INFO] Batch #0033 | 7.74s | 129r/s <<<< Here 2018-04-26 21:24:49,239 [INFO] Batch #0034 | 0.36s | 2758r/s 2018-04-26 21:24:49,596 [INFO] Batch #0035 | 0.36s | 2800r/s 2018-04-26 21:24:49,944 [INFO] Batch #0036 | 0.35s | 2877r/s 2018-04-26 21:24:50,297 [INFO] Batch #0037 | 0.35s | 2830r/s 2018-04-26 21:24:58,135 [INFO] Batch #0038 | 7.84s | 127r/s <<<< Here 2018-04-26 21:24:58,498 [INFO] Batch #0039 | 0.36s | 2757r/s 2018-04-26 21:24:58,844 [INFO] Batch #0040 | 0.35s | 2889r/s
它看起來像是每 n 秒或 n 次操作的某種“送出”,但我查看了 AWS 上的指標,它似乎不是磁碟 iops 的問題。
樣本文件:
{ "_id" : ObjectId("58de480d7ae97f6817f4a36d"), "external_id" : "123456789", "code" : {...}, "date_in" : ISODate("2015-12-20T01:00:00.000+0100"), "custom" : {...}, "address" : {...}, "orders" : [ {...}, {...}, {...}, {...}, {...} ], "mailing" : { "sent" : [ { "c" : NumberInt(0), "d" : ISODate("2018-04-20T02:01:00.000+0200"), "i" : NumberInt(5796), "r" : NumberInt(0), "t" : NumberInt(2), "x" : NumberInt(600030925), "y" : "722" }, { "c" : NumberInt(0), "d" : ISODate("2017-12-26T01:01:00.000+0100"), "i" : NumberInt(5796), "r" : NumberInt(0), "t" : NumberInt(2), "x" : NumberInt(600009477), "y" : "443" } ], "delivered":[{...},{...},{...}], "opened":[{...},{...},{...}], "opened":[{...},{...},{...}], "clicked":[{...},{...},{...}], "bounces":[{...},{...},{...}] } }
該過程使用 $addToSet 將新元素添加到數組 mailing.sent、mailing.delivered、mailing.opened 等。
我知道輔助節點比主節點壓力更大,因為 oplog 記錄了整個數組的更新,而不僅僅是 $addToSet 操作(JIRA 上有一張關於此的票)。
隨著我導入數據(給定集合的大約 60Go 數據)以及文件大小,數據庫量正在增長。
有沒有人經歷過這樣的事情並且可以指出我解決這個問題的正確方向?
謝謝 !
您看到的停頓聽起來像是磁碟試圖跟上傳入數據量的結果。也就是說,它是由 WiredTiger 等待磁碟刷新完成引起的。當 WiredTiger 等待時,所有上游程序也必須依次等待,從而導致可觀察到的停頓。
預設情況下,在 MongoDB 3.6.4 中,WiredTiger 將嘗試將臟百分比(記憶體中修改數據的大小相對於配置的記憶體大小)保持在配置記憶體大小的 5% 以下,並且整體記憶體使用率低於配置記憶體大小的 80% . WiredTiger 記憶體使用中描述了預設記憶體大小。
一旦百分比超過這些數字,WiredTiger 將更加努力,讓想要在 WiredTiger 中執行操作的應用程序執行緒(例如執行插入的執行緒)幫助記憶體驅逐(可能涉及刷新到磁碟)在允許之前做這項工作。這充當了一種內置的節流機制,以確保儲存引擎和磁碟不會被傳入的工作過度淹沒。
可能的解決方案包括:
- 配置能夠更快寫入的磁碟。
- 配置一個較小的 WiredTiger 記憶體,使 5% 的數字足夠小,不會壓倒磁碟的容量。
- 調節從應用程序端傳入的數據量。
- 以上三點的某種組合。
在適合您的工作負載的記憶體大小方面,我同意您需要在最小化這些刷新的影響之間找到平衡,同時仍然有足夠的大小來服務讀取。