AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。

Atlas レイテンシ削減に関するガイダンス

以下のセクションでは、Atlas 配置のレイテンシを低減するための設定オプションについて説明します。

物理的距離はレイテンシの主な原因です。ユーザーとアプリケーションの間、アプリケーションとデータの間、クラスターノード間の距離は、いずれもシステムのレイテンシやアプリケーションのパフォーマンスに影響を与えます。

読み取りおよび書き込み操作のレイテンシを軽減するには、アプリケーションとデータの両方を地理的にユーザーに近いものに配置することが重要です。データを保持する Atlas ノードは、データベースのデータを保存し、読み取りおよび書き込み操作を取り扱う Atlas クラスター内のサーバーノードです。アプリケーションユーザーのデータアクセスを高速化するには、アプリケーションユーザーの過半数に地理的に近いクラウドプロバイダーのリージョンに、データを含む Atlas ノードを配置します。

アプリケーションのユーザーが米国やヨーロッパなど複数の地域に分散されている場合、各地域で1つ以上のリージョンに配置することをお勧めします。これにより、各ロケーションのユーザーのレイテンシを低減できます。マルチリージョン配置の詳細については、「マルチリージョン配置のパラダイム」を参照してください。

データが地理ごとに分割されており、各地域のユーザーが異なるデータセットにアクセスする場合は、リージョンまたは地域ごとにデータをシャード分割して、各地域のユーザーの読み取りおよび書き込みパフォーマンスを最適化することもできます。このアプローチにより、データローカリティを確保しつつ、大規模なデータセットと高スループットを取り扱うことができます。

レプリケーションは、プライマリ ノードからセカンダリ ノードへのデータのコピーです。以下のレプリケーション設定オプションを調整することで、レプリカセット内の読み取りおよび書き込み操作のレイテンシを最小限に抑えることができます。

  • 書込み保証 (write concern) レベル: 書込み保証 (write concern)を設定する場合、書き込み (write)レイテンシと書き込み (write)耐久性の間にはトレードオフがあります。MongoDB のデフォルトのグローバル書込み保証 (write concern) は majority に設定されています。このため、Atlas がクライアントに対して操作の完了と成功させることを確認する前に、各書き込み (write)操作がレプリカセット内の投票権を持つデータを保持するノードの過半数に複製される必要があります。書込み保証 (write concern)を高く設定すると、 書き込み レイテンシが増加しますが、書き込み の耐久性も向上し、レプリカセットのフェイルオーバー中にロールバックが発生するのを防止できます。

  • 読み取り保証 (read concern) と読み込み設定 (read preference): 読み取り保証 (read concern) と 読み込み設定 (read preference) を構成する場合、クエリレイテンシ、データ可用性、およびクエリ応答の整合性の間にはトレードオフがあります。MongoDB のデフォルトのグローバル読み取り保証 (read concern)は local です。これにより、読み取り操作は、データが他のノードにレプリケーションされることを確認するのを待つことなく、ローカルレプリカセット内の 1 つのノードからのみ読み取る必要があります。このノードがプライマリ ノードかセカンダリ ノードかは、読み込み設定 (read preference)によって決まります。Atlas はデフォルトで primary に設定します。このデフォルトの読み取り保証 (read concern)と設定の組み合わせは、レプリカセット内の最新のノードからのレイテンシではレイテンシが最低となります。ただし、プライマリ ノードのデータが永続的ではなく、次の実行中にロールバックされる可能性があるリスクもあります:フェイルオーバー以降、使用可能な プライマリノードがない場合は、ユーザーはデータをクエリできません。

    読み込み設定を primaryPreferred に変更して、使用可能なプライマリノードがない場合や、地理的に近いセカンダリノードがある場合にセカンダリノードから読み込み操作を実行できるようにできますが、セカンダリノードが最新でない場合、古いデータが返されるリスクがあります。このリスクは書込み保証を増やしてより多くのセカンダリノードを最新の状態に保つことで軽減できますが、その代わりに書込みレイテンシが増加します。

    重要

    レプリケーションラグにより、セカンダリ ノードから古いデータが返される可能性があることに注意してください。

  • クエリ タイムアウトの制限: 配置にグローバルおよび操作レベルのクエリ タイムアウト制限を設定して、アプリケーションがタイムアウトするまでの応答を待つ時間を短縮できます。これにより、進行中のクエリが長期間にわたって配置のパフォーマンスに悪影響を与えるのを防ぐことができます。

  • ノード選挙の優先順位:メインデータセンターのノードが代替データセンターのノードよりも先にプライマリに選出される可能性を高めるには、レプリカセット選挙中に、代替データセンターのノードのmembers[n].priorityをプライマリデータセンターのノードよりも低く設定できます。例として、クラスターを AWS リージョン us-east-1(Northern Virginia)と us-west-1(Northern California)にわたって配置し、ユーザーの過半数がカリフォルニアにいる場合、AWS us-west-1(Northern California)リージョンのノードを優先すると、プライマリノードが常に地理的にユーザーの過半数に近く、読み取りおよび書き込み (write)操作に最小限のレイテンシで応答できるようになります。

  • ミラーリングされた読み取り: ミラーリングされた読み取りは、セカンダリ ノードのキャッシュを事前ウォーミングすることで、停止後のプライマリ選挙の影響を軽減します。詳細については、「ミラーリングされた読み取り」を参照してください。

お客様のニーズに最適なレプリケーション構成を実装するための詳しいガイダンスについては、MongoDB の Professional Services にお問い合わせください。

