Docs Menu
Docs Home
/ / /
Rust ドライバー
/

パフォーマンスに関する考慮事項

項目一覧

  • Overview
  • クライアントのライフサイクル
  • 接続プール
  • 最大プール サイズの設定
  • 同時接続オプションの構成
  • 最大アイドル時間の設定
  • 並列処理
  • ランタイム
  • 詳細情報
  • API ドキュメント

このガイドでは、Rust ドライバーのパフォーマンスを最適化する方法を学習できます。 MongoDB に接続するには、 Clientインスタンスを作成する必要があります。 Clientインスタンスは、サーバー トポロジーの検出、接続のモニタリング、内部接続プールの維持など、接続のほとんどの要素を自動的に処理します。 このガイドでは、 Clientインスタンスの構成と使用に関するベストプラクティスについて説明します。

このガイドには、次のセクションが含まれています。

  • クライアント ライフサイクルでは、 Clientインスタンスの作成と管理に関するベストプラクティスについて説明します。

  • 接続プールは、ドライバーでの接続プーリングの仕組みを説明します

  • 並列処理では、タスクを並行して実行するためのサンプルコードが提供されます

  • Runtimeでは、 tokio作成とasync_std作成の機能を使用してランタイムを管理する方法について説明しています。

  • 追加情報では、このガイドで言及されている型とメソッドのリソースとAPIドキュメントへのリンクを提供します

クライアントは複数のセッションやオペレーションで再利用することをお勧めします。 同じClientインスタンスを使用して複数のタスクを実行できます。 Client型は複数のスレッドで安全に同時使用できます。 リクエストごとに新しいClientインスタンスを作成すると、パフォーマンスが低下します。

次のコードでは、既存のClientインスタンスへのポインターを受け入れるメソッドが作成されます。これにより、同じクライアントを使用して多くのリクエストを実行できます。

// ... Create a client earlier in your code
async fn make_request(client: &Client) -> Result<(), Box<dyn Error>> {
// Use the client to perform operations
Ok(())
}

すべてのClientインスタンスには、MongoDB トポロジー内の各サーバーに対する接続プールが組み込まれています。 接続プールはオンデマンドでソケットを開き、アプリケーション内の MongoDB への同時要求をサポートします。

Clientのデフォルト構成はほとんどのアプリケーションで動作します。 次のコードは、デフォルトの接続設定を持つクライアントを作成する方法を示しています。

let client = Client::with_uri_str("<connection string>").await?;

あるいは、アプリケーションのニーズに合わせて接続プールを調整し、パフォーマンスを最適化することもできます。 接続設定をカスタマイズする方法の詳細については、このガイドの次のサブセクションを参照してください。

Tip

接続プールの構成の詳細については、サーバー マニュアルの「 接続プール設定の調整 」を参照してください。

各接続プールの最大サイズはmax_pool_sizeオプションによって設定され、デフォルトは10になります。 サーバーへの使用中の接続数がmax_pool_sizeの値に達した場合、そのサーバーへの次のリクエストは接続が利用可能になるまで待機します。

アプリケーションのリクエストをサポートするために必要なソケットに加えて、各Clientインスタンスは、サーバーの状態を監視するために MongoDB トポロジー内のサーバーごとにさらに 2 つのソケットを開きます。 たとえば、3 ノードのレプリカセットに接続されたクライアントは、6 つの監視ソケットを開きます。 アプリケーションがmax_pool_sizeのデフォルト設定を使用し、プライマリ(デフォルト)ノードのみをクエリする場合、接続プールには最大 16 個の接続を存在できます。 アプリケーションが 読み込み設定 (read preference) を使用してセカンダリ ノードをクエリすると、それらの接続プールは増大し、合計接続数は 36 になります。

1 つのプロセス内で多数の同時 MongoDB リクエストをサポートするには、 max_pool_sizeオプションの値を増やすことができます。 次のコードは、 Clientをインスタンス化するときにmax_pool_sizeの値を指定する方法を示しています。

let mut client_options = ClientOptions::parse_async("<connection string>").await?;
client_options.max_pool_size = Some(20);
let client = Client::with_options(client_options)?;

接続プールにはレート制限があります。 max_connectingオプションによって、プールが並行して作成できる接続数が決定されます。 たとえば、 max_connectingの値がデフォルト値である2の場合、接続を同時にチェックアウトしようとする 3 番目のリクエストは、次のいずれかの場合にのみ成功します。

  • 接続プールは接続の作成を完了し、プール内の接続数はmax_pool_sizeの値以下になります。

  • 既存の接続がプールにチェックバックされます。

  • 接続作成のレート制限により、既存の接続を再利用するドライバーの能力が向上します。

