MongoDBのパフォーマンスをモニタリングする方法

著者は、オープン・インターネット/フリースピーチ基金を寄付の受取先として選択しました。これは寄付のために書くプログラムの一環です。

導入

監視はデータベース管理の重要な部分であり、データベースのパフォーマンスや全体的な健康状態を把握することができます。データベースのパフォーマンスを監視することで、現在の容量をよりよく把握し、そのワークロードが時間とともにどのように変化するかを観察し、データベースが限界に近づいてきたときにデータベースを拡張するための計画を立てることができます。また、予期しないデータベースの使用量の急増など、ハードウェアの問題や異常な動作に気付くのに役立ちます。最後に、監視は、データベースを使用するアプリケーションに関する問題を診断するのに役立ちます。例えば、ボトルネックを引き起こすアプリケーションクエリなどです。

MongoDBには、データベースのパフォーマンスを観察するために使用できるさまざまなツールとユーティリティがインストールされています。このチュートリアルでは、組み込みのコマンドやツールを使用してデータベースのメトリクスをオンデマンドで監視する方法について学びます。また、MongoDBのデータベースプロファイラを使用して、最適化されていないクエリを検出する方法にも精通するようになります。

前提条件

このチュートリアルに従うには、次のものが必要です:

  • A server with a regular, non-root user with sudo privileges and a firewall configured with UFW. This tutorial was validated using a server running Ubuntu 20.04, and you can prepare your server by following this initial server setup tutorial for Ubuntu 20.04.
  • サーバーにインストールされたMongoDB。これを設定するには、Ubuntu 20.04にMongoDBをインストールする方法のチュートリアルに従ってください。
  • サーバーのMongoDBインスタンスを、認証を有効にして管理ユーザーを作成することでセキュリティで保護します。MongoDBをこのようにセキュアにするには、Ubuntu 20.04でMongoDBをセキュアにする方法のチュートリアルに従ってください。
  • MongoDBコレクションのクエリと結果のフィルタリングに精通しています。MongoDBクエリの使用方法について学ぶには、MongoDBでクエリを作成する方法のガイドに従ってください。

注意: サーバーの構成、MongoDBのインストール、MongoDBインストールのセキュリティ設定に関するリンク先のチュートリアルは、Ubuntu 20.04を参照しています。このチュートリアルは、MongoDB自体に焦点を当てており、基礎となるオペレーティングシステムに関係ありません。認証が有効にされていれば、オペレーティングシステムに関係なく、一般的にどのMongoDBインストールでも機能します。

ステップ1 — テストデータの準備

MongoDBのパフォーマンスを監視する方法を説明するために、このステップでは、MongoDBシェルを開いてローカルにインストールされたMongoDBインスタンスに接続し、その中にサンプルコレクションを作成する手順を概説します。

このガイドで使用されているサンプルコレクションを作成するには、管理ユーザーとしてMongoDBシェルに接続します。このチュートリアルは、事前準備のMongoDBセキュリティチュートリアルの規則に従っており、この管理ユーザーの名前がAdminSammyであること、およびその認証データベースがadminであることを前提としています。これらの詳細を自分のセットアップに合わせて変更してください:

  1. mongo -u AdminSammy -p --authenticationDatabase admin

インストール中に設定したパスワードを入力してシェルにアクセスしてください。パスワードを入力した後、>プロンプトサインが表示されます。

注意: 新しい接続では、MongoDBシェルはデフォルトでtestデータベースに接続します。このデータベースを使用してMongoDBとMongoDBシェルを試すことができます。

または、このチュートリアルで示されているすべての例のコマンドを実行するために、別のデータベースに切り替えることもできます。別のデータベースに切り替えるには、useコマンドに続いてデータベースの名前を指定します:

  1. use database_name

小規模なデータセットで作業する場合、データベースシステムは任意のクエリに対してわずかなレコードしかスキャンする必要がないため、データベースのモニタリングはあまり実用的または有用ではありません。MongoDBのパフォーマンスモニタリング機能を説明するためには、MongoDBがクエリを実行するのにかなりの時間がかかる十分なデータを持つデータベースが必要です。

このガイド全体を通しての例は、多数のドキュメントを含むaccountsというサンプルコレクションを参照しています。各ドキュメントはランダムに生成された口座残高を持つ個々の銀行口座を表します。コレクション内の各ドキュメントは、次のような構造を持ちます:

