レプリカセットにおける読み取りパフォーマンス最適化のベストプラクティス
MongoDBのレプリカセットは、本番環境において高可用性とデータ冗長性を確保するための基盤です。フェイルオーバーと耐久性は主な利点ですが、不適切に構成されたレプリカセットは深刻な読み取りレイテンシを引き起こし、高速なデータ取得に依存するアプリケーションの速度を低下させる可能性があります。読み取りパフォーマンスの最適化には、データのレプリケート方法、メンバー間での読み取りの分散方法、およびアプリケーションが真に必要とする一貫性保証について、慎重な調整が必要です。
本ガイドでは、MongoDBレプリカセットのクエリ速度に直接影響を与える、読み取りの確証(Read Concern)、書き込みの確証(Write Concern)、同期メカニズムを含む重要な設定項目について解説します。これらのベストプラクティスを実装することで、分散クラスター全体でのクエリのスループットを最大化し、レイテンシを最小限に抑えることができます。
レプリカセットにおける読み取りパスの理解
標準的なレプリカセットのデプロイでは、1つのメンバーがプライマリとして指定され、すべての書き込みを処理します。残りのメンバーはセカンダリとなり、プライマリからデータを非同期にレプリケートします。アプリケーションからの読み取りは、構成に応じてプライマリに向けられるか、セカンダリ全体に分散されることがあります。
読み取りの最適化とは、即時データ一貫性の必要性(多くの場合プライマリからの読み取りが必要)と、セカンダリからの読み取りによってプライマリのトラフィックをオフロードしたいという要望とのバランスを取ることを意味します。
1. 読み取りの確証(Read Concern)の戦略的な利用
読み取りの確証(Read Concern)は、読み取り操作に要求されるデータ一貫性の度合いを定義します。緩和されたもので十分な場合に過度に厳密な読み取りの確証を設定することは、複数のノードからの確認を操作に強制する可能性があるため、読み取りレイテンシの一般的な原因となります。
利用可能な読み取りの確証
MongoDBはいくつかの読み取りの確証を提供しており、それぞれがレイテンシと耐久性/一貫性のトレードオフになります。
| 読み取りの確証 | 説明 | ユースケース |
| :--- | :--- |
| strong | 投票ノードの過半数で永続化が保証されたデータを返します。一貫性が最も高い。 | データ損失が許容されない重要なトランザクション。 |
| majority | 投票ノードの過半数によってコミットが確認されたデータを返します。標準のデフォルト。 | 高い耐久性が要求される汎用的な読み取り。 |
| local | 読み取りが行われているメンバーで利用可能な最新のデータを返します。書き込み確認は問わない。 | 一部の古いデータ(例:ダッシュボードカウンター)を許容できる読み取り。 |
| linearizable | 読み取り操作が開始される前に正常に完了したすべての先行書き込み操作の結果を反映することを保証します。(majorityの書き込みの確証が必要)。
| 調整のため非常に高いレイテンシ。 | 最新の書き込み結果を即座に確認する必要がある読み取り。 |
最適化のヒント:local または majority のデフォルト設定
クリティカルではない読み取り(めったに更新されない設定データやキャッシュされた結果の読み込みなど)には、セカンダリで local 読み取りの確証を使用します。これにより、同期遅延を回避できます。
例:セッションレベルでの読み取りの確証の設定
// この特定のセッションに対して読み取りの確証を 'local' に設定
const session = mongoClient.startSession({ readConcern: { level: "local" } });
// セッションを使用した find 操作
db.collection('mydata').find().session(session).toArray();
警告: セカンダリで
localの確証を用いて読み取ると、まだレプリケートされていないデータを読み取る可能性があり、結果が古くなることがあります。
2. セカンダリ全体への読み取りの分散
デフォルトでは、MongoDBは読み取りをプライマリに転送します。読み取り容量をスケールアップするには、読み取りの優先度(Read Preference)設定を使用して、明示的にセカンダリに読み取りを指示する必要があります。
読み取りの優先度(Read Preference)の理解
読み取りの優先度は、レプリカセットのどのメンバーが読み取りリクエストを満たす資格があるか、および選択される順序を決定します。
一般的な読み取りの優先度には以下が含まれます。
primary: (デフォルト)プライマリのみが対象となります。primaryPreferred: まずプライマリを試行し、プライマリが利用できない場合はセカンダリにフォールバックします。secondary: セカンダリのみが対象となります。セカンダリが利用できない場合、操作は失敗します。secondaryPreferred: セカンダリを優先し、セカンダリが利用できない場合はプライマリにフォールバックします。nearest: クライアントからネットワークレイテンシが最も低いメンバー(プライマリまたはセカンダリ)を選択します。
最適化のヒント:secondaryPreferred または nearest の使用
ほとんどの読み取り集中型アプリケーションでは、secondaryPreferred を使用することで、利用可能なすべてのセカンダリにクエリ負荷を分散させ、プライマリの負荷を大幅に軽減できます。
地理的に分散したアプリケーションサーバーがある場合、クライアントのネットワークレイテンシを最小限に抑えるために nearest が最良の選択となることがよくありますが、その場合でもプライマリにヒットすることがあります。
例:secondaryPreferred を使用した接続
アプリケーションドライバーで接続する際に、読み取りの優先度を指定します。
const uri = "mongodb://host1,host2,host3/?replicaSet=rs0&readPreference=secondaryPreferred";
// またはドライバーセットアップで接続オプションを使用
const options = {
readPreference: "secondaryPreferred"
};
3. セカンダリの同期と遅延(Lag)の管理
セカンダリに読み取りをルーティングする場合、それらの読み取りのパフォーマンスは、セカンダリがプライマリにどれだけ速く追いついているかに完全に依存します。高いレプリケーション遅延(replication lag)は、セカンダリが古いデータを返していることを意味します。あるいは、遅延が大きすぎると、読み取りが失敗したりタイムアウトしたりする可能性があります。
レプリケーション遅延の監視
常にプライマリとセカンダリ間の optimeDate の差を監視してください。rs.printReplicationInfo() のようなツールや、MongoDB Cloud Manager/Ops Manager などの監視システムが不可欠です。
// セカンダリメンバー上で実行
rs.printReplicationInfo()
// 報告された遅延時間を確認
// 'secsBehindPrimary' フィールドを探します。
書き込みの確証がセカンダリのパフォーマンスに与える影響
この記事は読み取りに焦点を当てていますが、高い書き込みの確証設定は、プライマリを遅くすることで間接的に読み取りパフォーマンスに影響を与え、その結果セカンダリが最新データから遅れる原因となります。
例えば、w: 'majority' の書き込み確認を要求すると、プライマリは続行する前にノードの過半数が書き込みを承認するのを待つ必要があります。承認が遅い場合(ネットワークの輻輳やセカンダリの過負荷による)、レプリケーションパイプライン全体が遅くなります。
書き込みの確証に関するベストプラクティス(間接的な読み取りの最適化): 書き込みの確証が適切に設定されていることを確認してください。多数のセカンダリがある場合、より低い w: 値(例:w: majority の代わりに w: 2)を使用すると、プライマリが書き込みを適用する速度が向上し、セカンダリが最新の状態を維持するのに役立ちます。
4. インデックス作成とクエリの最適化
設定項目だけでは、不適切な書き方をされたクエリを克服することはできません。高速な読み取りの基本的な原則は、堅牢なインデックス作成であり続けます。
主要なインデックス作成の考慮事項
- カバーされたクエリ: インデックスによって完全に満たされ、ディスクからドキュメントを取得する必要がないようにクエリを設計します。これらは可能な限り最速の読み取りです。
- インデックスのアライメント:
find()、sort()、およびprojection()句で使用されるフィールドとインデックスが一致していることを確認します。 - コレクションスキャンの回避: 読み取り操作が完全なコレクションスキャン(
COLLSCAN)を実行するのではなく、インデックス(IXSCAN)を使用していることをクエリプロファイラで常に確認します。
クエリタイムアウトの調整
アプリケーションが大幅に遅延しているセカンダリにアクセスしている場合、クエリがタイムアウトする可能性があります。一時的な遅延に適切に対処するため、アプリケーションで合理的なタイムアウトを設定し、無期限にハングするのではなく、プライマリにフォールバックするか後で再試行するようにします。
読み取り最適化ステップのまとめ
MongoDBレプリカセットで最適な読み取りパフォーマンスを達成するには、次の実用的な手順に従ってください。
- 読み取りタイプの特定: 読み取りを2つのグループに分類します:強力な一貫性が必要なもの(プライマリ/Strong Read Concernを使用)と、結果的な一貫性を許容できるもの(セカンダリ/Local Read Concernを使用)。
- 読み取りの優先度の設定: アプリケーショントラフィックの大部分について、接続文字列またはセッションオプションを
secondaryPreferredまたはnearestを使用するように設定します。 - 遅延の監視: レプリケーション遅延(
secsBehindPrimary)を継続的に監視します。遅延が継続的に高い場合は、セカンダリのハードウェアまたはネットワークの問題を調査します。 - 書き込みの確証の確認: 書き込みの確証がプライマリを不必要に遅延させていないか確認します。そうでない場合、セカンダリへの最新データの供給が滞ります。
- 徹底的なインデックス作成: 頻繁に実行されるすべての読み取りパスが効率的なインデックスによってカバーされていることを確認します。