MongoDBのパフォーマンスを監視する方法
著者は、 Open Internet / Free Speech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
監視は、データベースのパフォーマンスと全体的な状態を理解できるため、データベース管理の重要な部分です。 データベースのパフォーマンスを監視することで、現在の容量をより正確に把握し、時間の経過とともにワークロードがどのように変化するかを観察し、データベースが限界に近づき始めたら、データベースを拡張する計画を立てることができます。 また、根本的なハードウェアの問題や、データベース使用の予期しない急増などの異常な動作に気付くのにも役立ちます。 最後に、監視は、ボトルネックの原因となるアプリケーションクエリなど、データベースを使用するアプリケーションの問題を診断するのに役立ちます。
MongoDB には、データベースのパフォーマンスを監視するために使用できるさまざまなツールとユーティリティがインストールされています。 このチュートリアルでは、組み込みのコマンドとツールを使用して、データベースメトリックをオンデマンドで監視する方法を学習します。 また、最適化が不十分なクエリを検出するのに役立つMongoDBのデータベースプロファイラーについても理解できます。
前提条件
このチュートリアルに従うには、次のものが必要です。
sudo
権限を持つ通常の非rootユーザーと、UFWで構成されたファイアウォールを備えたサーバー。 このチュートリアルは、Ubuntu 20.04を実行しているサーバーを使用して検証されており、Ubuntu20.04のこの初期サーバーセットアップチュートリアルに従ってサーバーを準備できます。- サーバーにインストールされているMongoDB。 これを設定するには、 Ubuntu20.04にMongoDBをインストールする方法に関するチュートリアルに従ってください。
- 認証を有効にして管理ユーザーを作成することにより、サーバーのMongoDBインスタンスを保護します。 このようにMongoDBを保護するには、 Ubuntu20.04でMongoDBを保護する方法に関するチュートリアルに従ってください。
- MongoDBコレクションのクエリと結果のフィルタリングに精通していること。 MongoDBクエリの使用方法については、MongoDBでクエリを作成する方法に関するガイドに従ってください。
注:サーバーの構成方法、MongoDBのインストール方法、およびMongoDBのインストールを保護する方法に関するリンクされたチュートリアルは、Ubuntu20.04を参照しています。 このチュートリアルは、基盤となるオペレーティングシステムではなく、MongoDB自体に焦点を当てています。 通常、認証が有効になっている限り、オペレーティングシステムに関係なく、すべてのMongoDBインストールで機能します。
ステップ1—テストデータの準備
MongoDBのパフォーマンスを監視する方法を説明するために、このステップでは、MongoDBシェルを開いて、ローカルにインストールされたMongoDBインスタンスに接続し、その中にサンプルコレクションを作成する方法の概要を説明します。
このガイドで使用するサンプルコレクションを作成するには、管理ユーザーとしてMongoDBシェルに接続します。 このチュートリアルは、前提条件 MongoDBセキュリティチュートリアルの規則に従い、この管理ユーザーの名前が AdminSammy であり、その認証データベースがadmin
であることを前提としています。 異なる場合は、次のコマンドでこれらの詳細を変更して、独自の設定を反映させてください。
- mongo -u AdminSammy -p --authenticationDatabase admin
インストール中に設定したパスワードを入力して、シェルにアクセスします。 パスワードを入力すると、>
プロンプトサインが表示されます。
注:新しい接続では、MongoDBシェルはデフォルトでtest
データベースに接続します。 このデータベースを安全に使用して、MongoDBとMongoDBシェルを試すことができます。
または、別のデータベースに切り替えて、このチュートリアルに記載されているすべてのコマンド例を実行することもできます。 別のデータベースに切り替えるには、use
コマンドに続けて、データベースの名前を実行します。
- use database_name
データベースシステムは、特定のクエリに対して少数のレコードをスキャンするだけでよいため、小さなデータセットを操作する場合、データベースの監視はあまり実用的でも有用でもありません。 MongoDBのパフォーマンス監視機能を説明するには、MongoDBがクエリを実行するのにかなりの時間がかかるのに十分なデータを備えたデータベースが必要です。
この目的のために、このガイド全体の例では、多数のドキュメントを含むaccounts
という名前のサンプルコレクションを参照しています。 各ドキュメントは、ランダムに生成された口座残高を持つ個々の銀行口座を表します。 コレクション内の各ドキュメントは、次のような構造になります。
{
"number": "1000-987321",
"currency": "USD",
"balance": 431233431
}
このサンプルドキュメントには、次の情報が含まれています。
number
:このフィールドは、指定されたアカウントのアカウント番号を表します。 このコレクションでは、各アカウント番号のプレフィックスは1000-
で、その後に増分する数値識別子が続きます。currency
:このフィールドは、各アカウントの残高が保存されている通貨の種類を示します。 各アカウントのcurrency
の値は、USD
またはEUR
のいずれかになります。balance
:これは特定の各銀行口座の残高を示します。 このサンプルデータベースでは、各ドキュメントのbalance
フィールドにランダムに生成された値が含まれます。
多数のドキュメントを手動で挿入するのではなく、次のJavaScriptコードを実行して、accounts
という名前のコレクションを同時に作成し、そのようなドキュメントを100万個挿入することができます。
- for (let i = 1; i <= 1000000; ++i) {
- db.accounts.insertOne({
- "number": "1000-" + i,
- "currency": i > 500000 ? "USD" : "EUR",
- "balance": Math.random() * 100000
- })
- }
このコードは、100万回連続して実行されるfor
ループを実行します。 ループが繰り返されるたびに、アカウントコレクションでinsertOne()
メソッドを実行して、新しいドキュメントを挿入します。 各反復で、メソッドは1000-
プレフィックスで構成されるnumber
フィールドに値を与え、その値はその反復のi
値に保持されます。 これは、このループが最初に繰り返されるときに、number
フィールド値が1000-1
に設定されることを意味します。 最後に繰り返すときは、1000-1000000
に設定されます。
通貨は、500000より大きい番号のアカウントの場合は常にUSD
として表され、それより小さい番号のアカウントの場合はEUR
として表されます。 バランスフィールドは、Math.random()
関数を使用して0〜1の乱数を生成し、その乱数に100000を掛けて、より大きな値を提供します。
注:このループの実行には、10分を超える場合でも長い時間がかかる場合があります。 終了するまで操作を実行したままにしておくのが安全です。
出力は成功を通知し、最後に挿入されたドキュメントのObjectId
を返します。
Output{
"acknowledged" : true,
"insertedId" : ObjectId("61a38a4beedf737ac8e54e82")
}
引数なしでcount()
メソッドを実行すると、ドキュメントが正しく挿入されたことを確認できます。これにより、コレクション内のドキュメントの数が取得されます。
- db.accounts.count()
Output1000000
このステップでは、MongoDBがパフォーマンス監視のために提供するツールを説明するために、このガイドで使用されるテストデータとして機能するサンプルドキュメントのリストを正常に作成しました。 次のステップでは、基本的なサーバー使用統計を確認する方法を学習します。
ステップ2—サーバー使用統計の確認
MongoDBは、いくつかの有用なパフォーマンス統計を自動的に追跡します。これらを定期的にチェックすることは、データベースを監視するための基本的な方法です。 これらの統計は、データベースで何が起こっているかについてのリアルタイムの洞察を提供しないことに注意してください。ただし、データベースのパフォーマンスや差し迫った問題があるかどうかを判断するのに役立ちます。
警告:このガイドで概説されているMongoDBモニタリングコマンドは、データベースとそのパフォーマンスに関する機密情報を返す可能性があります。 このため、これらのコマンドの一部には高度な権限が必要です。
具体的には、このステップで概説したserverStatus()
メソッドと、次のステップで強調表示されているmongostat
およびmongotop
コマンドはすべて、ユーザーにclusterMonitor
が付与されている必要があります。 ]それらを実行するための役割。 同様に、ステップ4で概説したsetProfilingLevel()
メソッドには、dbAdmin
ロールが必要です。
Ubuntu 20.04 でMongoDBを保護する方法の前提条件のチュートリアルに従い、そのガイドで作成した管理ユーザーとしてMongoDBインスタンスに接続している場合は、これらの追加の役割を付与して、このガイドの例。
まず、ユーザーの認証データベースに切り替えます。 これは次の例ではadmin
ですが、異なる場合は自分のユーザーの認証データベースに接続します。
- use admin
Outputswitched to db admin
次に、grantRolesToUser()
メソッドを実行し、accounts
コレクションを作成したデータベースに対してdbAdmin
ロールとともにclusterMonitor
ロールをユーザーに付与します。 次の例では、accounts
コレクションがtest
データベースにあると想定しています。
- db.grantRolesToUser(
- "AdminSammy",
- [
- "clusterMonitor",
- { role : "dbAdmin", db : "test" }
- ]
- )
一般に、特定の目的専用のユーザープロファイルを使用する方が安全であると考えられていることに注意してください。 このようにして、ユーザーが不必要に幅広い特権を持つことはありません。 実稼働環境で作業している場合は、データベースの監視を唯一の目的とする専用ユーザーが必要になる場合があります。
次の例では、 MonitorSammy という名前のMongoDBユーザーを作成し、このチュートリアルの例に沿って従うために必要な役割をユーザーに付与します。 readWriteAnyDatabase
ロールも含まれていることに注意してください。これにより、このユーザーはクラスター内の任意のデータベースに対してデータの読み取りと書き込みを行うことができます。
- db.createUser(
- {
- user: "MonitorSammy",
- pwd: passwordPrompt(),
- roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ]
- }
- )
ユーザーに適切な役割を付与した後、accounts
コレクションが保存されているデータベースに戻ります。
- use test
Outputswitched to db test
stats()
メソッドを実行して、データベース全体の統計を確認することから始めます。
- 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()
メソッドが役立ちます。
- 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
値は、サーバーの起動から使用された接続の数を保持します。
ほとんどのアプリケーションは、既存の接続を再利用するように設計されており、複数の接続を頻繁に開くことはありません。 したがって、接続数が多い場合は、予期しない場合でも、クライアントがサーバーにアクセスする方法が正しく構成されていないことを示す警告となる可能性があります。
実行されるワークロードの特性によって多数の接続が予想される場合は、1つ以上のシャードをシャードクラスターに追加して、複数のMongoDBインスタンスにトラフィックを分散することを検討してください。
次に、出力の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—mongostat
およびmongotop
を使用してリアルタイムデータベース統計を取得する
MongoDBのサーバー統計にアクセスするために使用されるコマンドは、サーバーがどのように使用されているかを振り返って洞察を提供できますが、現在最もアクティブに使用されているコレクションや実行されているクエリの種類に関するリアルタイムの情報を提供することはできません。
MongoDBは、データベースアクティビティを分析し、提供する情報を継続的に更新する、リアルタイム監視用の2つの便利なシステムツールmongostat
とmongotop
を提供します。 mongostat
は、MongoDBインスタンスの現在のステータスの概要を提供し、mongotop
は、インスタンスが読み取りおよび書き込み操作に費やした時間を追跡します。 これらのツールは両方とも、MongoDBシェルではなく、コマンドラインから実行されます。
mongostat
を使用するには、現在のMongoDBシェル接続を維持し、別のターミナルウィンドウを開いてサーバーシェルにアクセスします。 2番目のサーバーシェルで、mongostat
コマンドを実行します。
- mongostat -u AdminSammy --authenticationDatabase admin
前述のように、mongostat
には高度な権限が必要です。 MongoDBインスタンスで認証を有効にし、適切なロールを持つユーザーを設定した場合は、ユーザー名と認証データベース(この例を参照)を提供し、プロンプトが表示されたらパスワードを入力して、そのユーザーとして認証する必要があります。 。
デフォルトの構成では、mongostat
は、現在実行されているクエリのカウンターを1秒間隔で出力します。
Outputinsert 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
がアクティビティに気付くかどうかを確認します。
- for (let i = 1; i <= 10000; ++i) {
- db.accounts.insertOne({
- "number": "2000-" + i,
- "currency": "USD",
- "balance": Math.random() * 100000
- })
- }
これは、ステップ1で実行したものと同様のfor
ループです。 ただし、今回は、ループは10000エントリのみを挿入します。 アカウント番号の前には2000
が付いており、通貨は常に米ドルです。
新しいドキュメントが挿入されている間に、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秒間隔でデータを表示するため、他の種類のデータベース操作に対する挿入の割合だけでなく、データベースが新しいデータを挿入する速度も確認できます。 この例では、サーバーは1秒あたり約3000回の挿入を達成しました。
mongostat
を使用して、クエリタイプごとにグループ化されたデータベースサーバーの現在のワークロードを監視できます。 MongoDBに付属する2番目のツール— mongotop
—は、コレクションごとにグループ化されたデータベースサーバーのアクティビティを表示します。
CTRL + C
を押して、mongostat
が2番目のターミナルウィンドウで実行されないようにします。 次に、同じ端末でmongotop
を実行します。 ここでも、認証を有効にしている場合は、適切な特権を持つユーザーとして認証する必要があります。
- mongotop -u AdminSammy --authenticationDatabase admin
mongotop
は、データベース内のすべてのコレクションのリストを、読み取り、書き込み、および時間枠内の合計に費やされた時間とともに出力します。 mongostat
と同様に、出力は1秒ごとに更新されます。
Output2021-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
が実行されているターミナルウィンドウを確認します。
- for (let i = 1; i <= 10000; ++i) {
- db.accounts.insertOne({
- "number": "3000-" + i,
- "currency": "USD",
- "balance": Math.random() * 100000
- })
- }
今回は、アクティビティが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
ループ操作と一致している必要があります。
mongostat
と同様に、CTRL + C
を押すと、mongotop
の実行を停止できます。
ピーク負荷時に観察された場合、mongotop
を使用して、データベースアクティビティがさまざまなコレクションにどのように分散するかを監視し、スキーマの理解とスケーリングの計画に役立てることができます。 また、コレクションの使用量が読み取りまたは書き込みを多用するかどうかについての洞察も提供します。
ステップ4—MongoDBのデータベースプロファイラーを使用して低速クエリを特定する
データベースパフォーマンスのボトルネックは、多くの原因から発生する可能性があります。 多くの場合、データベースのスケーリング(水平または垂直)がパフォーマンスのボトルネックの解決策ですが、その原因は実際にはデータベースの制限ではなく、スキーマまたはクエリの設計に問題がある可能性があります。
クエリの実行時間が長すぎる場合は、クエリ自体でインデックスが効果的に使用されていないか、エラーが発生している可能性があります。 通常、テストデータセットが小さすぎるか、本番環境とは条件が異なるため、アプリケーション開発中に長時間実行されるクエリが監視されることがよくあります。
テストクエリを手動で実行し、どのクエリがパフォーマンスを低下させているかを確認することで、原因を見つけることができる可能性がありますが、これは非常に面倒です。 幸い、MongoDBのデータベースプロファイラーツールはそれを自動的に行うことができます。
MongoDBのデータベースプロファイラーは、特定の条件に一致した場合に、実行に関するクエリと統計をログに記録できます。 これらの条件の中で最も重要なのは、クエリの実行時間です。クエリの実行に指定された時間がかかる場合、プロファイラーはそのクエリに問題があるとして自動的にフラグを立てます。 プロファイラーを使用すると、パフォーマンスが低いクエリを特定し、それらの特定の問題の修正に集中できます。
プロファイラーを使用する前に、次のクエリを実行してください。 このクエリは、挿入したアカウントの1つを取得しますが、一見しただけでは簡単ではありません。
- db.accounts.find({"number": "1000-20"})
このコマンドは、要求した正確なアカウントを取得します。
Output{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }
クエリがすぐに実行されなかったことに気付いたかもしれません。MongoDBがアカウントを見つけるのに1、2分かかりました。 実際のアプリケーションでは、パフォーマンスの低い多くの種類のクエリが存在する可能性があり、実際にはそれらのパフォーマンスの低下に気付かない場合があります。
MongoDBを構成して、予想よりも時間がかかるクエリを特定することができます。 これを行うには、最初に次のコマンドを実行してプロファイラーを有効にします。
- db.setProfilingLevel(1, { slowms: 100 })
setProfilingLevel()
メソッドは2つの引数を取ります。 1つ目はプロファイリングレベルで、0
、1
、または2
のいずれかになります。
0
はプロファイラーを無効にします1
は、条件を満たす遅いクエリでのみプロファイラーを有効にします2
は、すべてのクエリに対してプロファイラーを有効にします
この例では、プロファイラーは、2番目の引数{ slowms: 100 }
で定義されているように、100ミリ秒より長く実行されるクエリを分析します。
注: MongoDBはクエリの実行に加えてクエリを分析する必要があるため、プロファイラーを使用するとパフォーマンスが低下します。 パフォーマンスのボトルネックを監視する場合は、慎重に使用する必要があります。
プロファイラーがログに記録するクエリのサブセットを、特定の割合のクエリのみをプロファイリングするように構成するか、クエリタイプでフィルタリングすることにより、さらに調整することができます。 プロファイラーをより細かく制御する方法の詳細については、主題に関する公式ドキュメントを参照してください。
このメソッドは成功メッセージを返します:
Output{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
今後、データベースプロファイリングが有効になり、MongoDBは実行するすべてのクエリをアクティブに監視して、完了するまでに100ミリ秒以上かかるクエリを見つけます。
いくつかの異なるクエリを実行して、これを試してください。 まず、count
コマンドを使用して、accounts
コレクション内のドキュメントの数を見つけます。
- db.accounts.count()
このコマンドは、コレクション内のドキュメントの数をすばやく返します。
Output1020000
次に、コレクションに表示されている最初の3つの銀行口座を調べてみてください。
- 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 }
最後に、特定の銀行口座の検索クエリをもう一度実行します。
- db.accounts.find({"number": "1000-20"})
このクエリは結果を返しますが、以前と同様に、前の操作よりも1〜2分長くかかります。
Output{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }
クエリが明らかに遅い場合でも、プロファイラーは独自の出力を生成しません。 代わりに、低速操作に関する詳細は、system.profile
という名前のデータベース内の特別なコレクションに登録されます。 このコレクションは、サイズが1MBを超えることのない上限付きコレクションです。 つまり、常に最新の低速クエリのみのリストが含まれます。
プロファイラーによって識別されたクエリに関する情報を取得するには、次のような方法でsystem.profile
コレクションをクエリする必要があります。
- 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
キーは、この情報がどのような操作を表すかを示します。 ここでは、query
です。これは、find()
を使用してデータベースからデータを取得する操作を表しているためです。ns
キーは、操作に関与したデータベースとコレクションを示します。 出力が示すように、この操作はtest
データベースのaccounts
コレクションを照会しました。command
キーは、クエリ自体に関する詳細情報を提供します。 この場合、filter
サブキーにはフィルタードキュメント全体が含まれます。op
およびcommand
フィールドからの情報を使用して、問題のクエリを再構築できます。millis
フィールドには、クエリの完了にかかった正確な時間が表示されます。 この例では、ほぼ0.5秒です。docsExamined
フィールドは、結果セットを返すためにスキャンされたドキュメントの数を提供します。nreturned
は、クエリが返したドキュメントの数を表します。 この例では、スキャンされた100万を超えるドキュメントのうち1つのドキュメントのみが返されました。planSummary
は、MongoDBがクエリの実行に使用したメソッドを示しています。COLLSCAN
は完全なコレクションスキャンに対応します。つまり、コレクション内のすべてのドキュメントを1つずつ参照して、一致する銀行口座を見つけます。
全体として、この情報は、MongoDBがこのクエリをより高速に実行するのに役立つインデックスの必要性を強調しています。 調査されたドキュメントと返されたドキュメントの数の大きな違い、および実行戦略によって示されるように、データベースはコレクション全体を調べて単一のドキュメントを見つける必要がありました。
この特定の例では、number
フィールドに基づいてデータをフィルタリングするクエリをサポートするインデックスを作成すると、これらの種類のクエリのパフォーマンスが即座に向上します。 実際のシナリオでは、遅いクエリの解決策は異なり、問題を引き起こしている正確なクエリによって異なります。
プロファイリングセッションを終了するには、プロファイリングレベルをゼロに設定して、プロファイラーを無効にします。
- db.setProfilingLevel(0)
操作は確認メッセージで成功します:
Output{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
これで、データベースは通常の操作に戻り、バックグラウンドでプロファイリングは行われません。
遅いクエリがデータベースのパフォーマンスに悪影響を及ぼしていると思われる場合は、データベースプロファイラーを使用してクエリを見つけ、その構造と実行方法をよりよく理解できます。 この情報を使用すると、それらを調整してパフォーマンスを向上させるための準備が整います。
結論
このガイドに従うことで、MongoDBのサーバー統計を見つける方法、mongotop
、mongostat
などの診断ツール、およびMongoDBのデータベースプロファイラーメカニズムの使用方法を学びました。 これらを使用して、データベースのワークロードをより正確に把握し、どのコレクションが最もアクティブであるか、およびサーバーが主に書き込みと読み取りのどちらを実行するかを判断できます。 また、MongoDBのパフォーマンスに影響を与えている低速のクエリを特定して、より効率的なクエリに置き換えることもできます。
これらは、MongoDBインストールの正常性とパフォーマンスを監視し、それに基づいて動作するために使用できるツールと手法のほんの一部です。 これらの各ツールをさらに構成およびカスタマイズして、サーバーのパフォーマンスに関するより的を絞った洞察を提供できます。 公式のMongoDBドキュメントを調べて、サーバーのパフォーマンスを監視し、それに基づいて行動するために使用できる手法について学ぶことをお勧めします。