An example bank account document
{
    "number": "1000-987321",
    "currency": "USD",
    "balance": 431233431
}

この例のドキュメントには、次の情報が含まれています:

  • number: このフィールドは、指定された口座の口座番号を表します。このコレクションでは、各口座番号には1000-の接頭辞が付いており、増加する数値識別子が続きます。
  • currency: このフィールドは、各口座の残高が格納されている通貨の種類を示します。各口座のcurrencyの値は、USDまたはEURのいずれかになります。
  • balance: これは、各銀行口座の残高を示します。このサンプルデータベースでは、各ドキュメントのbalanceフィールドにはランダムに生成された値が入ります。

大量のドキュメントを手動で挿入する代わりに、次のJavaScriptコードを実行してaccountsというコレクションを同時に作成し、100万件のそのようなドキュメントを挿入することができます:

  1. for (let i = 1; i <= 1000000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "1000-" + i,
  4. "currency": i > 500000 ? "USD" : "EUR",
  5. "balance": Math.random() * 100000
  6. })
  7. }

このコードは、連続して100万回forループを実行します。ループが繰り返されるたびに、insertOne()メソッドがアカウントコレクションに新しいドキュメントを挿入します。各繰り返しでは、i値によってそのイテレーションのためのnumberフィールドの値が1000-接頭辞と組み合わされます。これにより、このループが最初に繰り返されると、numberフィールドの値は1000-1に設定されます。最後に繰り返されると、1000-1000000に設定されます。

通貨は、500000より高い番号のアカウントでは常にUSDとして表され、それより低い番号のアカウントではEURとして表されます。バランスフィールドは、Math.random()関数を使用して0から1までのランダムな数値を生成し、そのランダムな数値に100000を乗算して大きな値を提供します。

注意: このループの実行には長い時間がかかる場合があります。操作が完了するまで実行を続けても安全です。

出力には成功の情報が含まれ、挿入された最後のドキュメントのObjectIdが返されます。

Output
{ "acknowledged" : true, "insertedId" : ObjectId("61a38a4beedf737ac8e54e82") }

ドキュメントが正しく挿入されたことを確認するには、引数なしでcount()メソッドを実行し、コレクション内のドキュメントの数を取得します。

  1. db.accounts.count()
Output
1000000

このステップでは、パフォーマンスモニタリングに使用されるMongoDBのツールを説明するためにこのガイドで使用されるテストデータの例のリストが正常に作成されました。次のステップでは、基本的なサーバー使用状況統計を確認する方法について学びます。

ステップ2 — サーバー使用統計の確認

MongoDBは自動的に多くの有用なパフォーマンス統計を追跡します。これらを定期的にチェックすることは、データベースをモニタリングするための基本的な方法です。ただし、これらの統計はデータベースで何が起こっているかについてのリアルタイムな洞察を提供しませんが、データベースのパフォーマンスや即座の問題があるかどうかを判断するのに役立ちます。

警告: このガイドで説明されているMongoDBの監視コマンドは、データベースとそのパフォーマンスに関する機密情報を返します。このため、これらのコマンドの一部には高度な権限が必要です。

具体的には、このステップで説明されているserverStatus()メソッド、および次のステップで強調されているmongostatおよびmongotopコマンドは、これらを実行するにはclusterMonitorロールが付与されたユーザーが必要です。同様に、ステップ4で説明されているsetProfilingLevel()メソッドにはdbAdminロールが必要です。

前提条件のチュートリアル「Ubuntu 20.04でMongoDBをセキュリティ設定する方法」に従った場合、およびそのガイドで作成した管理ユーザーとしてMongoDBインスタンスに接続している場合、このガイドの例に従うためにこれらの追加の役割を付与する必要があります。

最初に、ユーザーの認証データベースに切り替えます。次の例では、これはadminですが、異なる場合は独自のユーザーの認証データベースに接続してください:

  1. use admin
Output
switched to db admin

次に、grantRolesToUser()メソッドを実行し、ユーザーにclusterMonitorロールとdbAdminロールを、accountsコレクションを作成したデータベースで付与します。次の例では、accountsコレクションがtestデータベースにあると仮定しています:

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [
  4. "clusterMonitor",
  5. { role : "dbAdmin", db : "test" }
  6. ]
  7. )

