web-dev-qa-db-ja.com

二次の無限の回復状態

MongoDB 3.0.2で、プライマリ、セカンダリ、アービターを1つずつ使用してレプリケーションセットを構築します。プライマリとアービターは同じホスト上にあり、セカンダリは別のホスト上にあります。

書き込みの過負荷が増大すると、セカンダリはプライマリに追随できなくなり、回復状態になります。プライマリのホスト上のMongoShellによってセカンダリサーバーにログを記録できるため、プライマリはセカンダリに接続できます。

すべての操作を停止し、コマンドrs.status()を使用してセカンダリの状態を監視し、セカンダリでコマンドrs.syncFrom("primary's ip:port")を入力します。

次に、rs.status()コマンドの結果は、セカンダリのoptimeDateがプライマリのoptimeDateよりもはるかに遅れており、1つのメッセージが次のように断続的に表示されることを示しています。

"set" : "shard01", "date" : ISODate("2015-05-15T02:10:55.382Z"), "myState" : 3, "members" : [ { "_id" : 0, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 135364, "optime" : Timestamp(1431655856, 6), "optimeDate" : ISODate("2015-05-15T02:10:56Z"), "lastHeartbeat" : ISODate("2015-05-15T02:10:54.306Z"), "lastHeartbeatRecv" : ISODate("2015-05-15T02:10:53.634Z"), "pingMs" : 0, "electionTime" : Timestamp(1431520398, 2), "electionDate" : ISODate("2015-05-13T12:33:18Z"), "configVersion" : 3 }, { "_id" : 1, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 135364, "lastHeartbeat" : ISODate("2015-05-15T02:10:53.919Z"), "lastHeartbeatRecv" : ISODate("2015-05-15T02:10:54.076Z"), "pingMs" : 0, "configVersion" : 3 }, { "_id" : 2, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 3, "stateStr" : "RECOVERING", "uptime" : 135510, "optime" : Timestamp(1431602631, 134), "optimeDate" : ISODate("2015-05-14T11:23:51Z"), "infoMessage" : "could not find member to sync from", "configVersion" : 3, "self" : true } ], "ok" : 1

"infoMessage": "同期元のメンバーが見つかりませんでした"

プライマリとアービターはどちらもOKです。このメッセージの理由と、セカンダリの状態を「回復中」から「セカンダリ」に変更する方法を知りたいです。

8
tottishi05

問題(おそらく)

プライマリの最後の操作は「2015-05-15T02:10:56Z」からですが、セカンダリになる最後の操作は「2015-05-14T11:23:51Z」からです。これはおおよその違いです。 15時間。そのウィンドウは、レプリケーションoplogウィンドウ(oplogの最初と最後の操作エントリの時間の差)をはるかに超える可能性があります。簡単に言うと、プライマリでの操作が多すぎて、セカンダリが追いつくことができません。

もう少し複雑です(簡略化されていますが)。最初の同期中、2次同期元のデータは、特定の時点のデータです。その時点のデータが同期されると、セカンダリはoplogに接続し、oplogエントリに従って、その時点と現在の間に行われた変更を適用します。これは、oplogが上記の時点までのすべての操作を保持している限りうまく機能します。ただし、oplogのサイズには制限があります(いわゆる 上限付きコレクション )。したがって、最初の同期中にoplogが保持できるよりも多くの操作がプライマリで発生している場合、最も古い操作が「フェードアウト」します。セカンダリは、プライマリと同じデータを「構築」するために必要なすべての操作が利用できるわけではないことを認識し、同期の完了を拒否し、RECOVERYモードのままにします。

ソリューション

この問題は既知の問題であり、バグではありませんが、MongoDBの内部動作と、開発チームによるいくつかのフェイルセーフの仮定の結果です。したがって、状況に対処するいくつかの方法があります。残念ながら、データを保持するノードは2つしかないため、すべてダウンタイムが発生します。

オプション1:oplogサイズを増やす

これは私の好みの方法です。問題を一度だけ、そして(一種の)すべての問題に対処するからです。ただし、他のソリューションよりも少し複雑です。高レベルの観点から、これらはあなたが取るステップです。

  1. プライマリをシャットダウンします
  2. データファイルへの直接アクセスを使用して、oplogのバックアップを作成します
  3. スタンドアロンモードでmongodを再起動します
  4. 現在のoplogを一時的なコレクションにコピーします
  5. 現在のoplogを削除します
  6. 希望のサイズでoplogを再作成します
  7. 一時的なコレクションから光沢のある新しいoplogにoplogエントリをコピーして戻します
  8. レプリカセットの一部としてmongodを再起動します

セカンダリのoplogを増やすことを忘れないでください。これは、将来のある時点でプライマリになる可能性があるためです。

詳細については、レプリカセットのメンテナンスに関するチュートリアルの "oplogのサイズを変更する" をお読みください。

オプション2:同期中にアプリをシャットダウンする

オプション1が実行可能でない場合、他の唯一の解決策は、アプリケーションをシャットダウンしてレプリカセットに負荷をかけ、同期を再開して、完了しすぎるのを待つことです。転送するデータ量にもよりますが、数時間で計算してください。

個人的なメモ

Oplogウィンドウの問題はよく知られています。レプリカセットとシャードクラスターはMongoDBを使用して簡単にセットアップできますが、それらを適切に維持するには、かなりの知識と経験が必要です。基本を知らずに、複雑なセットアップでデータベースほど重要なものを実行しないでください。何か悪い(tm)が発生した場合、FUBARの状況につながる可能性があります。

9

別のオプション(プライマリに正常なデータがあると仮定)は、セカンダリのmongoデータフォルダー内のデータを削除して再起動することです。これにより、レプリカセットに追加したかのように、プライマリに同期して戻ります。

9
Steffan Perry

レプリカセットに4番目の新しいノードを追加します。同期したら、古いセカンダリをリセットします。

0
Gabriel