挿入のみのワークロードの分散ローカル書込み
MongoDB タグ対応シャーディング を使用すると、管理者はシャードキーの範囲を定義し、その範囲を 1 つ以上のシャードにタグ付けすることで、シャーディングされたクラスター内のデータの分散を制御できます。
このチュートリアルでは、ゾーンとマルチデータセンターのシャーディングされたクラスターの配置とアプリケーション側のロジックを使用して、分散ローカル書込みをサポートし、レプリカセットの選挙やデータセンターに障害が発生した場合の高い書込み可用性をサポートします。
空のコレクションまたは存在しないコレクションをシャーディングする前にゾーンとゾーン範囲を定義することで、シャード コレクション操作は定義されたゾーン範囲のチャンクと、シャードキー値の全範囲をカバーする追加のチャンクを作成し、初期化を実行しますゾーン範囲に基づく チャンク分散 。 このように初期チャンクを作成して分散することで、ゾーン シャーディングの設定を迅速に行うことができます。 初期分散後、バランサーは今後のチャンク分散を管理します。
例については、「 空または存在しないコレクションのゾーンとゾーン範囲の事前定義」を参照してください。
重要
このチュートリアルで説明される概念には、特定の配置アーキテクチャとアプリケーション レベルのロジックが必要です。
これらの概念には、 MongoDBのシャーディングされたクラスター、レプリカセット、およびゾーン の一般的な動作に関する知識が必要です。
このチュートリアルでは、挿入専用または挿入集中型のワークロードを前提としています。 このチュートリアルで説明されている概念と戦略は、高速な読み取りまたは更新を必要とするユースケースには適していません。
Scenario
書込みに比べて読み取りは頻度が低く、優先順位が低い、挿入集中型のアプリケーションを例にしましょう。 アプリケーションはドキュメントをシャーディングされたコレクションに書込みますが、SLA または SLO をサポートするにはデータベースからのほぼ一貫したアップタイムが必要です。
次は、アプリケーションがデータベースに書込むドキュメントの形式の部分的なビューを表します。
{ "_id" : ObjectId("56f08c447fe58b2e96f595fa"), "message_id" : 329620, "datacenter" : "alfa", "userid" : 123, ... } { "_id" : ObjectId("56f08c447fe58b2e96f595fb"), "message_id" : 578494, "datacenter" : "bravo", "userid" : 456, ... } { "_id" : ObjectId("56f08c447fe58b2e96f595fc"), "message_id" : 689979, "datacenter" : "bravo", "userid" : 789, ... }
シャードキー
コレクションでは、 { datacenter : 1, userid : 1 }
複合インデックスがシャードキーとして使用されます。
各ドキュメントのdatacenter
フィールドを使用すると、個別のデータセンター値ごとにタグ範囲を作成できます。 datacenter
フィールドがない場合、ドキュメントを特定のデータセンターに関連付けることはできません。
userid
フィールドは、 datacenter
と比較して、シャードキーに対して高濃度で低頻度のコンポーネントを提供します。
シャードキーの選択に関する一般的な手順については、「シャードキーの選択」を参照してください。
アーキテクチャ
配置は、 alfa
とbravo
の 2 つのデータセンターで構成されています。 シャードにはshard0000
とshard0001
の 2 つがあります。 各シャードは、3 つのメンバーを含むレプリカセットです。 shard0000
は、 alfa
に 2 つのノードを持ち、 bravo
に 1 つの優先順位 0 のノードを持ちます。 shard0001
は、 bravo
に 2 つのノードを持ち、 alfa
に 1 つの優先順位 0 のノードを持ちます。
tags
このアプリケーションでは、データセンターごとに 1 つのタグが必要です。 各シャードには、レプリカセット ノードの過半数を含むデータセンターに基づいて、1 つのタグが割り当てられます。 タグ範囲は、データセンターごとに 1 つずつ、2 つあります。
alfa
Datacenterこのデータセンター上の過半数のノードを含むシャードに
alfa
としてタグを付けます。次の要素を使用してタグ範囲を作成します:
{ "datacenter" : "alfa", "userid" : MinKey }
の下限、{ "datacenter" : "alfa", "userid" : MaxKey }
の上限、およびタグ
alfa
bravo
Datacenterこのデータセンター上の過半数のノードを含むシャードに
bravo
としてタグを付けます。次の要素を使用してタグ範囲を作成します:
{ "datacenter" : "bravo", "userid" : MinKey }
の下限、{ "datacenter" : "bravo", "userid" : MaxKey }
の上限、およびタグ
bravo
構成されたタグとタグ範囲に基づいて、 mongos
はdatacenter : alfa
を持つドキュメントをalfa
データセンターに、 datacenter : bravo
を持つドキュメントをbravo
データセンターにルーティングします。
書込み操作
挿入または更新されたドキュメントが設定されたタグ範囲と一致する場合、そのドキュメントは関連するタグを持つシャードにのみ書き込むことができます。
MongoDB は、設定されたタグ範囲に一致しないドキュメントをクラスター内の任意のシャードに書込むことができます。
注意
上記の動作では、クラスターが定常状態で、設定されたタグ範囲に違反するチャンクがない状態である必要があります。 詳しくは、 バランサーの次のセクションを参照してください。
バランサー
バランサーは、タグ付けされたチャンクを適切なシャードに移行します。 移行するまで、シャードには構成されたタグ範囲とタグに違反するチャンクが含まれる可能性があります。 バランシングが完了すると、シャードには、割り当てられたタグとタグ範囲に違反しない範囲のチャンクのみが含まれるようになります。
タグまたはタグ範囲を追加または削除すると、チャンクの移行が発生する可能性があります。 データセットのサイズと、タグ範囲が影響するチャンクの数によっては、これらの移行がクラスターのパフォーマンスに影響を与える可能性があります。 特定のスケジュールされた 中に バランサー Windowsを実行することを検討してください。スケジュール ウィンドウの設定方法については、「 バランシング ウィンドウのスケジュール」を参照してください。
アプリケーションの動作
デフォルトでは、アプリケーションは最も近いデータセンターに書込みます。 ローカル データセンターがダウンした場合、またはそのデータセンターへの書き込みが一定期間内に確認されない場合、アプリケーションはデータベースへのドキュメントの書込みを試みる前に、 datacenter
フィールドの値を変更して他の利用可能なデータセンターに切り替えます。
アプリケーションは書込みタイムアウトをサポートしています。 アプリケーションは、書込み保証を使用して、各書込み操作のタイムアウトを設定します。
アプリケーションで書込みまたはタイムアウトのエラーが発生した場合、各ドキュメントのdatacenter
フィールドを変更し、書込みを実行します。 これにより、ドキュメントは他のデータセンターにルーティングされます。 両方のデータセンターがダウンしている場合は、書込みは成功しません。 「書込み失敗の解決 」を参照してください。
アプリケーションは、「ダウン」とマークされたデータセンターへの接続を定期的にチェックします。 接続が復元された場合、アプリケーションは通常の書込み操作を引き続き実行できます。
切り替えロジックと、データセンター間のクライアントトラフィックを処理するためのロードバランサーまたは同様のメカニズムを考慮すると、アプリケーションは、特定のドキュメントが 2 つのデータセンターのどのデータセンターに書き込まれたかを予測できません。 読み取り操作の一環としてドキュメントが見逃しないようにするには、クエリの一部としてdatacenter
フィールドを含めずにブロードキャスト クエリを実行する必要があります。
アプリケーションは、レイテンシを削減するために の 読み込み設定( read preference nearest
) を使用して読み取りを実行します。
タイムアウト エラーが報告されていても、書込み (write) 操作は成功する可能性があります。 アプリケーションは、エラーに応答してドキュメントを他のデータセンターに書き換えようとします。これにより、両方のデータセンターにドキュメントが重複する可能性があります。 アプリケーションは、読み取りロジックの一部として重複を解決します。
スイッチ ロジック
このアプリケーションには、1 つ以上の書込み (write) が失敗した場合、または設定された時間内に書込み (write) が確認されなかった場合に、データセンターを切り替えるロジックがあります。 アプリケーションは、ターゲット データセンターのタグに基づいてdatacenter
フィールドを変更し、ドキュメントをそのデータセンターに送信します。
たとえば、アプリケーションがalfa
データセンターに書込みを試みる場合、次の一般的な手順に従います。
datacenter : alfa
を指定してドキュメントの書込みを試みます。書き込みタイムアウトまたはエラーが発生すると、
alfa
が一時的にダウンしているとしてログに記録されます。datacenter : bravo
を変更して、同じドキュメントの作成を試みます。書き込みタイムアウトまたはエラーが発生すると、
bravo
が一時的にダウンしているとしてログに記録されます。alfa
とbravo
の両方がダウンしている場合は、 がログに記録とエラーを報告します。
手順
シャード タグの構成
続行するには、ターゲットの mongos
シャーディングされたクラスター に関連付けられている に接続する必要があります。シャードレプリカセットに直接接続してタグを作成することはできません。
各シャードにタグを付けます。
alfa
データセンター内の各シャードにalfa
タグを付けます。
sh.addShardTag("shard0000", "alfa")
bravo
データセンター内の各シャードにbravo
タグを付けます。
sh.addShardTag("shard0001", "bravo")
任意のシャードに割り当てられたタグを確認するには、 sh.status()
を実行します。
各タグの範囲を定義します。
alfa
データベースの範囲を定義し、 sh.addTagRange()
メソッドを使用してalfa
タグに関連付けます。 このメソッドには次のものが必要です。
ターゲット コレクションの完全な名前空間。
範囲の下限を含みます。
範囲の排他的上限。
タグの名前。
sh.addTagRange( "<database>.<collection>", { "datacenter" : "alfa", "userid" : MinKey }, { "datacenter" : "alfa", "userid" : MaxKey }, "alfa" )
bravo
データベースの範囲を定義し、 sh.addTagRange()
メソッドを使用してbravo
タグに関連付けます。 このメソッドには次のものが必要です。
ターゲット コレクションの完全な名前空間。
範囲の下限を含みます。
範囲の排他的上限。
タグの名前。
sh.addTagRange( "<database>.<collection>", { "datacenter" : "bravo", "userid" : MinKey }, { "datacenter" : "bravo", "userid" : MaxKey }, "bravo" )
MinKey
とMaxKey
の値は比較用の特別な値として予約されています。 MinKey
は常に他のすべての可能な値よりも小さいとみなされ、 MaxKey
は常に他のすべての可能な値よりも大きいとみなされます。 構成された範囲では、各datacenter
のすべてのユーザーがキャプチャされます。
書込み失敗の解決
アプリケーションのデフォルトのデータセンターがダウンしているかアクセスできない場合、アプリケーションはdatacenter
フィールドを他のデータセンターに変更します。
たとえば、アプリケーションは、デフォルトで次のドキュメントをalfa
データセンターに書込み込もうとします。
{ "_id" : ObjectId("56f08c447fe58b2e96f595fa"), "message_id" : 329620, "datacenter" : "alfa", "userid" : 123, ... }
アプリケーションが書込み試行時にエラーを受け取った場合、または書込み確認に時間がかかりすぎる場合、アプリケーションはデータセンターが使用できないとしてログに記録され、 datacenter
フィールドが変更され、 bravo
データセンターを指すようにします。
{ "_id" : ObjectId("56f08c457fe58b2e96f595fb"), "message_id" : 329620, "datacenter" : "bravo", "userid" : 123, ... }
アプリケーションは、 alfa
データセンターの接続を定期的にチェックします。 データセンターに再びアクセスできるようになると、アプリケーションは通常の書込みを再開できます。
注意
特にエラーがタイムアウトに関連していた場合、 datacenter : alfa
への最初の書込み (write) は成功した可能性があります。 その場合、 message_id : 329620
を含むドキュメントは両方のデータセンターに複製される可能性があります。 アプリケーションは、読み取り操作の一部として重複を解決する必要があります。
読み取り時に重複したドキュメントを解決
アプリケーションの切り替えロジックにより、ドキュメントの重複が可能になります。 読み取りを実行する際、アプリケーションはアプリケーション層上の重複するドキュメントを解決します。
次のクエリは、 userid
が123
であるドキュメントを検索します。 userid
はシャードキーの一部ですが、クエリにはdatacenter
フィールドが含まれていないため、対象を絞った読み取り操作は実行されないことに注意してください。
db.collection.find( { "userid" : 123 } )
結果には、 329620
のmessage_id
を持つドキュメントが MongoDB に 2 回挿入されたことが示されています。これは遅延書込み (write) 確認応答が原因と考えられます。
{ "_id" : ObjectId("56f08c447fe58b2e96f595fa"), "message_id" : 329620 "datacenter" : "alfa", "userid" : 123, data : {...} } { "_id" : ObjectId("56f08c457fe58b2e96f595fb"), "message_id" : 329620 "datacenter" : "bravo", "userid" : 123, ... }
アプリケーションは、重複を無視して 2 つのドキュメントの 1 つを取得するか、ドキュメントが 1 つだけになるまで重複を削除しようとします。
重複を削除する方法の 1 つは、 ObjectId.getTimestamp()
メソッドを使用して_id
フィールドからタイムスタンプを抽出することです。 その後、アプリケーションは最初に挿入されたドキュメントまたは最後に挿入されたドキュメントを保持できます。 これでは、 _id
フィールドが MongoDB ObjectId()
を使用していることが前提となります。
たとえば、 ObjectId("56f08c447fe58b2e96f595fa")
が含まれるドキュメントでgetTimestamp()
を使用すると、次の値が返されます。
ISODate("2016-03-22T00:05:24Z")
ObjectId("56f08c457fe58b2e96f595fb")
とともにドキュメントでgetTimestamp()
を使用すると、次の結果が返されます。
ISODate("2016-03-22T00:05:25Z")