一般的には、特定の目的に専用のユーザープロファイルを持つことがセキュリティ上より安全とされています。これにより、ユーザーが不必要に広範な権限を持つことはありません。本番環境で作業している場合は、データベースを監視するためだけの専用ユーザーを持つことが望ましいかもしれません。

以下の例では、MongoDBユーザーMonitorSammyを作成し、このチュートリアルの例に従って操作するために必要な役割を付与します。このユーザーには、クラスター内の任意のデータベースにデータを読み取りおよび書き込む権限であるreadWriteAnyDatabaseロールも含まれていることに注意してください:

  1. db.createUser(
  2. {
  3. user: "MonitorSammy",
  4. pwd: passwordPrompt(),
  5. roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ]
  6. }
  7. )

適切なロールをユーザーに付与した後は、accountsコレクションが格納されているデータベースに戻ります:

  1. use test
Output
switched to db test

stats()メソッドを実行して、全体のデータベース統計を確認します:

  1. db.stats(1024*1024)

このメソッドの引数(1024*1024)は、スケールファクターであり、MongoDBにストレージ情報をメガバイト単位で返すよう指示します。これを省略すると、すべての値がバイト単位で表示されます。

stats()メソッドは、現在のデータベースに関連する重要な統計情報を短く簡潔に返します。

Output
{ "db" : "test", "collections" : 3, "views" : 0, "objects" : 1000017, "avgObjSize" : 80.8896048767171, "dataSize" : 77.14365005493164, "storageSize" : 24.109375, "indexes" : 4, "indexSize" : 9.9765625, "totalSize" : 34.0859375, "scaleFactor" : 1048576, "fsUsedSize" : 4238.12109375, "fsTotalSize" : 24635.703125, "ok" : 1 }

この出力は、このMongoDBインスタンスが格納しているデータの概要を提供します。この出力で返される以下のキーは特に役立ちます。

  • objectsキーには、データベース内のドキュメントの総数が表示されます。これを使用してデータベースのサイズを評価し、時間の経過とともに成長を観察することができます。
  • avgObjectSizeは、これらのドキュメントの平均サイズを示し、データベースが大きな複雑なドキュメントまたは小さなドキュメントで動作しているかどうかを示します。この値は常にバイト単位で表示されますが、スケールファクターを指定しているかどうかに関係なくです。
  • collectionsおよびindexesキーは、現在データベースで定義されているコレクションとインデックスの数を示します。
  • totalSizeキーは、データベースがディスク上でどれだけのストレージを使用しているかを示します。

stats()メソッドによって返されるこの情報は、現在のデータベースに格納されているデータの量を把握するのに役立ちますが、パフォーマンスや既存の問題についての洞察は提供しません。そのため、はるかに詳細なserverStatus()メソッドが役立ちます。

  1. db.serverStatus()

このメソッドの出力は長く、サーバーの使用状況に関する多くの情報を提供します。

Output
{ "host" : "ubuntu-mongo-rs", "version" : "4.4.6", "process" : "mongod", "pid" : NumberLong(658997), "uptime" : 976, . . . "ok" : 1 }

この情報はすべて有用である可能性がありますが、このガイドでは特に3つのセクションに焦点を当てます。まず、この出力のconnectionsセクションを見つけてください。

Output
. . . "connections" : { "current" : 4, "available" : 51196, "totalCreated" : 4, "active" : 2, "exhaustIsMaster" : 1, "exhaustHello" : 0, "awaitingTopologyChanges" : 1 }, . . .

各データベースサーバーは同時に接続できる数に限りがあります。currentキーは、現在データベースに接続しているクライアントの数を示し、availableはデータベースが利用可能な未使用の接続の数です。totalCreated値は、サーバーの起動から使用された接続の数を保持しています。

ほとんどのアプリケーションは既存の接続を再利用し、頻繁に複数の接続を開かないように設計されています。したがって、予期していない高い接続数は、クライアントがサーバーにアクセスする方法の誤配置の危険な兆候となる可能性があります。

もし高い接続数が行われる作業負荷の特性によって予期されている場合は、複数のMongoDBインスタンス間でトラフィックを分散するために、シャーディングされたクラスターに1つ以上のシャードを追加することを検討するかもしれません。

次に、出力のglobalLockセクションを見つけます。このセクションは、データベースサーバー全体のグローバルロックに関連しています。

