第17章 DRBDの内部

目次

17.1. DRBDメタデータ
17.1.1. 内部メタデータ
17.1.2. 外部メタデータ
17.1.3. メタデータサイズの見積り
17.2. 世代識別子
17.2.1. データの世代
17.2.2. 世代識別子タプル
17.2.3. 世代識別子の変化
17.2.4. 世代識別子とDRBDの状態
17.3. アクティビティログ
17.3.1. 目的
17.3.2. アクティブエクステント
17.3.3. アクティビティログの適切なサイズの選択
17.4. クイック同期ビットマップ
17.5. peer fencingインタフェース

この章ではDRBDの内部アルゴリズムと内部構造について、いくつか の背景情報を取り上げます。これは、DRBDの背景について関心のあるユーザが対象です。DRBD開発者が参考にできるほど深い内容には踏み込んでいません。開発者の方は「資料」に記載された文書やDRBDリソースソースコードを参照してください。

17.1. DRBDメタデータ

DRBDはレプリケートするデータに関するさまざまな情報を専用の領域に格納しています。このメタデータには次のようなものがあります。

このメタデータは 内部 または 外部に格納されます。いずれの方法で格納するかは、リソースごとに設定できます。

17.1.1. 内部メタデータ

内部メタデータを使用するようにリソースを設定すると、DRBDはメタデータを実際の本稼働データと同じ下位レベルの物理デバイスに格納します。デバイスの 末尾 の領域がメタデータを格納するための領域として確保されます。

メリット. メタデータは実際のデータと密接にリンクされているため、ハードディスクに障害が発生しても、管理者は特に何かする必要はありません。メタデータは実際のデータとともに失われ、ともに復元されます。

デメリット. RAIDセットではなく、下位レベルデバイスが唯一の物理ハードディスクの場合は、内部メタデータが原因で書き込みスループットが低下することがあります。アプリケーションによる書き込み要求の実行により、DRBDのメタデータの更新が引き起こされる場合があります。メタデータがハードディスクの同じ磁気ディスクに格納されている場合は、書き込み処理によって、ハードディスクの書き込み/読み取りヘッドが2回余分に動作することになります。

[注意]注意

すでにデータが書き込まれているディスク領域を下位デバイスに指定してDRBDでレプリケートする場合で、内部メタデータを使うには、DRBDのメタデータに必要な領域を 必ず 確保してください。

そうでない場合、DRBDリソースの作成時に、新しく作成されるメタデータによって下位レベルデバイスの末尾のデータが上書きされ、既存のファイルが破損します。以下のいずれかの方法でこれを避けることができます。

  • 下位レベルデバイスを拡張します。これには、LVMなどの論理ボリューム管理機能を使用します。ただし、対応するボリュームグループに有効な空き領域が必要です。ハードウェアストレージソリューションを使用することもできます。
  • 下位レベルデバイスの既存のファイルシステムを縮小します。ファイルシステムによっては実行できない場合があります。
  • 上記2つが不可能な場合は、代わりに外部メタデータを使用します。

下位レベルデバイスをどの程度拡張するか、またはファイルシステムをどの程度縮小するかについては、「メタデータサイズの見積り」を参照してください。

17.1.2. 外部メタデータ

外部メタデータは、本稼働データを格納するものとは異なる個別の専用ブロックデバイスに格納します。

メリット. 一部の書き込み処理では、外部メタデータを使用することにより、待ち時間をいくらか短縮できます。

デメリット. メタデータが実際の本稼働データに密接にリンクされません。つまり、ハードウェア障害により本稼働データだけが破損したか、DRBDメタデータは破損しなかった場合、手動による介入が必要です。生き残ったノードから切り替えるディスクに、手動でデータの完全同期を行う必要があります。

次の項目 すべて に該当する場合には、外部メタデータ使用する以外の選択肢はありません。

  • DRBDでレプリケートしたい領域にすでにデータが格納されている。
  • この既存デバイスを拡張することができない。
  • デバイスの既存のファイルシステムが縮小をサポートしていない。