次のネットワーク接続オプションを使用することで、セキュリティを強化し、さらにレイテンシを低減することができます。

  • プライベートエンドポイント: プライベートエンドポイントは、アプリケーションの仮想ネットワークと Atlas クラスター間で直接かつ安全な接続を確立し、ネットワーク コストを削減し、レイテンシ を改善する可能性があります。

  • VPC ピアリング:アプリケーションがピアリングされたリージョンに接続できるように、レプリカセットに VPC ピアリングを設定します。フェイルオーバーが発生した場合、VPC ピアリングはアプリケーションサーバーが新しいプライマリノードを検出し、それに応じてトラフィックをルーティングする方法を提供します。

アプリケーションがデータにアクセスする速度は、レイテンシに影響します。優れたデータモデリングとクエリの最適化により、データアクセス速度を向上させることができます。例としては次のことができます。

  • ドキュメント サイズを縮小: ネットワークを介して転送されるデータ転送量を減らすために、フィールド名と値の長さを短縮することを検討します。

  • クエリ パターンの最適化: インデックスを効果的に使用して、リージョン全体で読み取られる必要があるデータ量を最小限に抑えます。

Atlas は、さまざまなリージョンのレイテンシメトリクスを観察するためにリアルタイム パフォーマンス パネル(リアルタイム パフォーマンス パネル)を提供しています。また、アプリケーションレベルのモニタリングを実装して、アプリケーションとの間のエンドツーエンドのレイテンシを追跡することもできます。最終本番環境に配置する前に、さまざまなマルチリージョンシナリオでパフォーマンス テストを実行し、レイテンシのボトルネックを特定して対処することをお勧めします。

配置のモニタリングの詳細については、Atlas のモニタリングとアラート に関するガイダンス を参照してください。

可能な限り、アプリケーションのプログラミング言語に対応した最新のドライバー バージョンでビルドされた接続方法を使用することをお勧めします。Atlas が提供するデフォルトの接続文字列は良い出発点ですが、接続文字列オプションを接続文字列に追加して、特定のアプリケーションと配置アーキテクチャのコンテキストでパフォーマンスを向上させることができます。

エンタープライズレベルのアプリケーション配置の場合、 操作レイテンシ を最小限に抑えながら、ユーザーの需要に合わせて接続プールの設定を調整することは特に重要です。例、minPoolSize と maxPoolSize オプションを使用して、データベースクライアント接続の過半数が開く方法とタイミングを調整できるため、関連するネットワーク オーバーヘッドに伴うレイテンシの急増を防止または計画できます。

これらの設定をどの程度構成できるかは、配置アーキテクチャによって異なります。例えば、アプリケーションの配置がAmazon Web Services Lambda のようなシングルスレッド リソースを活用している場合、アプリケーションは 1つのクライアント接続しか開いて使用できません。接続プールの作成方法や使用場所、接続プール設定の指定箇所についての詳細は、「接続プールの概要」を参照してください。

次のサンプルアプリケーションでは、データ操作のレイテンシ を削減するために、このページに記載されている重要な推奨事項をまとめています。

アプリケーションは、クライアントがユーザー レコードを作成または一覧表示できるHTTP APIです。これにより、GET および POST リクエストを受け入れるエンドポイントが公開されます ( http://localhost:3000 )。

方式
エンドポイント
説明

GET

/users

usersコレクションからユーザー名のリストを取得します。

POST

/users

リクエスト本文にnameが必要です。 新しいユーザーをusersコレクションに追加します。

// File: App.java import java.util.Map;import java.util.logging.Logger; import org.bson.Document;import org.json.JSONArray; import com.mongodb.MongoException;import com.mongodb.client.MongoClient;import com.mongodb.client.MongoClients;import com.mongodb.client.MongoCollection;import com.mongodb.client.MongoDatabase; import fi.iki.elonen.NanoHTTPD; public class App extends NanoHTTPD { private static final Logger LOGGER = Logger.getLogger(App.class.getName()); static int port = 3000; static MongoClient client = null; public App() throws Exception { super(port); // Replace the uri string with your MongoDB deployment's connection string String uri = "<atlas-connection-string>"; client = MongoClients.create(uri); start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); LOGGER.info("\nStarted the server: http://localhost:" + port + "/ \n"); } public static void main(String[] args) { try { new App(); } catch (Exception e) { LOGGER.severe("Couldn't start server:\n" + e); } } @Override public Response serve(IHTTPSession session) { StringBuilder msg = new StringBuilder(); Map<String, String> params = session.getParms(); Method reqMethod = session.getMethod(); String uri = session.getUri(); if (Method.GET == reqMethod) { if (uri.equals("/")) { msg.append("Welcome to my API!"); } else if (uri.equals("/users")) { msg.append(listUsers(client)); } else { msg.append("Unrecognized URI: ").append(uri); } } else if (Method.POST == reqMethod) { try { String name = params.get("name"); if (name == null) { throw new Exception("Unable to process POST request: 'name' parameter required"); } else { insertUser(client, name); msg.append("User successfully added!"); } } catch (Exception e) { msg.append(e); } } return newFixedLengthResponse(msg.toString()); } static String listUsers(MongoClient client) { MongoDatabase database = client.getDatabase("test"); MongoCollection<Document> collection = database.getCollection("users"); final JSONArray jsonResults = new JSONArray(); collection.find().forEach((result) -> jsonResults.put(result.toJson())); return jsonResults.toString(); } static String insertUser(MongoClient client, String name) throws MongoException { MongoDatabase database = client.getDatabase("test"); MongoCollection<Document> collection = database.getCollection("users"); collection.insertOne(new Document().append("name", name)); return "Successfully inserted user: " + name; }}