Output
. . . "globalLock" : { "totalTime" : NumberLong(975312000), "currentQueue" : { "total" : 0, "readers" : 0, "writers" : 0 }, "activeClients" : { "total" : 0, "readers" : 0, "writers" : 0 } },

MongoDBは、複数の操作を実行する際にデータの一貫性を確保するためにロックを使用し、2つのクエリが同時に同じデータを変更しないことを保証します。使用が激しいサーバーでは、ロックがボトルネックを引き起こす可能性があり、1つ以上のクエリがロックが解除されるのを待って実行される前に待機することがあります。

currentQueue.total値は、クエリがロックが解除されるのを待機して実行できる数を示しています。この値が高い場合、データベースのパフォーマンスに影響があり、クエリの完了に時間がかかることを意味します。

これは、多くの長時間実行されるクエリがロックを保持しているために生じることがよくあり、インデックスの効果的な使用やクエリの設計の問題など、他の可能性を示している場合があります。

最後に、opcountersセクションを見つけます:

Output
"opcounters" : { "insert" : NumberLong(10000007), "query" : NumberLong(6), "update" : NumberLong(6), "delete" : NumberLong(0), "getmore" : NumberLong(0), "command" : NumberLong(1298) },

このserverStatus()の出力のセクションは、データベースサーバーが主に読み取りまたは書き込みに使用されているか、それともその使用がバランス良く行われているかを把握するのに役立ちます。この例では、テストドキュメントを挿入した後、insert操作のカウンターがquery操作よりもはるかに高いことが示されています。実生活のシナリオでは、これらの値はおそらく異なるでしょう。

書き込み重視のデータベースは、シャーディングを介して水平にスケーリングすることで利益を得ることができます。同様に、読み取り重視のMongoDBデータベースは通常、レプリケーションから利益を得るでしょう。

これらの統計は、サーバーがどのように使用されているかや、アクセス時に長いロック待ちキューなどのパフォーマンスの問題があるかどうかを全体的に把握するのに役立ちます。ただし、これらはサーバーのリアルタイムの使用状況に関する情報を提供しません。そのためには、mongostatおよびmongotopコマンドが有用です。

ステップ3 — mongostatmongotop を使用してリアルタイムのデータベース統計を取得する

使用されるコマンドで MongoDB のサーバー統計にアクセスすることは、サーバーが後でどのように使用されたかについての洞察を提供できますが、現時点でどのコレクションが最も活発に使用されているかやどのようなクエリが実行されているかのリアルタイム情報を提供することはできません。

MongoDB は、データベースの活動を分析し、提供される情報を継続的に更新するリアルタイムモニタリングに役立つ2つのシステムツールを提供しています: mongostatmongotopmongostat は MongoDB インスタンスの現在の状態の簡単な概要を提供し、mongotop はインスタンスが読み取りと書き込み操作に費やす時間を追跡します。これらのツールは、MongoDB シェルではなく、コマンドラインから実行されます。

mongostat を使用するには、現在の MongoDB シェル接続を維持し、別のターミナルウィンドウを開いてサーバーシェルにアクセスします。2番目のサーバーシェルで、mongostat コマンドを実行します:

  1. mongostat -u AdminSammy --authenticationDatabase admin

以前に述べたように、mongostatには高度な権限が必要です。 MongoDBインスタンスで認証を有効にし、適切な役割を持つユーザーを設定した場合、そのユーザーとして認証する必要があります。ユーザー名と認証データベース(この例に示すように)を提供し、プロンプトが表示されたらそのユーザーのパスワードを入力します。

デフォルトの構成では、mongostatは現在実行中のクエリのカウンターを1秒ごとに出力します。

Output
insert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.4k 7 Nov 28 15:40:40.621 *0 *0 *0 *0 0 2|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 224b 84.8k 7 Nov 28 15:40:41.619 *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.5k 7 Nov 28 15:40:42.621 *0 *0 *0 *0 0 3|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 365b 85.0k 7 Nov 28 15:40:43.619

mongostatの出力に特定のクエリタイプの値が0と表示される場合、データベースはそのタイプの操作を実行していないことを示します。この例の出力は、各クエリタイプに0が表示されており、現在アクティブに実行されているクエリはありません。

まだ最初のターミナルウィンドウが開いており、MongoDBシェルに接続されている必要があります。 accountsコレクションにさらにいくつかのテストドキュメントを挿入し、mongostatがアクティビティを検出するかどうかを確認してください。

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "2000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