デバイスのメタデータを格納する専用ブロックデバイスが必要とするサイズにについては「メタデータサイズの見積り」を参照してください。

17.1.3. メタデータサイズの見積り

次の式を使用して、DRBDのメタデータに必要な領域を正確に計算できます。

図17.1 DRBDメタデータサイズの計算(正確)

metadata-size-exact

Cs はセクタ単位のデータデバイスサイズです。

[注記]注記

デバイスサイズは`blockdev --getsz <device>`を実行して取得できます。

結果の Ms もセクタ単位です。MBに変換する場合は2048で割ります(521バイトをセクタサイズとする、s390を除くすべての標準のLinuxプラットフォームの場合)。

実際には、次の計算で得られる大まかな見積りで十分です。この式では、単位はセクタではなくメガバイトである点に注意してください。

図17.2 DRBDメタデータサイズの見積り(概算)

metadata-size-approx

17.2. 世代識別子

DRBDでは 世代識別子 (GI)を使用してレプリケートされたデータの「世代」を識別します。

これはDRBDの内部メカニズムで、次のような目的で使用されます。

  • 2つのノードが実際に同じクラスタのメンバか確認する(2つのノードが誤って接続されたものではないこと確認する)。
  • バックグラウンド同期の方向を確認する(必要な場合)。
  • 完全な再同期が必要か、部分的な再同期で十分か判断する。
  • スプリットブレインを検出する。

17.2.1. データの世代

DRBDは次のような場合に、新しい データ世代 の開始としてマークを付けます。

  • デバイスの初期フル同期。
  • 切断したリソースがプライマリロールに切り替わる。
  • プライマリロールのリソースが切断する。

つまり、リソースの接続状態が Connected になり、両方のノードのディスク状態が UpToDate になると、両方のノードの現在のデータ世代が同一になります。逆も同様です。逆も同様です。

新規のデータ世代は8バイトのUUID (Universally Unique Identifier)で識別されます。

17.2.2. 世代識別子タプル

DRBDでは、現在と履歴のデータ世代について4組の情報がローカルリソースメタデータに格納されます。

現在UUID. これは、ローカルノードからみた最新のデータ世代の世代識別子です。リソースが Connected になり完全に同期されると、両ノードの現在UUIDが同一になります。

Bitmap UUID. これは、オンディスク同期ビットマップにより変更が追跡されている世代のUUIDです。オンディスク同期ビットマップ自体については、切断モードの間のみこの識別子が意味を持ちます。リソースが Connected の場合は、このUUIDは常に空(ゼロ)です。

2つの履歴UUID. これらは現在の世代より前の2つのデータ世代識別子です。

まとめて、これら4つを 世代識別子タプル、または略して「GIタプル」と呼びます。

17.2.3. 世代識別子の変化

17.2.3.1. 新規データ世代の開始

ネットワーク障害や手動の介入によりノードが対向ノードとの接続を失うと、DRBDは次のようにローカル世代識別子を変更します。

図17.3 新規データ世代の開始時に変化するGIタプル

gi-changes-newgen

  1. 新規データ世代に対して新規UUIDが作成されます。これが、プライマリノードの新しい現在UUIDになります。
  2. 以前のUUIDは、ビットマップが変更を追跡している世代を参照します。したがって、これがプライマリノードの新しいビットマップUUIDになります。
  3. セカンダリノードではGIタプルは変化しません。

17.2.3.2. 再同期の開始

再同期を開始すると、DRBDはローカルの世代識別子に対して次のような変更を行います。

図17.4 再同期開始時のGIタプルの変化

gi-changes-syncstart

  1. 同期元の現在UUIDは変化しません。
  2. 同期元のビットマップUUIDが循環して、第1の履歴UUIDになります。
  3. 同期元で新規のビットマップUUIDが生成されます。
  4. このUUIDが同期先の新しい現在UUIDになります。
  5. 同期先のビットマップUUIDと履歴UUIDは変化しません。

