第22章 DRBDの内部

目次

22.1. DRBDメタデータ
22.1.1. 内部メタデータ
22.1.2. 外部メタデータ
22.1.3. メタデータサイズの見積り
22.2. 世代識別子
22.2.1. データ世代
22.2.2. 世代識別子タプル
22.2.3. 世代識別子の変化
22.2.4. 世代識別子とDRBDの状態
22.3. アクティビティログ
22.3.1. 目的
22.3.2. アクティブエクステント
22.3.3. アクティビティログの適切なサイズの選択
22.4. クイック同期ビットマップ
22.5. peer fencingインタフェース

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

22.1. DRBDメタデータ

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

このメタデータは 内部 または 外部 に格納されます。格納する場所はリソースごとに設定できます。

22.1.1. 内部メタデータ

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

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

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

[注意]注意

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

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

以下のいずれかの方法でこれを避けることができます。

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

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

22.1.2. 外部メタデータ

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

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

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

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

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

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

[注記]注記

外部メータデータは少なくとも1MBのデバイスサイズを必要とします。

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

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

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

metadata-size-exact

Cs はセクタ単位のデータデバイスサイズです。N は対向ノードの数です。

[注記]注記

デバイスサイズは(バイト単位で) blockdev --getsize64 <device> を実行して取得できます。MBに変換するときは1048576で割ってください(= 220または10242)

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

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

metadata-size-approx

22.2. 世代識別子

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

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

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

22.2.1. データ世代

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

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

つまり、リソースのコネクションステータスが Connected になり、両方のノードのディスク状態が UpToDate になると、両方のノードの現在のデータ世代が同一になります。逆も同様です。 現在はノードのロール(プライマリ/セカンダリ)を表すために最下位ビットを使用しています。そのため、同じデータ世代であってもあるノードでは最下位ビットが異なることがあります。

データ世代は8バイトで定義される、全体でユニークな識別子(UUID)です。

22.2.2. 世代識別子タプル

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

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

ビットマップUUID. リモードホストごとに変更を追跡しているオンディスクのビットマップの世代のUUIDです。オンディスク同期ビットマップ自体と同様に、リモートホストと切断されてい場合のみ意味を持ちます。

履歴UUID. 現在のものより以前のデータ世代の識別子で、リモートホストごとに1スロットです。

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

22.2.3. 世代識別子の変化

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

それがネットワーク障害であれ、意図的なものであれ、プライマリ のノードが対向ノードへのコネクションを失うと、DRBDは次のようにしてローカルの世代識別子を変更します。

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

gi-changes-newgen

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

22.2.3.2. 再同期の完了

再同期が完了すると、同期対象は同期元のGIタプルをすべて適用します。

同期元は元のUUIDを維持し、新しいUUIDは作成しません。

22.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つも検出できない場合です。この場合DRBDは、"Unrelate data"という警告をログに書き込んでコネクションを切断します。これは、相互にまったく関連のない2つのクラスタノードが誤って接続された場合に備えるDRBDの機能です。

22.3. アクティビティログ

22.3.1. 目的

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

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

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

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

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

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

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

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

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

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

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

al-extents

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

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

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

al-extents-example

また、最後に付け加えると、DRBD9ではデータを他のセカンダリノードへ同期させるので、セカンダリノードでもALを維持する必要があります。

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

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

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

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

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

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

[注記]注記

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

22.5. peer fencingインタフェース

DRBDにはレプリケーションリンクが途切れたときに対向ノードをフェンシング[18]するよう定義されたインタフェースがあります。Heartbeatに同梱の drbd-peer-outdater ヘルパーはこのインタフェースのリファレンス実装です。ただし、独自のpeer fencingヘルパープログラムも簡単に実装できます。

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

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

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

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

表22.1 fence-peer ハンドラの終了コード

終了コード意味

3

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

4

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

5

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

6

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

7

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




[18] フェンシングとSTONITHについてはhttp://clusterlabs.org/doc/crm_fencing.htmlの対応するPacemakerのページをご参照ください

[19] ネットワークリンク切断によるTCPタイムアウト、 ping-timeout、またはカーネルによるコネクション中断など