これは、Step 1で実行したのと似たようなfor-ループですが、今回はループがエントリーを10000個しか挿入しません。アカウント番号は2000で始まり、通貨は常にUSDです。

新しいドキュメントが挿入されている間に、mongostatの出力を確認してください。

Output
. . . *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 112b 42.5k 4 Nov 28 15:50:33.294 *0 *0 *0 *0 0 0|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:34.295 755 *0 *0 *0 0 1|0 0.1% 38.8% 0 1.54G 210M 0|0 1|0 154k 79.4k 4 Nov 28 15:50:35.294 2853 *0 *0 *0 0 0|0 0.4% 39.1% 0 1.54G 211M 0|0 1|0 585k 182k 4 Nov 28 15:50:36.295 2791 *0 *0 *0 0 1|0 0.7% 39.4% 0 1.54G 212M 0|0 1|0 572k 179k 4 Nov 28 15:50:37.293 2849 *0 *0 *0 0 0|0 1.0% 39.7% 0 1.54G 213M 0|0 1|0 584k 182k 4 Nov 28 15:50:38.296 745 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 153k 79.2k 4 Nov 28 15:50:39.294 *0 *0 *0 *0 0 0|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:40.295 *0 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 167b 42.7k 4 Nov 28 15:50:41.293 . . .

クエリが実行されている間、mongostatによって返される新しい行には、0以外の値が表示されるようになります。データベースに新しいデータを挿入するクエリの数を示すinsert列では、数秒間値が高くなりました。 mongostatは1秒間隔でデータを表示するので、他の種類のデータベース操作に対する挿入の割合だけでなく、データベースが新しいデータを挿入する速度もわかります。この例では、サーバーはほぼ秒間3000件の挿入を達成しました。

mongostatを使用して、クエリの種類ごとにデータベースサーバーの現在のワークロードを監視できます。MongoDBが提供する2番目のツールであるmongotopは、コレクションごとにグループ化されたデータベースサーバーのアクティビティを表示します。

mongostatを2番目のターミナルウィンドウで実行を停止するには、CTRL + Cを押します。その後、同じターミナルでmongotopを実行します。同様に、認証が有効になっている場合は、適切な特権を持つユーザーとして認証する必要があります。

  1. mongotop -u AdminSammy --authenticationDatabase admin

mongotopは、データベース内のすべてのコレクションのリストと、時間ウィンドウ内の読み取り、書き込み、および合計で費やした時間を出力します。 mongostatと同様に、出力は1秒ごとに更新されます。

Output
2021-11-28T15:54:42.290+0000 connected to: mongodb://localhost/ ns total read write 2021-11-28T15:54:43Z admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms test.accounts 0ms 0ms 0ms . . .

mongotopでアクティビティが登録されるかどうかを確認するために、データベースにさらにいくつかのドキュメントを挿入してみてください。MongoDBシェルで次のforループを実行した後、mongotopが実行されているターミナルウィンドウを観察してください。

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "3000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

この時点では、mongotopの統計情報にアクティビティが表示されます。

Output
. . . ns total read write 2021-11-28T15:57:27Z test.accounts 127ms 0ms 127ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms ns total read write 2021-11-28T15:57:28Z test.accounts 130ms 0ms 130ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms . . .

ここでは、mongotop が、test データベースの accounts コレクションでのすべてのデータベースアクティビティが発生し、時間ウィンドウ内のすべての操作が書き込み操作であることを示しています。すべてこれは、実行した for ループ操作と一致するはずです。

MongoDB のデータベースプロファイラを使用して遅いクエリを特定する

データベースのパフォーマンスボトルネックはさまざまな原因から発生する可能性があります。データベースのスケーリング(水平または垂直のどちらか)がパフォーマンスボトルネックの解決策であることがしばしばありますが、その原因は実際にはデータベースの制限ではなく、スキーマやクエリ設計の問題である場合もあります。

クエリが長時間実行される場合、その原因はインデックスの効率的な使用やクエリ自体のエラーかもしれません。長時間実行されるクエリは、通常、テストデータセットが小さすぎるか、条件が本番環境と異なるため、アプリケーション開発中に見逃されることがよくあります。