17.2.3.3. 再同期の完了

再同期が完了すると、次のような変更が行われます。

図17.5 再同期完了時のGIタプルの変化

gi-changes-synccomplete

  1. 同期元の現在UUIDは変化しません。
  2. 同期元のビットマップUUIDが循環して第1の履歴UUIDになり、第1のUUIDが第2の履歴UUIDに移動します。第2の履歴UUIDがすでに存在する場合は破棄されます。
  3. 次に、同期元のビットマップUUIDが空(ゼロ)になります。
  4. 同期先は、同期元からGIタプル全体を取得します。

17.2.4. 世代識別子とDRBDの状態

ノード間の接続が確立すると、2つのノードは現在入手可能な世代識別子を交換し、それに従って処理を続行します。結果は次のようにいくつか考えられます。

両ノードの現在UUIDが空の場合. ローカルノードと対向ノードの両方で現在UUIDが空の状態です。新規に構成され、初回フル同期が完了していない場合は、通常この状態です。同期が開始していないため、手動で開始する必要があります。

1つのノードの現在UUIDが空の場合. 対向ノードの現在UUIDが空で、自身は空でない場合です。これは、ローカルノードを同期元とした初期フル同期が進行中であることを表します。初期フル同期の開始時に、ローカルノードのDRBDはディスク上の同期ビットマップのすべてのビットを1にして、ディスク全体が非同期だと マークします。その後ローカルノードを同期元とした同期が始まります。逆の場合(ローカルの現在UUIDが空で、対向ノードが空でない場合)は、DRBDは同様のステップをとります。ただし、ローカルノードが同期先になります。

現在UUIDが等しい場合. ローカルの現在UUIDと対向ノードの現在UUIDが空はなく、同じ値を持っている状態です。両ノードがともにセカンダリで、通信切断中にどのノードもプライマリにならなかったことを表します。この状態では同期は必要ありません。

ビットマップUUIDが対向ノードの現在UUIDと一致する場合. ローカルノードのビットマップUUIDが対向ノードの現在UUIDと一致し、対向ノードのビットマップUUIDが空の状態です。これは、ローカルノードがプライマリで動作している間にセカンダリノードが停止して再起動したときに生じる正常な状態です。これは、リモートノードは決してプライマリにならず、ずっと同じデータ世代にもとづいて動作していたことを意味します。この場合、ローカルノードを同期元とする通常のバックグラウンド再同期が開始します。逆に、ローカルノード 自身の ビットマップUUIDが空で、対向ノードの ビットマップがローカルノードの現在UUIDと一致する状態の場合。これはローカルノードの再起動に伴う正常な状態です。この場合、ローカルノードを同期先とする通常のバックグラウンド再同期が開始します。

現在UUIDが対向ノードの履歴UUIDと一致する場合. ローカルノードの現在UUIDが対向ノードの履歴UUIDのうちの1つと一致する状態です。これは過去のある時点では同じデータを持っていたが、現在は対向ノードが最新のデータを持ち、しかし対向ノードのビットマップUUIDが古くなって使用できない状態です。通常の部分同期では不十分なため、ローカルノードを同期元とするフル同期が開始します。DRBDはデバイス全体を非同期状態とし、ローカルノードを同期先とするバックグラウンドでのフル再同期を始めます。逆の場合(ローカルノードの履歴UUIDのうち1つが対向ノードの現在UUIDと一致する)、DRBDは同様のステップを行いますが、ローカルノードが同期元となります。

ビットマップUUIDが一致し、現在UUIDが一致しない場合. ローカルノードの現在UUIDが対向ノードの現在UUIDと異なるが、ビットマップUUIDは一致する状態はスプリットブレインです。ただし、データ世代は同じ親を持っています。この場合、設定されていればDRBDがスプリットブレイン自動回復ストラテジが実行されます。設定されていない場合、DRBDはノード間の通信を切断し、手動でスプリットブレインが解決されるまで待機します。

