MongoDBのデータファイル同期について
MongoDBのストレージエンジン
ココで触れた通り
MongoDBは書き込みリクエストを受け付けると、一旦、内部キューにデータを積み、
バックグラウンドスレッド(journal)によって、journalファイルとデータファイルのmmap領域に書き込まれる。
その後、更にバックグラウンドスレッド(DataFileSync)によってmsync()され無事にファイルに書き込まれる事になっている。
この書き込む動作をwriteback呼ぶ
しかし、Linuxでは、mmap()領域はmsync()せずともkernelが一定間隔で書き込んでくれる。
今回は、この辺の挙動の話。
MongoDBのwriteback
mongodの起動オプション--syncdelay=<秒> によって指定できる。
デフォルト値は60
0を指定するとmsync()を呼ばない挙動になる。
- //docs.mongodb.org/manual/reference/configuration-options/#journal">マニュアル:If you set syncdelay to 0, MongoDB will not sync the memory mapped files to disk. Do not set this value on production systems.
syncdelayを0にするとディスクには書かないから本番では指定するなよ。
ここまで来るとまるっきり嘘である!
以前、syncdelayのドキュメントのミスを指摘したのだが
更に輪を掛けて酷くなったのでついカッとなってこのエントリーを書いた。多分彼らもこの辺の挙動を正確に理解してないのだな。
Linuxのwriteback
主に以下のパラメータで制御されている。
- vm.dirty_expire_centisecs
- デフォルト3000(=30秒)。
ディスクに書き込まれるまでの猶予期間。 - vm.dirty_writeback_centisecs
- デフォルト500(=5秒)。
実際にディスクに書き込む処理の起動間隔。
それぞれこんな感じで確認できる。(直接/proc以下を読み書きしても可)
$ sysctl vm.dirty_expire_centisecs vm.dirty_expire_centisecs = 3000 $ sysctl vm.dirty_writeback_centisecs vm.dirty_writeback_centisecs = 500
問題
MongoDBのデフォルトのwriteback間隔は60秒、Linuxのwritebackは最低でも30秒以内には動く。
だからMongoDBのwriteback専用スレッド(DataFileSync)やsyncdelayオプションなんて要らないじゃん!
だったらいっその事、デフォルトsyncdelay=0としてOSに任せた方が良くね?
という話を投げてみた。
これも時間かかるだろうな・・・
syncdelay=0とした場合の挙動を確かめた
1.syncdelay=0を指定してmongodを上げる。
2.毎秒一回、適当なコレクションを更新する。
for i in {0..10000}; do mongo 127.0.0.1:27017 <<< "use testdb db.testcol.save({key:$i})"; sleep 1 done;
3.データファイルのstatを取り、更新時刻を確認する。
stat data/testdb/testdb.0 -c'%y'
結果1(デフォルト)
2013-03-13 00:20:57.441599513 -0700 2013-03-13 00:21:04.838052872 -0700 2013-03-13 00:21:29.125808067 -0700 2013-03-13 00:21:34.408625047 -0700 2013-03-13 00:21:42.857941700 -0700 2013-03-13 00:21:59.761572768 -0700 2013-03-13 00:22:00.817927798 -0700 2013-03-13 00:22:28.286594599 -0700 :
バラツキはあるが、30秒近く更新されないケースもある。
結果2(5秒間隔でwriteback)
# sysctl vm.dirty_expire_centisecs=500 # sysctl vm.dirty_writeback_centisecs=100
2013-03-13 00:23:09.481541037 -0700 2013-03-13 00:23:14.760541494 -0700 2013-03-13 00:23:20.040029026 -0700 2013-03-13 00:23:24.267557606 -0700 2013-03-13 00:23:29.551242097 -0700 2013-03-13 00:23:34.832939305 -0700 2013-03-13 00:23:35.888281140 -0700 2013-03-13 00:23:40.109627939 -0700 2013-03-13 00:23:45.389313622 -0700 2013-03-13 00:23:50.671000401 -0700 2013-03-13 00:23:51.726337540 -0700 :
大体5秒毎に更新されている
結果2(1秒間隔でwriteback)
# sysctl vm.dirty_expire_centisecs=100 # sysctl vm.dirty_writeback_centisecs=100
2013-03-13 00:28:44.298270234 -0700 2013-03-13 00:28:45.353080480 -0700 2013-03-13 00:28:46.409875411 -0700 2013-03-13 00:28:47.467720763 -0700 2013-03-13 00:28:48.527613888 -0700 2013-03-13 00:28:49.583300450 -0700 2013-03-13 00:28:50.640146646 -0700 2013-03-13 00:28:51.697976987 -0700 2013-03-13 00:28:52.754726703 -0700 2013-03-13 00:28:53.809552595 -0700 :
毎秒に更新されている模様。