犯人を見つける方法の一つとして、テストクエリを手動で実行し、どのクエリが性能が低いかをチェックすることができますが、これは非常に手間がかかります。幸いなことに、MongoDBのデータベースプロファイラツールがこれを自動的に行うことができます。

MongoDBのデータベースプロファイラは、特定の条件に一致する場合にクエリとその実行に関する統計情報を記録することができます。これらの条件の中で最も重要なのは、クエリの実行時間です。クエリの実行に指定された時間よりも長くかかる場合、プロファイラはそのクエリを自動的に問題のあるものとしてフラグ付けします。プロファイラを使用すると、性能が低いクエリを特定し、その特定の問題に焦点を当てて修正することができます。

プロファイラを使用する前に、次のクエリを実行してください。このクエリは、挿入したアカウントの1つを取得しますが、最初の見た目ほど単純ではありません:

  1. db.accounts.find({"number": "1000-20"})

コマンドは、指定したアカウントを正確に取得します:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

クエリがすぐに実行されなかったことに気づいたかもしれません。MongoDBがアカウントを見つけるのに数秒かかりました。実際のアプリケーションでは、性能が低いさまざまな種類のクエリがあり、実践ではその性能低下に気付かないかもしれません。

予想よりも時間がかかるクエリを特定するのを助けるようにMongoDBを設定することができます。それを行うには、まず次のコマンドを実行してプロファイラを有効にします:

  1. db.setProfilingLevel(1, { slowms: 100 })

setProfilingLevel()メソッドには2つの引数があります。最初はプロファイリングレベルで、01、または2のいずれかです:

  • 0はプロファイラを無効にします
  • 1は条件を満たす遅いクエリのみにプロファイラを有効にします
  • 2 はすべてのクエリに対してプロファイラを有効にします。

この例では、プロファイラは第二引数 { slowms: 100 } で定義されたように、100ミリ秒以上かかるクエリを解析します。

注意: プロファイラを使用するとパフォーマンスが低下します。MongoDB はクエリを実行するだけでなく、解析する必要があります。パフォーマンスのボトルネックを監視する際には慎重に使用する必要があります。

プロファイラがログに記録するクエリのサブセットをさらに細かく設定することができ、クエリの一定割合のみをプロファイリングしたり、クエリのタイプでフィルタリングしたりすることができます。プロファイラに対するより細かな制御方法について詳しくは、公式ドキュメントを参照してください。

このメソッドは成功メッセージを返します:

Output
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

これにより、データベースのプロファイリングが有効になり、MongoDB が実行するすべてのクエリをアクティブに監視し、100ミリ秒以上かかるクエリを見つけます。

いくつかの異なるクエリを実行して試してみてください。まず、accounts コレクション内のドキュメント数を検索するために count コマンドを使用してください。

  1. db.accounts.count()

このコマンドはコレクション内のドキュメント数を迅速に返します:

Output
1020000

次に、コレクション内で最初の3つの銀行口座を検索してみてください。

  1. db.accounts.find().limit(3)

再度、データベースは結果を迅速に返します:

Output
{ "_id" : ObjectId("61ef40640f2ba52efc56ee17"), "number" : "1000-1", "currency" : "EUR", "balance" : 25393.132960293842 } { "_id" : ObjectId("61ef40640f2ba52efc56ee18"), "number" : "1000-2", "currency" : "EUR", "balance" : 63629.42056192393 } { "_id" : ObjectId("61ef40640f2ba52efc56ee19"), "number" : "1000-3", "currency" : "EUR", "balance" : 75602.12331602155 }

最後に、特定の銀行口座の検索クエリを再実行してください:

  1. db.accounts.find({"number": "1000-20"})

このクエリは結果を返しますが、以前と同様に、前の操作よりも少し時間がかかります:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

プロファイラーは自分自身の出力を生成しませんが、クエリは目に見えるほど遅くなりました。代わりに、遅い操作に関する詳細は、データベース内の特別なコレクションに登録されます。その名前はsystem.profileです。このコレクションは、常に1 MBを超えないようにするキャップ付きのコレクションです。つまり、常に最新の遅いクエリのリストのみを含みます。

プロファイラーによって識別されたクエリに関する情報を取得するには、次のようにsystem.profileコレクションをクエリする必要があります:

  1. db.system.profile.find().sort({ "ts" : -1 }).pretty()

