MongoDB レプリケーション概要
今回は「MongoDB レプリケーション」について見ていく。
レプリケーション (Replication)
レプリケーションとは、データを複数のデータベースサーバーにコピーし、冗長性と可用性を提供する仕組みである。保存するデータセンターが異なる場合は、障害や災害への対策になる。また、同じデータを保持しているため、読み取りが多いアプリケーションでは負荷分散にも利用できる。
MongoDB におけるレプリケーション
MongoDB は、同じデータを保持するデータベースインスタンスを「レプリカセット」という単一のグループとして管理する。MongoDB は、このレプリカセットの動作方式によって冗長性と可用性を提供する。
プライマリサーバーはすべての書き込み操作を受けるサーバーであり、データへの変更内容を記録してログに残す。セカンダリサーバーはプライマリサーバーの操作ログをコピーして適用し、プライマリサーバーと同じデータ状態にする。もしプライマリサーバーに障害が発生すると、適切なセカンダリサーバーがプライマリサーバーとして選出され、サービスを継続する。

レプリカセットのメンバー
MongoDB のレプリカセットに含まれるメンバー種別には、次の 3 種類がある。
- プライマリ (Primary)
- セカンダリ (Secondary)
- アービター (Arbiter)
それぞれについて以下で詳しく紹介する。
プライマリ(主、Primary)サーバー
レプリカセットの中に 1 つだけ存在する書き込み可能なサーバーである。プライマリサーバーの書き込み操作情報は oplog というログに残され、この操作ログがセカンダリサーバーへ送信されてコピーされる。
プライマリサーバーに何らかの問題が発生すると、残りのセカンダリサーバーの中から次のプライマリサーバーが投票で選出される。
セカンダリ(補助、Secondary)サーバー
プライマリサーバーの操作ログをもとにデータを更新する読み取り専用サーバーである。セカンダリサーバーを複数台用意することで、大量の読み取り処理を実行できる。
クライアントからのデータ読み取りは、基本的にセカンダリサーバー優先で行い、即時に必要なデータだけをプライマリサーバー優先で読み取る。
セカンダリサーバーの基本設定には、優先順位 (Priority)、非表示 (Hidden)、遅延 (Delayed) の 3 つがある。
- 優先順位 (Priority)
Priority: 0を指定すると、プライマリサーバーへ昇格しない。優先順位が 0 より大きい値に設定されたサーバーからプライマリサーバーを選出する。また、優先順位が高い値に設定されたサーバーが優先的にプライマリサーバーとして選出される。 - 非表示 (Hidden)
プライマリサーバーから操作ログをコピーしてデータを最新化するが、クライアントアプリケーションからは見えない設定である。クライアントアプリケーションから見えないため、他のサーバーに比べて負荷が低い。非表示設定にしたサーバーは、データ分析やバックアップなど通常業務とは異なる専用端末として利用する。 - 遅延 (Delayed)
プライマリサーバーから操作ログをコピーしてデータを反映するが、プライマリサーバーより指定した時間だけ遅延させて反映する。プライマリサーバーより遅延させて反映することで、何らかの操作ミスが発生した場合の復旧に利用できる。
アービター(仲裁、Arbiter)サーバー
レプリカセットで投票権を持つサーバー数を奇数にするために追加する調整用サーバーである。アービターサーバー自体にはデータがなく、プライマリサーバーに問題が発生したとき、新しいプライマリサーバーの選出で投票することが主な役割である。自身がプライマリサーバーになることはないため、Priority: 0 を指定しておく。
レプリカセット構成
レプリカセットには最大 50 台のメンバーを含めることができ、そのうち最大 7 台までが投票権を持つ。投票権を持つサーバー数は奇数になるように設計する。不足する場合は、仲裁者であるアービターを追加して調整する。
最小レプリカセットは 3 台構成で、次のような構成にできる。
- プライマリ、セカンダリ 2 台
- プライマリ、セカンダリ、アービター
地理的に離れたデータセンターにメンバーを配置すると、より高い可用性を得られる。
プライマリ、セカンダリ 2 台
このパターンは、2 台のセカンダリサーバーのどちらもプライマリサーバーになれるため、可用性が高い構成になる。
通常、2 台のセカンダリサーバーに完全なコピーが作成される。プライマリサーバーに問題が発生すると、残っている 2 台のセカンダリサーバーが投票を行い、どちらか一方がプライマリサーバーへ昇格する。

プライマリ、セカンダリ、アービター
いわゆるサーバー 2 台構成である。実際に動作するのはプライマリサーバーとセカンダリサーバーの 2 台であり、アービターサーバーはフェイルオーバーが行われるときに投票へ参加する程度である。ただし、アービターをセカンダリへ昇格させることは推奨されないため、管理用サーバーなど物理的に別の低スペックサーバーに配置する。
このパターンでは、アービターサーバーにはデータがコピーされないため、完全なコピーはセカンダリサーバーにのみ適用される。プライマリサーバーに問題が発生するとプライマリサーバー選出の投票が行われるが、必然的に残っているセカンダリサーバーがプライマリサーバーへ昇格する。