現在UUIDもビットマップUUIDも一致しない場合. ローカルノードの現在UUIDが対向ノードの現在UUIDと異なり、ビットマップUUIDも 一致しない 状態です。これもスプリットブレインで、しかも過去に同一のデータ状態であったという保証もありません。したがって、自動回復ストラテジが構成されていても役に立ちません。DRBDはノード間通信を切断し、手動でスプリットブレインが解決されるまで待機します。

いずれのUUIDも一致しない場合. 最後は、DRBDが2つのノードのGIタプルの中に一致するものを1つも検出できない場合です。この場合は、関連のないデータと、切断に関する警告がログに記録されます。これは、相互にまったく関連のない2つのクラスタノードが誤って接続された場合に備えるDRBDの機能です。

17.3. アクティビティログ

17.3.1. 目的

書き込み操作中に、DRBDは書き込み操作をローカルの下位ブロックデバイスに転送するだけでなく、ネットワークを介して送信します。実用的な目的で、この2つの操作は同時に実行されます。タイミングがランダムな場合は、書込み操作が完了しても、ネットワークを介した転送がまだ始まっていないといった状況が発生する可能性があります。

この状況で、アクティブなノードに障害が発生してフェイルオーバが始まると、このデータブロックのノード間の同期は失われます。障害が発生したノードにはクラッシュ前にデータブロックが書き込まれていますが、レプリケーションはまだ完了していません。そのため、ノードが回復しても、このブロックは回復後の同期のデータセット中から取り除かれる必要があります。さもなくば、クラッシュしたノードは生き残ったノードに対して「先書き」状態となり、レプリケーションストレージの「オール・オア・ナッシング」の原則に違反してしまいます。これはDRBDだけでなく、実際、すべてのレプリケーションストレージの構成で問題になります。バージョン0.6以前のDRBDを含む他の多くのストレージソリューションでは、アクティブなノードに障害が発生した場合、回復後にそのノードを改めてフル同期する必要があります。

バージョン0.7以降のDRBDは、これとは異なるアプローチを採用しています。アクティビティログ (AL)は、メタデータ領域にに格納され、「最近」書き込まれたブロックを追跡します。この領域は ホットエクステント と呼ばれます。

アクティブモードだったノードに一時的な障害が発生し、同期が行われる場合は、デバイス全体ではなくALでハイライトされたホットエクステントだけが同期されます。これによって、アクティブなノードがクラッシュしたときの同期時間を大幅に短縮できます。

17.3.2. アクティブエクステント

アクティビティログの設定可能なパラメータに、アクティブエクステントの数があります。アクティブエクステントは4MiB単位でプライマリのクラッシュ後に再送されるデータ量に追加されますこのパラメータは、次の対立する2つの状況の折衷案としてご理解ください。

アクティブエクステントが多い場合. 大量のアクティビティログを記録すれば書き込みスループットが向上します。新しいエクステントがアクティブになるたびに、古いエクステントが非アクティブにリセットされます。この移行には、メタデータ領域への書き込み操作が必要です。アクティブエクステントの数が多い場合は、古いアクティブエクステントはめったにスワップアウトされないため、メタデータの書き込み操作が減少し、その結果パフォーマンスが向上します。

アクティブエクステントが少ない場合. アクティビティログが小さい場合は、アクティブなノードが障害から回復した後の同期時間が短くなります。

17.3.3. アクティビティログの適切なサイズの選択

エクステントの数は所定の同期速度における適切な同期時間にもとづいて定義します。アクティブエクステントの数は次のようにして算出できます。

図17.6 同期速度とターゲットの同期時間にもとづくアクティブエクステントの計算

al-extents

R はMB/秒単位の同期速度、tsync は秒単位のターゲットの同期時間です。E は求めるアクティブエクステントの数です。

スループット速度が90MiByte/秒のI/Oサブシステムがあり、同期速度が30MiByte/sに設定されているとします(R =30)。ターゲットの同期時間は4分(240秒)を維持する必要があります。(tsync =240):

