レプリカセットにおける読み取りパフォーマンス最適化のベストプラクティス

読み取り設定、読み取り保証、レプリケーションラグの監視、インデックス、タイムアウト制御を用いてMongoDBレプリカセットの読み取りを改善します。

レプリカセットにおける読み取りパフォーマンス最適化のベストプラクティス

MongoDBのレプリカセットは高可用性を提供しますが、自動的に読み取りを高速化するわけではありません。アプリケーションがすべてのクエリをプライマリに送信したり、弱いインデックスを使用したり、ラグのあるセカンダリから読み取ったりすると、ユーザーはページの遅さや古いデータを感じることになります。

優れた読み取りパフォーマンスは、適切な読み取り設定の選択、必要な一貫性に合わせた読み取り保証の設定、レプリケーションラグの監視、そしてまず遅いクエリを修正することから生まれます。

レプリカセットにおける読み取りパスの理解

標準的なレプリカセットのデプロイでは、1つのメンバーがプライマリとして指定され、すべての書き込みを処理します。残りのメンバーはセカンダリであり、プライマリからデータを非同期にレプリケートします。アプリケーションの読み取りは、設定に応じてプライマリに送信されるか、セカンダリに分散されます。

読み取りの最適化とは、即時のデータ一貫性(多くの場合プライマリからの読み取りが必要)と、プライマリからのトラフィックをオフロードする(セカンダリから読み取る)ことのバランスを取ることを意味します。

1. 読み取り保証の戦略的使用

読み取り保証は、読み取り操作に必要なデータ一貫性の程度を定義します。緩やかな保証で十分な場合に過度に厳格な読み取り保証を設定すると、複数ノードからの確認を待つ必要が生じ、読み取りレイテンシの一般的な原因となります。

利用可能な読み取り保証

MongoDBはいくつかの読み取り保証を提供しており、それぞれレイテンシと耐久性/一貫性のトレードオフがあります。

読み取り保証 説明 ユースケース
majority 投票ノードの過半数によってコミットされたと確認されたデータを返します。標準のデフォルト。 高い耐久性を必要とする汎用的な読み取り。
local 書き込み確認に関係なく、読み取り元のメンバーで利用可能な最新のデータを返します。 多少の古いデータを許容できる読み取り(例:ダッシュボードのカウンター)。
linearizable プライマリから読み取り、読み取り開始前に確認されたすべての書き込みを反映します。readConcern: "linearizable"と、関連する書き込みに対する過半数の書き込み保証が必要です。 ロック所有権のチェックなど、確認された最新の状態を観測する必要がある稀な読み取り。

最適化のヒント: localまたはmajorityをデフォルトに

重要でない読み取り(頻繁に更新されない設定データやキャッシュされた結果の読み込みなど)には、セカンダリでlocal読み取り保証を使用します。これにより、同期の遅延を回避できます。

例: セッションレベルでの読み取り保証の設定

// この特定のセッションに対して読み取り保証を'local'に設定
const session = mongoClient.startSession({ readConcern: { level: "local" } });

// セッションを使用した検索操作
db.collection('mydata').find().session(session).toArray();

警告: セカンダリでlocal保証を使用して読み取ると、プライマリと比較して古いデータが返される可能性があります。

2. セカンダリへの読み取りの分散

デフォルトでは、MongoDBは読み取りをプライマリに送信します。読み取り容量を拡張するには、読み取り設定を使用して明示的に読み取りをセカンダリに送信する必要があります。

読み取り設定の理解

読み取り設定は、レプリカセットのどのメンバーが読み取りリクエストを処理する資格があるか、およびそれらをどの順序で選択するかを指定します。

一般的な読み取り設定は次のとおりです。

  • 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. セカンダリの同期とラグの管理

読み取りをセカンダリにルーティングしている場合、それらの読み取りのパフォーマンスは、セカンダリがプライマリにどれだけ追いついているかに完全に依存します。レプリケーションラグが大きいと、セカンダリが古いデータを提供していることになり、ラグが大きすぎると読み取りが失敗したりタイムアウトしたりする可能性があります。