自動フェイルオーバー
レプリカセットは自動フェイルオーバーによって高可用性を提供する。具体的には、プライマリサーバーが応答しないとき、セカンダリサーバーから次のプライマリサーバーを選出し、選出されたセカンダリサーバーがプライマリサーバーへ昇格することで実現される。
各メンバーは 2 秒間隔でハートビート(ping)を行う。10 秒間応答を受け取れない場合、そのサーバーを不良サーバーとしてマークする。プライマリサーバーが不良サーバーに設定されると、残りのセカンダリサーバーで次のプライマリサーバーの選出が開始される。
サーバーが投票するときは、優先順位が高いサーバーが優先的にプライマリサーバーとして選出される。優先順位が低いサーバーが選出された状態で、より高い優先順位のサーバーが有効になった場合、再び優先順位が高いサーバーがプライマリサーバーになるよう投票が行われる。
投票しないメンバーは優先順位 (Priority) を 0 に設定する。1 つのレプリカセットで投票権は最大 7 個までなので、それ以上の補助サーバーを用意する場合は、優先順位 (Priority) を 0、投票権 (votes) も 0 に設定したサーバーにする。
データの読み書き
データの読み書きも、MongoClient 作成時の設定オプションで指定できる。書き込み設定には w、j、wtimeout の 3 つがあり、読み取り設定には readPreference、readConcern.level の 2 つがある。
var {MongoClient, ReadPreference} = require("mongodb");
var URL = "mongodb://localhost:27017/test";
MongoClient.connect(URL, {
// 書き込み設定
w: "majority",
j: true,
wtimeout: 5000,
// 読み取り設定
readPreference: ReadPreference.SECONDARY_PREFERRED
readConcern: {
level: "local"
}
}, (client) => {
client.close();
});
データ書き込み
書き込みは Write Concern 構成で、レプリカセットに含まれる何台のサーバーまで書き込み処理を伝播するかを指定する。
w
| 設定値 | 説明 |
|---|---|
<number> |
指定した台数まで書き込まれることを保証する。 |
"majority" |
投票権を持つサーバーの過半数に記録されるようにする。 |
j
| 設定値 | 説明 |
|---|---|
true |
ディスクに書き込むまで実行する。 |
false |
デフォルト値。メモリへの書き込みのみを保証する。 |
wtimeout
| 設定値 | 説明 |
|---|---|
<number> |
書き込みがタイムアウトする時間(ミリ秒)を指定する。設定する場合は 1 より大きい値を指定する。0 を指定するとタイムアウト処理は行われない。 |
データ読み取り
読み取りは Read Preference 設定で、どのサーバーから優先的にデータを読み込むかを設定できる。
readPreference
| 設定値 | 説明 |
|---|---|
primary |
デフォルトモード。プライマリサーバーから取得する。 |
primaryPreferred |
ほとんどの場合はプライマリサーバーから取得するが、プライマリサーバーにアクセスできない場合はセカンダリサーバーから取得する。 |
secondary |
セカンダリサーバーから取得する。 |
secondaryPreferred |
ほとんどの場合はセカンダリサーバーから取得するが、セカンダリサーバーにアクセスできない場合はプライマリサーバーから取得する。 |
nearest |
レプリカセットの種類に関係なく、レイテンシが最小のサーバーから取得する。 |
readConcern.level
どのデータを取得するかを指定する。
| 設定値 | 説明 |
|---|---|
"local" |
基本的にローカルを読む。インスタンスの最新データを取得する。レプリカセットの過半数に書き込まれたデータかどうかは保証しない。 |
"available" |
基本的にセカンダリを読む。インスタンスの最新データを取得する。レプリカセットの過半数に書き込まれたデータかどうかは保証しない。 |
"majority" |
多数のメンバーに記録された最新データを取得する。 |
"linearizable" |
すべての書き込みが完了した後、ロールバックされないデータを取得する。 |
まとめ
今回は「MongoDB のレプリケーション」について整理した。ポイントは次のとおりである。
- 書き込みはプライマリサーバーのみ可能である。
- プライマリサーバーに問題が発生すると、残りのセカンダリサーバーがプライマリサーバーへ昇格する。
参考資料
- MongoDB - Replication
- MongoDB - Replica Set Members
- MongoDB - Replica Set Primary
- MongoDB - Priority 0 Replica Set Members
- MongoDB - Hidden Replica Set Members
- MongoDB - Delayed Replica Set Members
- MongoDB - Replica Set Arbiter
- MongoDB - Write Concern
- MongoDB - Read Preference
- MongoDB - Read Concern