図17.7 同期速度とターゲット同期時間にもとづくアクティブエクステントの計算(例)

al-extents-example

正確な計算結果は1800ですが、DRBDのAL実装のハッシュ関数はエクステントの数が素数に設定されている場合に最適に動作します。したがって、ここでは1801を選択します。

17.4. クイック同期ビットマップ

クイック同期ビットマップはDRBDがリソースごとに使用する内部データ構造で、同期ブロック(両方のノードで同一)または非同期ブロックを追跡します。ビットマップはノード間通信が切断しているときのみ使われます。

クイック同期ビットマップでは、1ビットが4KiBチャンクのオンディスクデータを表します。ビットがクリアされていれば、対応するブロックが対向ノードと同期しています。つまり、切断以降、ブロックに書き込まれていないということです。逆に、ビットが設定されていればブロックが変更されているため、接続が再確立したらすぐに再同期を行う必要があります。

スタンドアロンノードでディスクにデータが書き込まれると、クイック同期ビットマップのへの書き込みも始まります。ディスクへの同期的なI/Oは負荷が大きいため、実際にはメモリ上のビットマップのビットが設定されます。アクティビティログ)が期限切れになってブロックがコールドになると、メモリ上のビットマップがディスクに書き込まれます。同様に、生き残ったスタンドアロンのノードでリソースが手動でシャットダウンされると、DRBDは すべての ビットマップをディスクにフラッシュします。

リモートノードが回復するか接続が再確立すると、DRBDは両方のノードのビットマップ情報を照合して、再同期が必要な すべてのデータ領域 を決定します。同時に、DRBDは世代識別子を調べ、同期の 方向 を決定します。

同期元ノードが同期対象ブロックを対向ノードに送信し、同期先が変更を確認すると、ビットマップの同期ビットがクリアされます。別のネットワーク障害などで再同期が中断し、その後再開すると、中断した箇所から同期を続行します。中断中にブロックが変更された場合、もちろんそのブロックが再同期データセットに追加されます。

[注記]注記

drbdadm pause-syncdrbdadm resume-sync コマンドを使用して、再同期を手動で一時停止したり再開することもできます。ただしこれは慎重に行ってください。再同期を中断すると、セカンダリノードのディスクが必要以上に長く Inconsistent 状態になります。

17.5. peer fencingインタフェース

DRBDは、レプリケーションリンクが遮断したときに、対向ノードを切り離すメカニズムとして定義されたインタフェースを備えています。Heartbeatに同梱の drbd-peer-outdater ヘルパーはこのインタフェースのリファレンス実装です。ただし、独自のpeer fencingヘルパープログラムも簡単に実装できます。

fencingヘルパーは次のすべてを満たす場合にのみ呼び出されます。

  1. リソース(またはcommon)の handlers セクションで fence-peer ハンドラが定義されている。
  2. fencing オプションで、resource-only または resource-and-stonith が設定されている。
  3. レプリケーションリンクの中断時間が、DRBDがネットワーク障害を検出するために十分である。

fence-peer ハンドラとして指定されたプログラムかスクリプトが呼び出されると、DRBD_RESOURCEDRBD_PEER 環境変数が利用できるようになります。これらの環境変数には、それぞれ、影響を受けるDRBDリソース名と対向ホストのホスト名が含まれています。

peer fencingヘルパープログラム(またはスクリプト)は、次のいずれかの終了コードを返します。

  1. fence-peer ハンドラの終了コード
終了コード意味

3

対向ノードのディスク状態がすでに Inconsistent になっている。

4

対向ノードのディスク状態が正常に Outdated に設定された(または最初から Outdated だった。)

5

対向ノードへの接続に失敗。対向ノードに到達できなかった。

6

影響を受けるリソースがプライマリロールになっていたため、対向ノードを無効にできなかった。

7

対向ノードがクラスタから正常にフェンシングされた。影響を受けるリソースの fencingresource-and-stonith に設定しておかなければ発生しない。