このクエリは、通常のようにfind()メソッドを使用しています。さらに、引数として{ "ts" : -1 }を含むsort句も含まれています。これにより、結果セットが最新のクエリでソートされます。最後に、最後にpretty()メソッドが出力をより読みやすい形式で表示します。

各遅いクエリは通常のドキュメントとして表され、system.profileは通常のコレクションと同様です。つまり、結果をフィルタリングしたり、ソートしたり、さらにクエリのリストを絞ったり分析するための集計パイプラインで使用したりすることができます。

結果は単一のドキュメントのみであることに注意してください。他の2つのクエリはプロファイラーをトリガーしないほど速く実行されました:

Output
{ "op" : "query", "ns" : "test.accounts", "command" : { "find" : "accounts", "filter" : { "number" : "1000-20" }, . . . }, "nreturned" : 1, "keysExamined" : 0, "docsExamined" : 1030000, . . . "millis" : 434, "planSummary" : "COLLSCAN", . . . }

この出力には、遅いクエリの実行に関する多くの詳細が含まれています。

  • opキーは、この情報がどのような操作を表しているかを示します。ここでは、find()を使用してデータベースからデータを取得する操作を表しているので、queryです。
  • nsキーは、操作に関与したデータベースとコレクションを示します。出力からわかるように、この操作はtestデータベースのaccountsコレクションをクエリしました。
  • commandキーは、クエリ自体に関するさらなる情報を提供します。この場合、filterサブキーにはフィルター文書全体が含まれています。opおよびcommandフィールドからの情報を使用して、問題のクエリを再構築できます。
  • millisフィールドには、クエリの完了にかかった正確な時間が記載されています。この例では、ほぼ0.5秒です。
  • docsExaminedフィールドには、結果セットを返すためにスキャンされたドキュメントの数が表示されます。
  • nreturnedはクエリが返したドキュメントの数を表します。この例では、100万以上のスキャンから1つのドキュメントのみが返されました。
  • planSummaryには、MongoDBがクエリを実行するために使用したメソッドが表示されます。COLLSCANは、フルコレクションスキャンに対応し、つまり一致する銀行口座を見つけるためにコレクション内のすべてのドキュメントを一つずつ参照しました。

すべての情報は、このクエリをMongoDBがより速く実行できるようにするインデックスの必要性を強調しています。データベースは、検査された文書の数と返された文書の数、および実行戦略の間の大きな違いから示されるように、単一の文書を見つけるためにコレクション全体を見る必要がありました。

この具体的な例では、numberフィールドに基づいてデータをフィルタリングするクエリをサポートするインデックスを作成することで、この種のクエリのパフォーマンスが直ちに向上します。実際のシナリオでは、遅いクエリの解決策は異なる場合があり、問題を引き起こしている正確なクエリに依存します。

プロファイリングセッションを終了するには、プロファイラを無効にしてプロファイリングレベルをゼロに設定します:

  1. db.setProfilingLevel(0)

操作は確認メッセージとともに成功します:

Output
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

これで、データベースは裏でプロファイリングを行わずに通常の動作に戻ります。

遅いクエリがデータベースのパフォーマンスに悪影響を与えている可能性がある場合は、データベースプロファイラを使用してそれらを見つけ、その構造と実行方法をよりよく理解することができます。この情報を元に、それらを調整してパフォーマンスを向上させる準備ができます。

結論

このガイドに従うことで、MongoDBのサーバー統計情報を見つける方法や、mongotopmongostatなどの診断ツールの使用方法、さらにはMongoDBのデータベースプロファイラ機構の使用方法を学びました。これらを使用すると、データベースのワークロードをより良く把握し、どのコレクションが最もアクティブであるか、サーバーが主に書き込みまたは読み取りを行っているかを判断できます。また、MongoDBのパフォーマンスに影響を与えている遅いクエリを特定し、より効率的なものに置き換えることができます。

これらは、MongoDBインストールの健全性とパフォーマンスを監視し、それに対処するための選択されたツールと技術に過ぎません。これらのツールはそれぞれ、サーバーパフォーマンスに対するよりターゲットを絞った洞察を提供するためにさらに設定およびカスタマイズできます。MongoDBの公式ドキュメントを研究して、サーバーパフォーマンスを監視し、それに対処するために使用できる技術についてさらに学ぶことをお勧めします。

Source:
https://www.digitalocean.com/community/tutorials/how-to-monitor-mongodb-s-performance