[MongoDB] AWSにおけるレプリカセット構成の配置パターン

2017.02.26

こんにちは、菊池です。

ドキュメント指向のNOSQL DBであるMongoDBを、AWSで構築する際に考慮すべきレプリカセットの配置パターンを整理しました。

MongoDBのレプリカセット構成

MongoDBは、レプリカセット構成をとることで冗長化と読み取り負荷分散が可能です。

以下のように、アプリケーションからのデータ書き込みはプライマリノードに対して行われます。プライマリノードに書き込まれたデータは、複数のセカンダリノードに同期されます。データの読み出しはプライマリ/セカンダリのどちらかからも可能となりますので、複数のノードから読み出すことで読み取りの負荷分散が可能になります。

mongo_rep_00

各ノードはお互いにハートビートを行い、プライマリノードで障害が発生した場合、いずれかのセカンダリノードが選出されプライマリに昇格します。障害時のスプリットブレイン発生を防止するため、レプリカセットの合計ノード数は奇数にするのが基本です。

レプリカセットのパラメータ

レプリカセット構成時に各ノード毎に設定可能なパラメータから、レプリカセット配置で考慮すべき項目を説明します。

項目 設定値 説明
priority 0 - 100 プライマリ選出の優先度。値が大きいノードが優先でプライマリに選出される。
votes 0 or 1 プライマリ選出における投票権。0の場合にはプライマリ選出に参加しない。
arbiterOnly true | false データを保持せず、プライマリ選出にのみ参加するノードに指定する。
hidden true | false 指定することで、レプリカセットのクライアントから隠された状態になる。
tags string ノードにKey:Valueのタグを付与する。

Write Concern

レプリカセットに書き込まれたデータの完全性を保証する上で、考慮すべきパラメータにWrite Concern(書き込み保証)があります。プライマリノードに書き込まれたデータはセカンダリに同期されますが、同期が完了するまでの間に障害が発生するとデータが失われるリスクがあります。そこで、書き込まれたデータが何台のノードまで同期した時点でAckを応答するか、クライアント側で指定することが可能になっています。そのパラメータがWrite Concernです。

以下の図のように、何台のノードまで同期したかを指定してデータを書き込みます。

mongo_rep_07

  • w = 0:クライアントは応答を待ちません。
  • w = 1:1台のノード(=プライマリ)への書き込みが完了した時点で応答を返します。
  • w = 2:2台のノードへ書き込みが完了した時点で応答を返します。
  • w = majority:過半数のノードに書き込みが完了した時点で応答を返します。
  • w = :タグで指定したノードに書き込みが完了した時点で応答を返します。

書き込みデータの安全性/完全性と書き込みパフォーマンスのトレードオフとなりますので、データの重要性に合わせて設定する必要があります。

AWSにおける配置パターン

上記パラーメタを踏まえ、AWSにおけるレプリカセットのノードの配置パターンを考えます。

Multi-AZ(3つのAZ)

AZが3つ以上あるリージョンでは、3つのノードをそれぞれ別のAZに配置するMulti-AZが適切でしょう。

mongo_rep_01

Multi-AZ(2つのAZ)

東京リージョンでは一部ユーザを除き、AZ-A/Cの2つのAZしか使えません。その場合はどちらかのAZに2つのノードを配置したこのパターンになります。

mongo_rep_02

この場合に考慮すべきなのは、書き込み保証と同期のパフォーマンス、そしてAZ障害への対応です。

上の図でWrite Concernをw=2に設定した場合を考えます。2台のノードがいるAZ-A側にプライマリがいた方が、同じAZ内で同期して応答を返すことができるためパフォーマンス面で有利です。なので、AZ-A側のノードが優先でプライマリになるよう、priorityを高く設定します。

このケースで最も考慮しておくべきは、AZ-A障害時の対応です。AZ-A障害によりAZ-Cのノードのみとなった場合、過半数のノードが失われているためプライマリに昇格できず、書き込みができない状態となります。スタンドアロンでの起動や、ノード追加/レプリカセットのパラメータ変更といった対応が必要となりますので手順を確立しておきましょう。

Multi-AZ + 別拠点

2AZのリージョンでは、3つ目のノードを別の拠点に起動する案もあります。別のAWSリージョンやオンプレミスのデータセンターを使います。

mongo_rep_03

別の拠点にレプリケーションすることで、データの可用性も向上します。

この構成にする場合、別拠点のノードがプライマリに昇格することがないよう、priorityを0に設定しましょう。また、拠点をまたぐレプリケーションの通信経路には、DirectConnectやVPN接続、あるいはMongoDBのTLS/SSLを使って安全な通信をするのがいいでしょう。

Multi-AZ + 別拠点(Arbiter)

同じく別拠点を使うパターンですが、データをレプリケーションする必要はないという場合には、Arbiterとすることも可能です。

mongo_rep_04

Arbiterとすることでハートビート/プライマリ選出には参加しますが、データを持たずプライマリにも昇格しません。そのため、別の拠点に起動するノードは最小限のスペックでよいというメリットもあります。

Hiddenノード

1つのセカンダリノードをHiddenに指定することで、レプリカセットのクライアントからは不可視となり読み取り負荷分散にも加わらなくなります。

mongo_rep_05

Hiddenノードに指定する際は、priorityも必ず0にする必要があります。

明示的にノードを指定することでアクセスも可能なので、オンライン処理とは切り離したバッチ集計などの処理やデータ分析に使うことが可能です。また、その他の用途として、単純なデータバックアップとして最小限のインスタンスタイプとしておくことも可能です。

Hiddenノード(4ノード構成)

基本の3ノードにHiddenを追加し、合計4ノードとするパターンです。

mongo_rep_06

前述の通り、スプリットブレインを防止するために基本は奇数にする必要があります。偶数のノードを起動する要件がある場合には、1台のvotesを0に設定し、プライマリ選出に参加するノードを奇数とします。

上のケースでは、HiddenノードのVote権を0にすることで、プライマリ選出に参加しないデータレプリケーションのみを保持するノードとなります。

まとめ

いかがでしたでしょうか。

他にも要件によって色々なパターンがあると思います。求められる可用性・冗長性に応じて適切な構成を組めるようにしておきたいと思い、基本的なパターンをまとめてみました。