min_pool_sizeオプションを使用して、各サーバーへの同時接続の最小数を設定できます。デフォルトは0になります。 ドライバーは、このソケット数で接続プールを初期化します。 ソケットが閉じられ、使用中とアイドル状態の両方を含むソケットの合計数が最小値を下回ると、最小値に達するまで接続プールはさらにソケットを開きます。

max_connecting次のコードでは、min_pool_size をインスタンス化するときに オプションとClient オプションを設定します。

let mut client_options = ClientOptions::parse_async("<connection string>").await?;
client_options.max_connecting = Some(3);
client_options.min_pool_size = Some(1);
let client = Client::with_options(client_options)?;

max_idle_timeオプションを設定することで、プール内で接続がアイドル状態を維持できる最大時間を設定できます。 max_idle_timeで指定された期間、接続がアイドル状態になると、接続プールはその接続を削除し、置き換えます。 このオプションのデフォルトは0であるか、制限なしです。

アプリケーション内の任意の点でClient::shutdown()メソッドが呼び出されると、ドライバーはすべてのアイドル ソケットを閉じ、プールに返されるときに使用されているすべてのソケットを閉じます。 Client::shutdown()を呼び出すと非アクティブなソケットのみが閉じられるため、このメソッドを使用して実行中の操作を中断したり終了したりすることはできません。 ドライバーはこれらのソケットを、プロセスが完了した場合にのみ閉じます。

次のコードは、 Clientをインスタンス化するときに、 max_idle_timeオプションの値を90秒に設定します。

let mut client_options = ClientOptions::parse_async("<connection string>").await?;
client_options.max_idle_time = Some(Duration::new(90, 0));
let client = Client::with_options(client_options)?;

並列データ操作を実行できる場合は、非同期の同時実行タスクを実行することでパフォーマンスを最適化できます。 次のコードでは、 tokio::taskモジュールのspawn()メソッドを使用して、挿入操作を実行するための個別の同時実行タスクを作成します。

let client = Client::with_uri_str("<connection string>").await?;
let data = doc! { "title": "1984", "author": "George Orwell" };
for i in 0..5 {
let client_ref = client.clone();
let data_ref = data.clone();
task::spawn(async move {
let collection = client_ref
.database("items")
.collection::<Document>(&format!("coll{}", i));
collection.insert_one(data_ref).await
});
}

Clientインスタンスは、それを作成したtokioまたはasync-stdランタイムのインスタンスにバインドされます。 Clientインスタンスを使用して別のランタイムで操作を実行すると、予期しない動作や失敗が発生する可能性があります。

tokioまたはasync_stdtestヘルパー マイクロを使用してアプリケーションをテストすると、意図したランタイムとは異なるランタイムで操作を実行する可能性があります。 これは、これらのヘルパー マイクロがテストごとに新しいランタイムを作成するためです。 ただし、この問題を回避するには、次のいずれかの戦略を使用できます。

  • testヘルパー マイクロを使用せずに、ランタイムをClientインスタンスにアタッチします。

  • asyncテストごとに新しいClientインスタンスを作成します。

この例では、最初の戦略に従い、テスト専用のグローバル ランタイムを作成しています。 次のコードでは、 test_list_dbs()メソッドは、このランタイムに手動で接続するクライアントを使用して配置内のデータベースを一覧表示します。

use tokio::runtime::Runtime;
use once_cell::sync::Lazy;
static CLIENT_RUNTIME: Lazy<(Client, Runtime)> = Lazy::new(|| {
let rt = Runtime::new().unwrap();
let client = rt.block_on(async {
Client::with_uri_str("<connection string>").await.unwrap()
});
(client, rt)
});
#[test]
fn test_list_dbs() -> Result<(), Box<dyn Error>> {
let (client, rt) = &*CLIENT_RUNTIME;
rt.block_on(async {
client.list_database_names().await
})?;
Ok(())
}

2 つ目の戦略を実装することで、次のコードはtokio::testを使用して実行されるテストごとに新しいClientインスタンスを作成し、ランタイム間で意図しない相互作用が存在しないようにします。

#[tokio::test]
async fn test_list_dbs() -> Result<(), Box<dyn Error>> {
let client = Client::with_uri_str("<connection string>").await?;
client.list_database_names().await?;
Ok(())
}

MongoDB への接続の詳細については、「 接続ガイド 」を参照してください。

Rust ドライバーで利用可能なランタイムの詳細については、「非同期 API と同期 API に関するガイド 」を参照してください。

戻る

コマンドの実行