Mongo threads 日本語版
この記事はmongoのソースを読み解きたい人向けです。
それ以外の人には多分有意な情報は無いかと。。
また私自身がコードリーディングした時に書き散らしたメモを纏めただけなので
精確じゃなかったり諦めたりした部分もありますので、ご了承ください。
スレッド
スレッド名はログファイルに現れている。
Tue Feb 5 19:15:33.544 [rsBackgroundSync] replSet syncing to: 192.168.159.134:27017
例えば、このログは[rsBackgroundSync]というスレッドが出力したという事。
main
メインスレッドは少し特殊で名前が変わる。
- //github.com/mongodb/mongo/blob/r2.3.2/src/mongo/db/db.cpp#L740">(noname): 最初は名前が無い。
- //github.com/mongodb/mongo/blob/r2.3.2/src/mongo/db/db.cpp#L568">initandlisten: イニシャル処理中の名前
- //github.com/mongodb/mongo/blob/r2.3.2/src/mongo/util/net/listen.cpp#L208">conn(class MyMessageHandler): サービス開始後はソケットサーバスレッドに変わる
DataFileSync
定期的にデータファイルのmmapをmsync()する。
- sleep
- [--syncdelay]*1000 (60*1000 is default , 0 is never)
ちなみにsyncdelayオプションはオンラインで変更可能。
admin db.runCommand({'setParameter':1,syncdelay:1})
しかし実際はわざわざmsync()しなくてもkernelが定期的にsyncしている。
しかもsyncdelayは秒指定で長すぎてほとんど意味がない。
多分このスレッドは設計ミスで全然効いてない(要らない)
journal
MongoDBではパフォーマンス確保の為、一定期間のアップデートを貯めて置きグループコミットする。
- sleep
- (journalCommitInterval/3) + 1
-
- journalCommitIntervalオプション値の1/3の時間毎にuncommitted bytesのリミットをチェックする。
実は"--journalCommitInterval"の範囲が2から300である理由かも
2って半端だよな!って思ってたw
- ジャーナルに書く(fsync)
- getlasterrorへ『書いたよ』通知
- データファイルへ書く(その内msync()される)
indexRebuilder : (since 2.4)
スタートアップ時の一時的なスレッド。
- sleep
- 修復が終わったら死ぬのでsleepしない
前回終了がクラッシュで『作りかけのインデックス』がある場合に修復する。
("--noIndexBuildRetry"オプションには従う )
clientcursormon
カーソルの数を数えたり、タイムアウトしたカーソルを回収したりする。
- sleep
- 4000
カーソル数が100000を超えるとこんなログを出す
warning number of open cursors is very large: ??
回収した時のログ
killing old cursor [id] [ns] idle: ??ms
- timeout of cursor
- 600000 msec
PeriodicTask::Runner
1分毎タスクを走らせるフレームワーク
- sleep
- 60000
mongos と mongo-client で使われてる模様。
- Cleaner (writeback query cleaner)
- DBConnectionPool (staled connection cleaner)
mongosでは動作確認したが(この辺)
mongodではシチュエーションが良く解らない。。。まあ動きは解ってるし放置しとく。
TTLMonitor : (since 2.2)
新機能。期限付きドキュメントを回収するスレッド
- sleep
- 60000
db.foo.ensureIndex({"status":1},{expireAfterSeconds:3600})
rsHealthPoll
Mongod間の生死チェックメッセージ用のスレッド
- sleep
- 2000
何か変わってたらrsMgrに投げるだけ
- Heartbeatリクエスト&レスポンス
- Send "update heartbeat" message to rsMgr
- Send "check new state" message to rsMgr
rsMgr on on task::Server
非同期メッセージングフレームワーク
- sleep
- by mutex cond wait
ラムダ式を直接キューイングする変わった仕組み。
実際はrsHealthPollからしか使われて無いんじゃないか?
rsSync
レプリカの肝処理だが、以下のスレッドと複雑に絡み合って動作する。
- rsBackgroundSync
- rsSyncNotifier
- rsGhostSync
正直複雑すぎて良く解らない・・・
- sleep
- 1000
まず、プライマリでは何もしない。(誰からも同期しない)
スレーブの場合
- 必要なら初期同期する。
- サービス中はループ
- 内部キューのOPQueueを読んで自分に書き込んでいく
in SyncTail::oplogApplication()
- replBatchLimitBytesやslaveDelayを考慮しつつOPQueueから必要な量を読む。
- Multi apply
- 処理したOplogを記録。(次回何処から処理するのか?)
- rsBackgroundSync と rsSyncNotifierへ通知
rsBackgroundSync
同期先(普通はPrimary)のOplogを読んでOPQueueに貯める
- sleep
- no wait
- 同期対象を決める。(普通はPrimary)
- Oplogを読む
- OPQueueに積む
rsSyncNotifier
役割が良く解らない・・・
- sleep
- no wait
- rsSyncからの通知を受け取るまで待機
- _oplogMarker.more()を叩く。
多分、rsBackgroundSyncのOplogと比べてるんだろう・・・
ただ実際はログを吐いているだけで、特に重要な処理はしてなさそう・・・にしては複雑すぎる仕組みなので何かありそう。
結局はoplogMarkerの役割は不明
rsGhostSync on task::Server
GhostSync用っぽい。こいつも良く解らない。
- sleep
- no wait
自分がスレーブの時、別のスレーブからOplogを読まれる場合(Ghost sync)にGhostSync::percolate()が呼ばれる。
percolate() では、循環同期を検出する為、自分の同期先が相手に向いていないか否かをチェックする。
ただ、循環同期を検出してもログを吐いているだけに見える。。
slaveTracking
スレーブ構成をウォッチするスレッド
- sleep
- 1000
- スレーブ構成変更の通知を受ける
- local.slavesに書く
- 別スレッドに通知 (多分mongosだけの処理)
mongodではlocal.slavesに書くだけっぽい。
Threads
conn%d
Mongodはクライアント接続毎に専用スレッドを振る模様。
スレッド名はconn1 , conn2 , ... となっていく。
ASIOビルドの場合はその限りでは無いが、まだ正式サポートしてないので無視。