ひとりMongoDB University 12/13 - データーベースのプロファイリング
この記録は、アドベントカレンダー形式の、MongoDB Universityの学習コースの記録、13日目になります!
ただいまコース: M103[1]を進めています。目標は12/25までにChapter1の完走!
Chapter 1: Profiling the Database (動画)
データベースの状態を分析するためには、ログからだけでなく、プロファイルを使う方法があります。
今回の動画ではその紹介。
- ログファイルの特徴
- データベースのイベントに関する全ての情報が記録される
- 非常に量が多い&ファイルや標準出力での取得なので、加工をしないと構造的に扱えない
- データベースが健全かどうかを確認するためのもの
- どんなオペレーションが行われたかに着目
- プロファイルは特定の用途に絞ってデータを収集
- プロファイル用のデータベース&コレクションにデータを溜めることができる
- どのクエリが遅いのか、といったことを突き止めるためには、プロファイルが有効
プロファイルの取得単位
-
プロセス全体でなく、データベース単位でデータを蓄積する
- 該当するデータベースごとに、プロファイルデータを保持したコレクションを作成する
- db.systemというコレクションになる
-
取得対象
- CRUDオペレーション
- 管理上の操作
- 設定変更・調整の操作
-
プロファイルのレベル
- 0: 取得しない
- 1: 標準
- 2: デバッグレベル。トランザクションの多いデータベースだと非常に大きくなっちゃうので注意!
- データベースの負荷も上がるので値の設定には注意!
動画に沿ってMongoDBのコンテナで確認
- Dockerで起動したMongoDBのコンテナ内にアタッチ
- mongoコマンドでMongo shellを起動
# 既存のデータベースの確認
> show databases
admin 0.000GB
config 0.000GB
local 0.000GB
# 存在しないデータベースであっても、use データベース名 でネームスペースを切り替え
> use newDB
switched to db newDB
> show databases
admin 0.000GB
config 0.000GB
local 0.000GB
# show collectionsと同じ内容を db.runCommand() で実行
# まだコレクションは存在しない (ns = NameSpace: newDB)
> db.runCommand({listCollections: 1})
{
"cursor" : {
"id" : NumberLong(0),
"ns" : "newDB.$cmd.listCollections",
"firstBatch" : [ ]
},
"ok" : 1
}
> db.getProfilingLevel()
0
> db.setProfilingLevel( 1 )
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> show collections
system.profile
# 上記と同様に、コレクション表示をdb.runCommand() で実行
> db.runCommand({listCollections: 1})
{
"cursor" : {
"id" : NumberLong(0),
"ns" : "newDB.$cmd.listCollections",
"firstBatch" : [
{
"name" : "system.profile",
"type" : "collection",
"options" : {
"capped" : true,
"size" : 1048576
},
"info" : {
"readOnly" : false,
"uuid" : UUID("eec9f873-195f-4d8d-a6cc-2cf2c3b3c4c6")
}
}
]
},
"ok" : 1
}
> result = db.runCommand({listCollections: 1})
> result.cursor.firstBatch[0].name
system.profile
# JavaScriptが使えるのでチェック
> result.cursor.firstBatch.map((object) => object.name )
[ "system.profile" ]
# レベル調整
> db.setProfilingLevel( 1, { slowms: 0 } )
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
# 新しいコレクションにデータを挿入してみる(勝手にコレクションは作られます)
> db.new_collection.insert( { "a": 1 } )
WriteResult({ "nInserted" : 1 })
> show collections
new_collection # 追加された
system.profile
# 同じく確認
> result = db.runCommand({listCollections: 1})
> result.cursor.firstBatch.map((object) => object.name )
[ "new_collection", "system.profile" ]
# プロファイル取得を有効にしているので、systemコレクションにデータが出来ているハズ!
> db.system.profile.find().count()
1
# 1件を確認したので、プロファイルを取得してみる
> db.system.profile.find().pretty()
{
"op" : "insert",
"ns" : "newDB.new_collection",
"command" : {
"insert" : "new_collection",
"ordered" : true,
"lsid" : {
"id" : UUID("690c46ea-4270-4e79-b63d-f0d8eecb07ea")
},
"$db" : "newDB"
},
"ninserted" : 1,
"keysInserted" : 1,
"numYield" : 0,
"locks" : {
"ParallelBatchWriterMode" : {
"acquireCount" : {
"r" : NumberLong(5)
}
},
"ReplicationStateTransition" : {
"acquireCount" : {
"w" : NumberLong(6)
}
},
"Global" : {
"acquireCount" : {
"r" : NumberLong(3),
"w" : NumberLong(3)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(2),
"w" : NumberLong(3)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(1),
"w" : NumberLong(3)
}
},
"Mutex" : {
"acquireCount" : {
"r" : NumberLong(5)
}
}
},
"flowControl" : {
"acquireCount" : NumberLong(3),
"timeAcquiringMicros" : NumberLong(4)
},
"storage" : {
},
"responseLength" : 45,
"protocol" : "op_msg",
"millis" : 41,
"ts" : ISODate("2020-12-13T03:01:18.304Z"),
"client" : "127.0.0.1",
"appName" : "MongoDB Shell",
"allUsers" : [ ],
"user" : ""
}
{
"op" : "command",
"ns" : "newDB.system.profile",
"command" : {
"count" : "system.profile",
"query" : {
},
"lsid" : {
"id" : UUID("690c46ea-4270-4e79-b63d-f0d8eecb07ea")
},
"$db" : "newDB"
},
"keysExamined" : 0,
"docsExamined" : 0,
"numYield" : 0,
"locks" : {
"ReplicationStateTransition" : {
"acquireCount" : {
"w" : NumberLong(2)
}
},
"Global" : {
"acquireCount" : {
"r" : NumberLong(2)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(1)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(1)
}
},
"Mutex" : {
"acquireCount" : {
"r" : NumberLong(1)
}
}
},
"flowControl" : {
},
"responseLength" : 45,
"protocol" : "op_msg",
"millis" : 0,
"planSummary" : "RECORD_STORE_FAST_COUNT",
"execStats" : {
"stage" : "RECORD_STORE_FAST_COUNT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 0,
"works" : 1,
"advanced" : 0,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"nCounted" : 1,
"nSkipped" : 0
},
"ts" : ISODate("2020-12-13T03:03:15.211Z"),
"client" : "127.0.0.1",
"appName" : "MongoDB Shell",
"allUsers" : [ ],
"user" : ""
}
# 検索もしてみる
> db.new_collection.find({ a: 1 })
{ "_id" : ObjectId("5fd583fe3d930029a247d9aa"), "a" : 1 }
# この時のプロファイルも確認
# 操作はquery
#
{
"op" : "query",
"ns" : "newDB.system.profile",
"command" : {
"find" : "system.profile",
"filter" : {
},
"lsid" : {
"id" : UUID("690c46ea-4270-4e79-b63d-f0d8eecb07ea")
},
"$db" : "newDB"
},
"keysExamined" : 0,
"docsExamined" : 7,
"cursorExhausted" : true,
"numYield" : 0,
"nreturned" : 7,
"locks" : {
"ReplicationStateTransition" : {
"acquireCount" : {
"w" : NumberLong(2)
}
},
"Global" : {
"acquireCount" : {
"r" : NumberLong(2)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(1)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(1)
}
},
"Mutex" : {
"acquireCount" : {
"r" : NumberLong(1)
}
}
},
"flowControl" : {
},
"storage" : {
},
"responseLength" : 6406,
"protocol" : "op_msg",
"millis" : 0,
"planSummary" : "COLLSCAN", # スキャンの方法とか
"execStats" : {
"stage" : "COLLSCAN",
"nReturned" : 7,
"executionTimeMillisEstimate" : 0,
"works" : 9,
"advanced" : 7,
"needTime" : 1,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"direction" : "forward",
"docsExamined" : 7
},
"ts" : ISODate("2020-12-13T03:09:23.177Z"),
"client" : "127.0.0.1",
"appName" : "MongoDB Shell",
"allUsers" : [ ],
"user" : ""
}
以上。
Profiling the Database (クイズ)
Problem
Which of the following events are captured by the profiler?
こたえ
- CRUD operations
- Administrative operations
- Configuration operations
ネットワークタイムアウトや、WiredTigerのストレージデータのイベントはプロファイラではなく、ログから。
Lab: Logging to a Different Facility (演習問題)
1 設定を調整して起動
- ログを /var/mongodb/logs/mongod.log に指定
- mongod is forked and run as a daemon (デーモンモードで動かすこと)
2 起動したら、テスト接続用のユーザを作るスクリプトを流すこと
3 テストを実行すること
設定
デーモンモードだと、起動を --fork オプションをつけるか、設定に以下のように追記する。
processManagement:
fork: true
上記を踏まえた設定ファイル。
storage:
dbPath: /var/mongodb/db
net:
bindIp: localhost
port: 27000
security:
authorization: enabled
systemLog:
path: "/var/mongodb/logs/mongod.log"
destination: "file"
processManagement:
fork: true
この状態で起動。
bash-4.4# mongod -f mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 351
child process started successfully, parent exiting
テストが通りました!
今日の進捗
シェルを使って操作しながら動画を見て進めているので、進度は遅め。でもたぶん理解はなんとかなると思います。
3つほど進みました。Chapter1の残りは、あと9つ。1日3つくらいのペースで終わらせたい!
また、気になっているテストの実行方式。
「Run Test」ボタンを押すとサーバ側にUserIDと対象のテストIDが送信されるみたいです。
結果をJSONで受け取り、フロントエンドで描画(成功なら緑)
ターミナルへの出力は結果を表示する感じ。
次回はもう少しWeb IDEを操作している時の通信を眺めてみよう。
きょうのzenn
しばし同じ方法で進めています!毎日変わる絵文字が楽しい。
-
M103: Basic Cluster Administration のコースになります。コースを開始すると、完了までの期限は2ヶ月以内です。 ↩︎
Discussion