レプリケーションラグの監視

プライマリとセカンダリ間のoptimeの差を常に監視します。rs.status()はメンバーごとのレプリケーション状態を示し、MongoDB Atlas、Cloud Manager、Ops Managerなどの管理ツールはラグに関するアラートを発行できます。

rs.status().members.map(m => ({
  name: m.name,
  stateStr: m.stateStr,
  optimeDate: m.optimeDate
}))

書き込み保証がセカンダリのパフォーマンスに与える影響

この記事は読み取りに焦点を当てていますが、高い書き込み保証設定はプライマリを遅くすることで間接的に読み取りパフォーマンスに影響を与え、その結果セカンダリがさらに遅れる原因となります。

例えば、w: "majority"を要求すると、書き込みが投票データ保持メンバーの過半数に到達するまでクライアントは確認を受け取りません。ディスクやネットワークのプレッシャーによりセカンダリが遅い場合、アプリケーションの書き込みレイテンシが上昇し、それらの過負荷のセカンダリが遅い読み取りを提供する可能性もあります。

書き込み保証のベストプラクティス(間接的な読み取り最適化): 読み取りを高速化するためだけに書き込み保証を下げないでください。耐久性の要件に基づいて書き込み保証を選択し、その後ラグの原因(遅いディスク、過負荷のセカンダリ、小さすぎるoplog、ネットワーク問題、またはレプリケーションと競合するクエリ)を修正してください。

4. インデックスとクエリの最適化

適切に作成されていないクエリを克服できる設定はありません。高速な読み取りの基本原則は、堅牢なインデックス作成です。

主要なインデックス作成の考慮事項

  1. カバードクエリ: ディスクからドキュメントを取得せずにインデックスだけで完全に満たされるクエリを設計します。これらは可能な限り最速の読み取りです。
  2. インデックスの整合性: インデックスがfind()sort()projection()句で使用されるフィールドと一致していることを確認します。
  3. コレクションスキャンの回避: クエリプロファイラで、読み取り操作がインデックス(IXSCAN)を使用しており、完全なコレクションスキャン(COLLSCAN)を実行していないことを常に確認します。

クエリタイムアウトの調整

アプリケーションが大幅に遅延しているセカンダリにヒットしている場合、クエリがタイムアウトする可能性があります。アプリケーションで適切なタイムアウトを設定し、一時的なラグを適切に処理し、無期限にハングするのではなく、プライマリにフォールバックするか後で再試行するようにします。

読み取り最適化手順のまとめ

MongoDBレプリカセットで最適な読み取りパフォーマンスを達成するには、次の実践可能な手順に従ってください。

  1. 読み取りタイプの特定: 読み取りを、最新のプライマリデータが必要なものと、セカンダリからの結果整合性を許容できるものに分類します。
  2. 読み取り設定の構成: 接続文字列またはセッションオプションを設定し、アプリケーショントラフィックの大部分にsecondaryPreferredまたはnearestを使用します。
  3. ラグの監視: rs.status()、ドライバメトリクス、または監視プラットフォームからレプリケーションラグを継続的に監視します。ラグが一貫して高い場合は、セカンダリのハードウェアまたはネットワークの問題を調査します。
  4. 書き込み保証の見直し: 書き込み保証がプライマリを不当に遅くしていないことを確認します。これによりセカンダリが最新データを受け取れなくなります。
  5. 徹底的なインデックス作成: 頻繁に実行されるすべての読み取りパスが効率的なインデックスを使用していることを確認します。

レプリカセットの読み取りスケーリングは、データの古さについて正直であるときに最も効果的です。ユーザーにとって重要な読み取りは、最新である必要がある場合はプライマリに送信し、セカンダリは遅延を許容できる分析やダッシュボードに使用し、トラフィックの変化に応じてクエリプランとレプリケーションの健全性を測定し続けてください。