DRBD.CONF(5) 設定ファイル DRBD.CONF(5)

drbd.conf - DRBD デバイスの設定ファイル

/etc/drbd.conf ファイルは drbdadm コマンドから読み込まれる。

本ファイルの形式は、クラスタを構成する 2 つのノード間でそのままコピーしても問題がないようにデザインされている。設定を管理しやすくするため、設定ファイルをそのままコピーすることを強く推奨する。/etc/drbd.conf ファイルは、クラスタを構成する 2 つのノードで同じ内容でなければならない。/etc/drbd.conf への変更はただちに反映されるものではない。

通例、メイン設定ファイルは 2 つのインクルードステートメントが含まれている。1 つ目は /etc/drbd.d/global_common.conf であり、2 つ目は .res の付いたすべてのファイルのサフィックスである。

resource r0 {
	net {
		protocol C;
		cram-hmac-alg sha1;
		shared-secret "FooFunFactory";
	}
	disk {
		resync-rate 10M;
	}
	on alice {
		volume 0 {
			device    minor 1;
			disk      /dev/sda7;
			meta-disk internal;
		}
		address   10.1.1.31:7789;
	}
	on bob {
		volume 0 {
			device    minor 1;
			disk      /dev/sda7;
			meta-disk internal;
		}
		address   10.1.1.32:7789;
	}
}

上の例は r0 という名前の 1 つの DRBD リソースを設定している。ノード間の通信プロトコルは C である。ホスト alice では 1 つのボリューム含んでいて、 /dev/drbd1 をアプリケーション用のデバイスとして使用し、/dev/sda7 をデータ用の下位デバイスとしている。IP アドレスには 2 ノード間の通信に使うネットワークインタフェースの IP アドレスを指定している。DRBD の再同期には 10 メガバイト/秒の帯域幅を使うことができる。この resync-rate ステートメントはボリューム 0 に対して有効だが、追加のボリュームにも有効である。この例では各ボリュームに 10MB/秒フルで指定している。

1つの drbd.conf に複数のリソースセクションを書くこともできる。他の設定例については DRBD User's Guide[1] を参照

本ファイルはセクションとパラメータで構成される。各セクションはキーワードで始まり、任意指定のパラメータ、開き中括弧 (“{”) で始まる。閉じ中括弧 (“}”) でセクションが終わる。中括弧はパラメータを囲むのにも使われる。

section [name] { parameter value; [...] }

パラメータ名と値の間にホワイトスペースが必要である。パラメータ名の後ろの文字列はパラメータに対する値と見なされる。ブールパラメータは特別なパラメータで、パラメータ名だけで構成される。パラメータの最後にセミコロン (“;”) が必要である。

いくつかのパラメータ値はデフォルトの単位を持つが、 K 、 M 、または G を明示的に指定することによって単位を変えられる。これらの単位はコンピュータでおなじみの方法で定義される (K=2^10=1024, M=1024K, G=1024M)。

設定ファイルにコメントを記述できる。コメント行はハッシュ記号 (“#”) で始まらなければならない。この文字以降行末までの文字がコメントと見なされる。

skip
このセクション内のテキストは、複数行にわたってすべてコメントと見なされる。キーワードの skip と開き中括弧 (“{”) の間にある文字は無視される。中括弧で囲まれたすべてが無視される。何か 'resource [name] {...}' セクションをコメントアウトしたいとき、 'skip' を前に置けばよいので便利である。

global

いくつかの全般的なパラメータを記述する。現在 minor-count, dialog-refresh, disable-ip-verification, usage-count が許可されている。global セクションは 1 回だけ記述でき、設定ファイルの先頭に書くのが望ましい。

common

common セクションに記述したパラメータはすべてのリソースに継承される。このセクションには、 startup, options, handlers, net, disk セクションがある。

resource name

DRBD リソースを定義するセクションである。各リソースセクションは、 2 つ (またはそれ以上) の on host セクションを持つ必要があり、必要に応じて startup, options, handlers, net, disk セクションを書くことができる。volume セクションを含ませることもできる。

on host-name

このセクションを取り囲む resource セクションの中の DRBD デバイスの設定を指定する。host-name は必須で、各ノードの Linux ホスト名 (uname -n) でなければならない。複数のホスト名を指定しても構わないが、この場合、それぞれのホストは同じ設定でなければならない。ただし、 IP アドレスに関しては、複数のホストの間で変更する必要がある。もしくは、このセクションを複数指定できる。

	resource r1 {
		protocol C;
		device minor 1;
		meta-disk internal;
		on alice bob {
			address 10.2.2.100:7801;
			disk /dev/mapper/some-san;
		}
		on charlie {
			address 10.2.2.101:7801;
			disk /dev/mapper/other-san;
		}
		on daisy {
			address 10.2.2.103:7801;
			disk /dev/mapper/other-san-as-seen-from-daisy;
		}
	}
	

floating セクションのキーワードも参照すること。このセクションでの必要なステートメントは addressvolume である。上位互換性と利便性のため、直接ホストセクションに 1 つのボリュームのステートメントを埋め込むことが有効である。

volume vnr

コネクションの範囲でボリュームを定義する。別のホストでは、レプリケートされたボリュームのマイナー番号が異なっている事があるため、ボリューム番号 (vnr) はこれらを結びつける。このセクションで必要なパラメータは device, disk, meta-disk である。

stacked-on-top-of resource

3 または 4 ノード構成のときのスタックした DRBD リソース(上位リソース)を指定するときに、on セクションの代わりに stacked-on-top-of を指定する。このセクションには device, address が必須である。

floating AF addr:port

このセクションを取り囲む resource セクションの中の DRBD デバイスの設定を指定する。このセクションは、on セクションと非常に類似性がある。on セクションとの違いは、ホスト名ではなく IP アドレスでホスト名を照合することである。このセクションには、 device, disk, meta-disk が必要である。これらのパラメータを resource セクションに記述すると、このセクションはこれらの値を継承できる。すべてを継承する場合、 IP アドレスを指定するだけでよい。

	resource r2 {
		protocol C;
		device minor 2;
		disk      /dev/sda7;
		meta-disk internal;
		# short form, device, disk and meta-disk inherited
		floating 10.1.1.31:7802;
		# longer form, only device inherited
		floating 10.1.1.32:7802 {
			disk /dev/sdb;
			meta-disk /dev/sdc8;
		}
	}
	

disk

このセクションは、下位ストレージに対する DRBD の取り扱いをチューニングするパラメータで構成される。詳細は次のドキュメントを参照: drbdsetup(8) 。指定できるパラメータは次のとおり: on-io-error, size, fencing, disk-barrier, disk-flushes, disk-drain, md-flushes, max-bio-bvecs, resync-rate, resync-after, al-extents, al-updates, c-plan-ahead, c-fill-target, c-delay-target, c-max-rate, c-min-rate, disk-timeout, discard-zeroes-if-aligned, rs-discard-granularity, read-balancing.

net

このセクションは、DRBD のプロパティの取り扱いをチューニングするパラメータで構成される。詳細は次のドキュメントを参照: drbdsetup(8) 。指定できるパラメータは次のとおり: protocol, sndbuf-size, rcvbuf-size, timeout, connect-int, ping-int, ping-timeout, max-buffers, max-epoch-size, ko-count, allow-two-primaries, cram-hmac-alg, shared-secret, after-sb-0pri, after-sb-1pri, after-sb-2pri, data-integrity-alg, no-tcp-cork, on-congestion, congestion-fill, congestion-extents, verify-alg, use-rle, csums-alg, socket-check-timeout.

startup

このセクションは、DRBD のプロパティの取り扱いをチューニングするパラメータで構成される。詳細は次のドキュメントを参照: drbdsetup(8) 。指定できるパラメータは次のとおり: wfc-timeout, degr-wfc-timeout, outdated-wfc-timeout, wait-after-sb, stacked-timeouts and become-primary-on.

options

このセクションはリソースオブジェクトの取り扱いをチューニングするパラメータで構成される。詳細は次のドキュメントを参照: drbdsetup(8) 。指定できるパラメータは次のとおり: cpu-mask, and on-no-data-accessible.

handlers

このセクションでは、特定のイベントへに応答して DRBD によって起動される(実行可能な)ハンドラを指定できる。指定できるパラメータは次のとおり: pri-on-incon-degr, pri-lost-after-sb, pri-lost, fence-peer (formerly oudate-peer), local-io-error, initial-split-brain, split-brain, before-resync-target, after-resync-target.

環境変数がインタフェースとなる:

DRBD_RESOURCE はリソース名である。

DRBD_MINOR は DRBD デバイスの 10 進法のマイナー番号である。

DRBD_CONF はプライマリ設定ファイルへの入り口である。設定を複数ファイルに分割した場合 (例えば /etc/drbd.conf.d/ など) には、あまり役にたたない。

DRBD_PEER_AF , DRBD_PEER_ADDRESS , DRBD_PEERS はそれぞれ、アドレスファミリ (ipv6 など)、対向ホストのアドレス、対向ホストのホスト名となる。

DRBD_PEER は推奨しない。

これらの設定がすべてのハンドラに設定されるわけではない。いくつかの値は floating 設定では無効になる。

minor-count count
count には 1 から 1048575 の値を指定できる。

Minor-count は DRBD のサイジングための手がかりである。これは様々なメモリプールを適正サイズにするのに役立つ。実際に使っているマイナー番号よりも大きな数を順に指定しなければいけない。デフォルトでは、現在定義されているリソースの数に加えてさらに 11 個のリソースを定義できる。ただし最低でも 32 個は定義できる。

dialog-refresh time

time は 0 または正の数を指定する。

ユーザダイアログは time 秒ごとに秒を作画する (time が 0 だと再作画しない)。デフォルト値は 1 である。

disable-ip-verification

何らかの理由で drbdadm が ip または ifconfig コマンドで正常さを確認できない場合 disable-ip-verification を指定する。このオプションを指定することによって、 IP アドレスを検証しないようにできる。

udev-always-use-vnr

udev が drbdadm にデバイス関連のシンボリックリンクのリストを要求すると、drbdadm は、リソースに明示的な volume VNR { } 定義があるか、暗黙的なボリューム番号 0 を持つ単一のボリュームしかないかによって、異なる命名規則でシンボリックリンクを提示する:

# implicit single volume without "volume 0 {}" block
DEVICE=drbd<minor>
SYMLINK_BY_RES=drbd/by-res/<resource-name>
# explicit volume definition: volume VNR { }
DEVICE=drbd<minor>
SYMLINK_BY_RES=drbd/by-res/<resource-name>/VNR

global セクションでこのパラメータを定義すると、drbdadm は常に .../VNR の部分を追加し、ボリューム定義が暗黙的であるか明示的であるかを気にしない。

過去との互換性のために、これはデフォルトでは無効になっているが、有効にすることを推奨する。

usage-count val

DRBD の利用者統計[2] に参加する。最も簡単な方法は、このオプションを yes に指定する。指定できる値は yes, no, ask である。

protocol prot-id

DRBD の TCP/IP の通信の際に使われる プロトコル を指定する。指定できるプロトコルは A, B, C である。

プロトコル A: ローカルディスクとローカル TCP 送信バッファにデータを書き込んだらディスクへの書き込みが完了したと判断する。

プロトコル B: ローカルディスクとリモートバッファキャッシュにデータを書き込んだらディスクへの書き込みが完了したと判断する。

プロトコル C: ローカルディスクとリモートディスクの両方にデータを書き込んだらディスクへの書き込みが完了したと判断する。

device name minor nr

定義している DRBD リソースに対応するブロックデバイス名を指定する。アプリケーションでは、ここで指定する名前をデバイス名として指定する(ファイルシステムとして)。逆に、disk に指定したデバイス名を決して指定してはならない。

name, minor, minor number は省略する事ができる。name を省略すると、デフォルトの /dev/drbdminor が使われる。

udev は自動的に /dev/drbd/by-res と /dev/drbd/by-disk の中のシンボリックリンクを作成する。

disk name

DRBD はこのブロックデバイスに実際にデータの読み書きを行う。DRBD 動作中は、このデバイスに絶対に別の方法でアクセスしてはならない。この禁止事項には、次のコマンドやその他の類似コマンドも含まれる: dumpe2fs(8)。

address AF addr:port

それぞれが各対向デバイスからの接続を待ち受けるために、 デバイスごとに全てのリソースに IP アドレス が必要である。AFipv4, ipv6, ssocks or sdp (互換性のため scissocks へのエイリアスになっている) のなかから選択される。IPv4 の場合、これを省略できる。IPv6 を使う場合は、 ipv6 のキーワードに続けて角括弧の中に記載する。例: ipv6 [fd01:2345:6789:abcd::1]:7800。

各 DRBD リソースは、ノードのパートナーデバイスと接続するために TCP port が必要である。2 つの別の DRBD リソースが同じ addr:port の組み合わせを同一ノードで使用することはできない

meta-disk internal,
meta-disk device,
meta-disk device [index]

内部 (internal) を指定すると、下位デバイスの最後の部分にメタデータが作られる。メタデータのサイズはデバイスのサイズから計算される。

device が指定されると、 index がある場合でもない場合でも、 DRBD はそのデバイスにメタデータを保存する。index がない場合、メタデータのサイズはデータデバイスのサイズから決定される。このキーワードは通常 LVM と組み合わせて使用され、様々なサイズのブロックデバイスを扱うときに使用する。メタデータのサイズは 36KB + 下位デバイスのサイズ / 32K であり、4KB 単位で切り上げる。(おおまかな目安として、ストレージサイズ 1GB あたり 32KB のメタデータ領域が必要で、これを MB 単位に切り上げる)。

index が指定されると、各インデックス数は 128MB のメタデータスロットを参照する。これは最大 4TiB まで指定することができる。この方法により複数の DBRD デバイスが同一のメタデータデバイスを共有できるようになる。例えば /dev/sde6[0] と /dev/sde6[1] を使用するとき、 /dev/sde6 は最低でも 256MB 以上でなければいけない。ハードサイズの制限のため、メタディスクのインデックスは推奨されない。

on-io-error handler

下位デバイスが I/O エラーを上位に伝えたときに実行する handler を指定する。

handler には pass_on, call-local-io-error, detach のいずれかを指定できる。

pass_on: ノードはディスクのステータスを inconsistent(不整合) にし、 I/O エラーを起こしたブロックに対応するビットマップにマークをつける。そして、リモートのノード上で入出力を再度行う。

call-local-io-error: ハンドラスクリプト local-io-error を呼び出して実行する。

detach: 低レベルデバイスを切り離して、ディスクレスモードで処理を続行する。

fencing fencing_policy

fencing は、2 つのノードがともにプライマリで切り離された状態 (スプリットブレイン) になる事を防ぐ手段である。

次のフェンシングポリシーを指定できる:

dont-care

デフォルトの設定値で、フェンシングのためのアクションを実行しない。

resource-only

ノードが切り離されたプライマリ状態になると、他ノードを無効状態に変えようとする。この動作は fence-peer ハンドラによって行われる。このハンドラは他ノードにレプリケーション用とは別のネットワーク経由でアクセスし、'drbdadm outdate res' を実行することを想定している。

resource-and-stonith

ノードが切り離されたプライマリ状態になると、 DRBD はすべてのディスク I/O を停止して fence-peer ハンドラを呼び出す。このハンドラには、レプリケーション用とは別のネットワーク経由で他ノードにアクセスし、 'drbdadm outdate res' を実行するという機能を想定している。ハンドラが他ノードに到達できない場合、 DRBD は STONITH 機能を使って他ノードを強制排除する。これらが完了したら、ディスク I/O を再開する。ハンドラが失敗した場合には、 resume-io コマンドでディスク I/O を再開できる。

disk-barrier,
disk-flushes,
disk-drain

DRBD は下位デバイスに対する複数のディスク書き込みの間の依存関係を指定するための 4 種類のオプションを用意している。そのうち、下位デバイスがサポートしていてユーザが無効に設定していない最初のオプションが使用される。デフォルトでは flush メソッドが使われる。

drbd-8.4.2 から disk-barrier は、linux-2.6.36 (及び RHEL6 の 2.6.32) 以降での正常動作が確認できないためデフォルトで無効になった。注意: 有識者による指示のもとでのみ使用すること。

手法を選択するにあたっては、測定可能なパフォーマンスデータのみに頼るべきではない。下位デバイスが揮発性の書き込みキャッシュしか持たない場合 (通常のハードディスクや通常のハードディスクだけで構成される RAID など)、最初の 2 つのオプションのどちらかを使うべきである。下位デバイスにバッテリバックアップ機能付きの書き込みキャッシュがある場合には、3 番目のオプションが利用できる。4番目のオプション (すべてを無効にする場合は "none") は、ほとんどの I/O スタックにおいて危険で、ディスクへの書き込み順序が入れ替わってしまう可能性がある。no-disk-drain を使っては ならない

残念なことに、デバイスマッパ(LVM) はバリアをサポートしていない。

/proc/drbd の "wo:" の文字の後ろに、下位デバイスに対する現在の設定が b, f, d, n の文字で表示される。オプションは次のとおり:

barrier

下位デバイスがバリア (SCSI では "tagged command queuing"、SATA では "native com-mand queuing" と呼ばれる) をサポートしている場合、このオプションを選択できる。このオプションを有効にするには disk-barrier オプションを yes にする。

flush

下位デバイスがディスクフラッシュ (ベンダーは "force unit access" と呼んでいる) をサポートしている場合、このオプションを選択できる。このオプションを無効にするには disk-flushesno に設定する。

drain

3番目の方法は、単純に、最初の書き込みは次の書き込みリクエストを処理する前に吐き出す、方法である。8.0.9 まではこれが唯一のオプションであった。

none

4番目の方法は、no-disk-drain を指定し、下位デバイスへの書き込みの依存関係を一切指示しない方法である。これはほとんどの I/O スタックにおいて 危険 であり、ディスクへの書き込み順序が入れ替わってしまう可能性がある。そうなると、理論的にはデータ破損の原因、または DRBD プロトコルを乱し、再接続と切断を繰り返すような状態に陥る可能性がある。no-disk-drain使ってはならない

md-flushes

メタデータデバイスへのアクセスにあたってバリアやフラッシュを使用しない。 disk-flushes についての説明を参照のこと。

max-bio-bvecs

ある特別な環境において、デバイスマッパースタックは、複数の bvec を持つ制約に違反する BIO を merge_bvec() 関数の4番目の引数に設定し DRBD に渡す。 例えば、物理ディスク → DRBD → LVM → Xen → 誤ったパーティション(63) → DomU FS の場合である。Dom0 のカーネルログには、 "bio would need to, but cannot, be split:" と記録される。

最も良い回避方法は、VM の内部にパーティションを適切に配置する (例えば、セクタ 1024 から開始する) ことである。これは、ストレージ領域を 480 KiB を消費する。残念ながら、ほとんどの Linux パーティションツールは、奇数 (63) でパーティションを開始する。そのため、ほとんどのディストリビューションは、仮想 Linux マシンにインストールを行うと、誤ったパーティションで終了してしまう。第 2 の回避方法は、 BIO あたりの最大 DRBD bvecs (= max-bio-bvecs) を 1 にすることである。しかし、パフォーマンスは低下する。

max-bio-bvecs のデフォルト値は 0 で、これはユーザに制限が無いことを意味する。

disk-timeout

DRBD デバイスがデータを格納する下位レベルデバイスが、指定した disk-timeout 以内で I/O リクエストを完了しない場合、DRBD はこれを障害とみなす。下位デバイスは切り離され、デバイスのディスク状態はディスクレス状態になる。DRBD が 1 台以上の対向ノードに接続したとき、失敗したリクエストはそのうち 1 台に伝えられる。

このオプションは カーネルパニックを引き起こす可能性があり、注意が必要である

リクエストの「中断」あるいはディスクの強制切り離しは、完全に下位デバイスをブロックまたはハンギングして、リクエストをまったく処理せずエラーも処理しなくなる。この状況ではハードリセットとフェイルオーバ以外になす術がない。

「中断」すると、基本的にローカルエラーの完了を装い、すみやかにサービスの移行を行うことで安全な切り替えを行う。それでもなお、影響を受けるノードは "すぐ" に再起動される必要はある。

リクエストを完了することで、上位レイヤーに関連するデータページを再利用させることができる。

後にローカルの下位デバイスが「復帰」すると、ディスクから元のリクエストページへの DMA のデータは、うまくいくと未使用のページへランダムなデータを送るが、多くの場合その間に関係のないデータに変形してしまい、様々なダメージの原因になる。

つまり遅延した正常な完了は、特に読み込みリクエストの場合 panic() の原因になる。遅延した「エラー」完了は、その都度に通知は行うが、問題ないと考えてよい。

disk-timeout のデフォルト値は 0 であり、無限のタイムアウトを意味する。タイムアウトは 0.1 秒単位で指定する。このオプションは DRBD 8.3.12. から利用できる。

discard-zeroes-if-aligned {yes | no}

Linux のブロックデバイスで discard/trim/unmap のサポートにはいくつかの側面がある。discard が一般的にサポートされていても、暗黙に失敗したり、discard 要求を部分的に無視したりすることがある。デバイスは、また、マップされていないブロックからの読み込みが、定義済みのデータ(通常はゼロ)、未定義のデータ(おそらく古いデータか、ゴミ)のどちらを返すか通知する。

異なるノードで DRBD が discard 特性が異なるデバイスによって構成されている場合、discard はデータの不一致(古いデータまたはゴミが 1 つのバックエンドに残り、別のバックエンドではゼロが残る)の原因となる。オンライン照合は、数多くの偽の差異を報告する可能性がある。たぶんほとんどのユースケース (ファイルシステム上の fstrim) では無害であるが、DRBD はそれを持つことはできません。

安全に動作させるには、ローカルのバックエンド(プライマリ上)が "discard_zeroes_data=true" をサポートしていない場合、 discard のサポートを無効にする必要がある。受信側(セカンダリ)がマップされていなかった領域を割り当て、 "discard_zeroes_data = true" をサポートしていない場合、受信側で discard を明示的にゼロに変換する必要がある。

discard をサポートしているのに、discard_zeroes_data = false をアナウンスするデバイス(特に LVM/DM シンプロビジョニング)がある。DM-thin の場合、チャンクサイズに合わせた discard はマップされず、マッピングされていないセクタからの読み込みはゼロを返す。ただし、discard 要求のアライメントされていない部分ヘッドまたはテール領域は暗黙に無視される。

整列したフル・チャンクの discard をパスし、これらの整列していない部分領域を明示的にゼロ・アウトするヘルパーを追加すると、そのようなデバイスでは discard_zeroes_data = true を効果的に達成する。

discard-zeroes-if-aligned yes に設定すると、 discard_zeroes_data = false を通知するバックエンドであっても DRBD は discard を使用し、 discard_zeroes_data = true を通知する。

discard-zeroes-if-aligned no に設定すると、それぞれのバックエンドが discard_zeroes_data = false をアナウンスする場合、DRBD は常に受信側でゼロアウトにフォールバックし、プライマリ側では discard に関して通知しない。

私たちは、 discard_zeroes_data 設定を完全に無視していました。確立し、期待された動作を壊さず、シンプロビジョニング LV の fstrim がスペースを解放する代わりにスペースを使い果たさないためのデフォルト値は yes である。

このオプションは 8.4.7 から有効である。

--disable-write-same {yes | no}

一部のディスクは、WRITE_SAME サポートをカーネルに通知するが、実際にそのようなリクエストを受信すると、I/O エラーで失敗する。これは主に、仮想化されたディスクを使用しているときに発生する。特に、この動作は VMware の仮想ディスクで観察されている。

disable-write-sameyes に設定すると、WRITE_SAME サポートが手動で無効にできる。

disable-write-same のデフォルト値は no である。このオプションは 8.4.7 から有効である。

read-balancing method

読み込みリクエストの負荷分散で使用できる methodsprefer-local, prefer-remote, round-robin, least-pending, when-congested-remote, 32K-striping, 64K-striping, 128K-striping, 256K-striping, 512K-striping, 1M-striping である。

read-balancing のデフォルト値は prefer-local である。このオプションは 8.4.1 から有効である。

rs-discard-granularity byte

rs-discard-granularity がゼロ以外の正の値に設定されている場合、DRBD はこのサイズで再同期操作を要求する。そのようなブロックが同期ソースノード上にゼロバイトしか含まない場合、同期ターゲットノードは、その領域に対して discard/trim/unmap コマンドを発行する。

この値は、下位ブロックデバイスの discard 粒度によって制約される。 rs-discard-granularity が下位ブロックデバイスの discard 粒度の乗数でない場合、DRBD はそれを切り上げる。この機能は、下位ブロックデバイスが discard コマンドの後に、ゼロを読み戻す場合にのみアクティブになる。

rs-discard-granularity のデフォルト値は 0 である。このオプションは 8.4.7 から有効である。

sndbuf-size size

size は TCP ソケットのセンドバッファである。デフォルト値は 0 で自動調整される。これより小さい値も大きい値も指定できる。遅延が大きいネットワークに対してプロトコル A を指定する場合に大きな値を指定すると、書き込みスループットを向上できる。32K より小さい値は現実的ではない。8.0.13 から 8.2.7 までは、手動で 0 を設定しないと自動調整にならない。

rcvbuf-size size

size は TCP ソケットの受信バッファサイズである。デフォルト値は 0 で自動調整される。これより小さい値も大きい値も指定できる。通常は、このオプションはデフォルト値のまま運用する。size に 0 指定すると、カーネルが自動的に設定したバッファを使う。

timeout time

対向ノードからの応答パケットが 1/10 の time 倍の時間以内に返ってこない場合、対向ノードが死んだと判断して TCP/IP コネクションを切断する。この値は connect-int および ping-int よりも小さくなければならない。デフォルト値は 60 で、これは 6 秒に相当する。すなわちこのパラメータの単位は 0.1 秒である。

connect-int time

対向ノードにただちに接続できない場合、DRBD は接続を繰り返し試行する。このパラメータは試行間隔を指定する。デフォルト値は 10 で、このパラメータの単位は秒である。

ping-int time

DRBD デバイス間の TCP/IP 接続があり、対向ノードから time 秒の間に何も通信が行われなかった場合、 DRBD は死活確認のためキープアライブパケットを生成する。デフォルト値は 10 で、このパラメータの単位は秒である。

ping-timeout time

このパラメータで指定した時間内にキープアライブパケットに応答しなければならない。応答パケットが返ってこない場合、その対向ノードは死んだと判断される。デフォルト値は 500ms で、100ms 単位で指定する。

max-buffers number

再同期、オンライン照合を行う際に、受信側で DRBD マイナーデバイスあたりに使用するメモリを制限する。単位は PAGE_SIZE で、ほとんどのシステムで 4KiB である。設定できる最小値は 32 (=128 KiB) でハードコードされている。これらバッファはディスクからの読み書きの際にデータブロックを保持するために使用される。輻輳時のデッドロックを回避するために、この設定はハード制限というよりは閾値として使用される。最大バッファページが使用されると、プールからのそれ以上の割り当てが制限される。受信側の I/O バックエンドに余裕がない場合には、 max-buffers を増やすとよい。

ko-count number

セカンダリノードが 1 回の書き込みリクエストに count 回以上失敗した場合、そのセカンダリノードはクラスタから排除される。(つまり、プライマリノードが接続をいったん終了し、再接続する)。この機能を無効にするには、明示的に 0 に設定する必要がある。デフォルトはバージョン間で変更されている。 8.4 は 7 がデフォルト値である。

max-epoch-size number

書き込みバリア間に処理するデータブロックの最大数を指定する。10 未満の値を指定するとパフォーマンスが低下することがある。

allow-two-primaries

このオプションを指定すると、両ノードにプライマリを割り当てられる。このオプションは分散共有ファイルシステムを使うときのみ指定する。現在 DRBD がサポートするファイルシステムは OCFS2 と GFS である。これら以外のファイルシステムを使うときにこのオプションを指定すると、データの破損とノードのダウンを引き起こす。

unplug-watermark number

この設定は、最近の明示的にスタックプラギングを使用するカーネルには効果がない (Linux kernel 2.6.39 には移植されている)。

スタンバイ(セカンダリ) ノードで書き込まれていない書き込みリクエスト数が unplug-watermark を上回ると、下位デバイスに対して書き込みリクエストを送る。ストレージによっては小さい値でも良好な結果が得られるが、多くのデバイスでは max-buffers と同じ値を指定するときに最良の結果が得られる。デフォルト値は 128 で、指定できる最小値は 16、最大値は 131072 である。

cram-hmac-alg

対向ノードの認証を行いたい場合、 +HMAC アルゴリズムを指定する。対向ノードの認証は行うべきである。チャレンジ-レスポンス方式で対向ノードを認証するのに、 HMA CFC アルゴリズムが使われる。/proc/crypto に記録されている任意のダイジェストアルゴリズムを指定できる。

shared-secret

対向ノードの認証には共有秘密鍵が使用され、64文字までで指定する。cram-hmac-alg を指定しないと対向ノードの認証は行われない。

after-sb-0pri policy

指定できるポリシーは以下の通り:

disconnect

自動再同期を行わず接続を切断する。

discard-younger-primary

スプリットブレイン発生前にプライマリであったノードからの再同期を自動的に実行する。

discard-older-primary

スプリットブレイン発生時にプライマリになったノードからの再同期を自動的に実行する。

discard-zero-changes

プリットブレイン発生後どちらか一方のノードに書き込みがまったく行われなかったことが明白な場合、書き込みが行われたノードから行われなかったノードに対する再同期が実行される。どちらも書き込まれなかった場合は、 DRBD はランダムな判断によって 0 ブロックの再同期を実行する。両ノードに書き込みが行われた場合、このポリシーはノードの接続を切断する。

discard-least-changes

スプリットブレイン発生後、より多くのブロックを書き込んだノードから他方に対する再同期を実行する。

discard-node-NODENAME

指定した名前のノードに対する再同期を実行する。

after-sb-1pri policy

指定できるポリシーは以下の通り:

disconnect

自動再同期を行わず接続を切断する。

consensus

after-sb-0pri アルゴリズムの結果が現在のセカンダリノードのデータを壊すことになる場合、セカンダリノードのデータを捨てる。そうではない場合は接続を切断する。そうではない場合は接続を切断する。

violently-as0p

プライマリのデータに大きな変更がある場合でも、常に after-sb-0pri アルゴリズムの判断を採用する。このポリシーは allow-two-primaries オプションを指定したうえで 1 ノードファイルシステム (OCF2 や GFS ではない) を使用し、かつ十分に理解している場合のみ有用である。プライマリノードでファイルシステムをマウントしている場合、このポリシーは危険であり、マシンを破壊する可能性がある

discard-secondary

セカンダリ側のデータを捨てる。

call-pri-lost-after-sb

after-sb-0pri アルゴリズムの判断を常に採用する。セカンダリ側のデータが正しいと判断された場合には、現在のプライマリ側で "pri-lost-after-sb" ハンドラが呼び出される。

after-sb-2pri policy

指定できるポリシーは以下の通り:

disconnect

自動再同期を行わず接続を切断する。

violently-as0p

プライマリのデータに大きな変更がある場合でも、常に after-sb-0pri アルゴリズムの判断を採用する。このポリシーは allow-two-primaries オプションを指定したうえで 1 ノードファイルシステム (OCF2 や GFS ではない) を使用し、かつ十分に理解している場合のみ有用である。プライマリノードでファイルシステムをマウントしている場合、このポリシーは危険であり、マシンを破壊する可能性がある

call-pri-lost-after-sb

どちらか一方のマシンで "pri-lost-after-sb" ハンドラを呼び出す。このプログラムには、マシンをリブートしてそのマシンをセカンダリにするような機能が要求される。

always-asbp

通常、3 番目のノードが存在しないことが現在の UUID 値から明らかな場合のみ、スプリットブレイン発生後の修復ポリシーだけが適用される。

このオプションを指定すると、両ノードのデータに関連性があるとして、スプリットブレイン発生後のポリシーが適用される。UUID の分析により 3 番目のノードの存在が疑われる場合には、フル同期が行われることがある。(または、なんらかの別の原因によって間違った UUID セットで判断してしまった場合)

rr-conflict policy

このオプションは、再同期決定の結果がクラスタ内の現在のロール割り当てと互換性がない場合を解決するのに役立つ。

disconnect

自動再同期を行わず接続を切断する。

violently

プライマリノードへの同期が許可され、ブロックデバイス上のデータがノードの 1 つに対して安定しているという前提に反す。危険なので使ってはならない。

call-pri-lost

そのマシンがセカンダリに降格できる場合を除いて、いずれかのマシンの pri-lost-after-sb ヘルパープログラムを呼び出す。ヘルパープログラムはマシンを再起動することが期待され、ノードをセカンダリにする。どのマシンがヘルパープログラムを実行するかは、 after-sb-0pri ポリシーによって決定される。

data-integrity-alg alg

ネットワーク経由で受け渡されるデータの整合性を担保するために、DRBD はハッシュ値を比較する機能を備えている。通常は、TCP/IP パケット自体のヘッダに含まれる 16 ビットチェックサムで保証される。

このオプション値には、カーネルがサポートする任意のダイジェストアルゴリズムを指定できる。一般的なカーネルの場合、少なくとも md5, sha1, crc32c のどれかが利用できる。デフォルトでは、この機能は無効である。

データ整合性に関する説明も参照のこと。

tcp-cork

DRBD は、 TCP ソケットの TCP_CORK オプションを使って、いつ追加データを受け取るか、あるいは送信キューのデータをいつフラッシュするかのヒントを得ている。この方法が悪影響を及ぼすネットワークスタックが少なくとも存在する。したがって、このオプションを導入された。 tcp-corkno にセットすると、DRBD による TCP_CORK ソケットオプションの設定を無効にする。

on-congestion congestion_policy,
congestion-fill fill_threshold,
congestion-extents active_extents_threshold

デフォルトでは、 TCP 送信キューが一杯になると、 DRBD は書き込みをブロックする。このことは DRBD が TCP で送信できるデータ量を越えてディスクに書きこもうとするアプリケーションの処理速度が低下することを意味する。

DRBD-Proxy を使っている場合、送信キューが満杯になる直前に AHEAD/BEAIND モードに移行するのが望ましい。AHEAD/BEHIND モードでは、DRBD 間の通信は切断しないが、データレプリケーションは行われなくなる。

AHEAD/BEHIND モードの利点は、たとえ DRBD-Proxy のバッファがすべての書き込み要求を受け入れるのに十分でなくても、アプリケーションが遅くならないことである。欠点は、対向ノードが後れをとっているため、同期状態に戻すために再同期が必要になることである。再同期中対向ノードのデータは不整合状態のままとなる。

congestion_policy では blockpull-ahead が使用できる。デフォルトは block である。Fill_threshold は 0 から 10GiB までの値を指定できる。デフォルト値は 0 で、これはチェックが無効になることを意味する。Active_extents_threshold は、 al-extents と同じ制限がある。

AHEAD/BEHIND は DRBD8.3.10 以降で利用できる。

wfc-timeout time

接続確立までの待機時間にタイムアウト値を設定する。 init スクリプト drbd(8) は、 DRBD リソースの接続が確立するまで待ち続ける。後に起動されるクラスタ管理システムは、通常はリソース内のスプリットブレイン状態まではチェックしない。待ち時間を制限したい場合には、このパラメータ値を設定する。デフォルト値は 0 で、タイムアウトせずに待ち続ける。単位は秒である。

degr-wfc-timeout time

クラスタが縮退した場合には、コネクションタイムアウトを待つ。縮退とは、片方のノードしか動作していない状態を表す。このようなクラスタをリブートした場合には、対向ノードが一定時間内に起動する可能性が低いため、wfc-timeout ではなく degr-wfc-timeout が使われる。0 を指定すると、タイムアウトしなくなる。

outdated-wfc-timeout time

相手ノードが無効になってから、接続確立までの待機時間にタイムアウト値を設定する。無効になった相手ノードが再起動されているデグレードクラスタ (1 つのノードしか残っていないクラスタ) では、このタイムアウト値は wfc-timeout の代わりに使用される。なぜなら、相手ノードはその間プライマリになることを許可されていないためである。0 を指定すると、タイムアウトしなくなる。

wait-after-sb

このパラメータを指定すると、スプリットブレイン状態にあって接続自体が拒否されるような状態でも、起動スクリプトは接続まで待ち続けるようになる。

become-primary-on node-name

起動時にプライマリになるべきノードの名前を指定する。node-name はホスト名またはキーワードの 両方 かもしれない。このパラメータが指定されていない場合は、両ノードともセカンダリ状態で起動する。通常は、役割の決定をクラスタ管理システム (heartbeat など) に委ねることが多い。

stacked-timeouts

スタックした上位デバイスについて、通常は wfc-timeout および degr-wfc-timeout は無視される。コネクションタイムアウト値には、代わりに connect-int の 2 倍の時間が使われる。stacked-timeouts を指定すると、DRBD は wfc-timeout および degr-wfc-timeout にもとづいて動作するようになる。スタックデバイスの対向ノードが多くの場合に利用できないケースや対向ノードがプライマリにならない場合に限って、このオプションを指定すべきである。誤用すれば、予期しないスプリットブレインが起きるリスクが生じる。

resync-rate rate

DRBD の上位で動作するアプリケーションの円滑な実行のために、バックグラウンドの同期作業が利用する帯域幅を制限できる。デフォルト値は 250KB/秒、デフォルト単位は KB/秒である。K、 M、 G の接尾語を補って単位を変更できる。

use-rle

再同期開始時のハンドシェークの過程で各ノードのビットマップが交換され、ビット単位の OR 計算が行われる。これによって、どのブロックがダーティ (不一致) であるかについて、それぞれのノードは共通の認識を持つ。大容量デバイスではビットマップも大きくなり、帯域幅が小さいネットワークではその交換に時間を要する。

典型的なビットマップは、すべてがセットされていない (クリーン) あるいはセットされている (ダーティ) いくつかのエリアに分かれている。このため、単純ではあるがランレングス符号化を採用することにより、ビットマップ交換のためのネットワークトラフィックを顕著に減らすことができる。

過去のバージョンとの互換性のため、また高速ネットワークでは転送時間改善効果が少なく CPU 使用量が増えるため、デフォルトではこの機能は無効である。

socket-check-timeout value

DRBD-Proxy を使っていて大量のバッファを確保する必要がある環境では ping-timeout に非現実的な大きな値を指定しなければならないことがある。TCP コネクションが開始したときの安定するのを待つ局面でも、 DRBD はデフォルトで ping-timeout を使ってしまう。DRBD-Proxy は通常、同じデータセンターに配置されているため、長い待機時間は DRBD の接続プロセスを妨げる可能性がある。

このような場合、socket-check-timeout に DRBD と DRBD-Proxy 間の round trip time(RTT) を設定するとよい。たいていの場合 1 である。

デフォルトの単位は 10 分の 1 秒である。デフォルト値は 0 で socket-check-timeout 値の代わりに ping-timeout 値を使用する。8.4.5 から導入された。

resync-after res-name

デフォルトでは全てのデバイスの再同期処理が並行して行われる。resync-after で依存性を定義すると、リソース res-name が connected 状態 (つまり再同期の完了後) になってからリソースの再同期を開始する。

al-extents extents

DRBD はホットエリアを自動的に検出する。このパラメータを指定すると、ホットエリアの大きさを制御できる。各エクステントは、下位デバイスの 4MB の領域になる。予定外の事情によってプライマリノードがクラスタから切り離されると、そのときのホットエリアのデータは、次回接続したときの再同期の対象になる。このデータ構造は、メタデータ領域に書き込まれる。したがって、ホットエリアの状態更新は、メタデータデ バイスへの書き込みを引き起こす。エクステント値を大きくすると、再同期所要時間が長くなるが、メタデータの更新頻度を減らすことができる。 extents のデフォルト値は 1237 である。(最小値:7、最大値:65534)

有効な最大値はもっと小さくなる点に注意が必要であり、メタデータのデバイスの作成方法によっても異なる。次のマニュアルページを参照、drbdmeta(8) を参照。有効な最大値は 919 * (使用できる オンディスクのアクティビティログのリングバッファ領域 /4KB -1) である。リングバッファはデフォルトで 32KB で、有効な最大値は 6433 である (データは 25GiB 以上カバーしている)。下位デバイスの量とレプリケーションリンク全体が 5 分以内で再同期できるようにすることを推奨する。

al-updates {yes | no}

DRBD のアクティビティログ処理の書き込みによって、プライマリノードのクラッシュ後の部分的な (ビットマップに基づく) 再同期でノードを up-to-date に復帰させる事ができるようになる。al-updatesno に設定すると通常の運用パフォーマンスが向上するかもしれないが、クラッシュ時にプライマリが再接続した際にはフル同期となる。デフォルト値は yes である。

verify-alg hash-alg

verify サブコマンドでディスク内容をオンライン照合する際、 DRBD はビット単位の比較ではなく、ブロックごとのハッシュ値を計算し、対向ノードのハッシュ値と比較する。照合に利用するハッシュアルゴリズムは、このパラメータで指定する。オプション値には、カーネルがサポートする任意のダイジェストアルゴリズムを指定できる。一般的なカーネルの場合、少なくとも md5, sha1, crc32c のどれかが利用できる。デフォルトでは、この機能は無効である。オンライン照合を有効にするには、このパラメータを明示的に設定する必要がある。

データ整合性に関する説明も参照のこと。

csums-alg hash-alg

csums-alg が指定されていない場合、再同期プロセスはすべてのマークされたデータブロックをコピー元からコピー先に転送するこのオプションを指定すると、マークされたデータブロックのハッシュ値を最初に送り、ハッシュ値が一致しないブロックについてのみデータを転送する。

帯域幅が小さい回線を使うとき、このオプションは有用である。クラッシュしたプライマリノードが復帰したとき、アクティビティログに記録されたすべてのブロックが再同期の対象となる。しかし大部分のブロックは同期が取れている。このため、 csums-alg を指定することによって、 CPU の使用量と引き換えに必要な転送量を減らせる。

c-plan-ahead plan_time,
c-fill-target fill_target,
c-delay-target delay_target,
c-max-rate max_rate

plan_time に正の値を指定すると、再同期速度を動的に調整できるようになる。これは、 fill_target に指定した一定速度で、あるいは delay_target に指定した一定の遅延でデータを送信バッファに送り込むことによって実現される。調整における最大値は max_rate で指定する。

plan_time パラメータで調節機能の機敏さを設定する。大きな値を設定すると、調節機能のレスポンスが低下する。この値は最低でもネットワークの RTT の 5 倍以上を指定する。通常のデータ経路では fill_target に 4k から 100k を指定するのが適切である。DRBD-Proxy を使用する場合には、代わりに delay_target を使用するのが望ましい。delay_targetfill_target が 0 の場合にのみ使用できる。初期値は RTT の 5 倍が適切である。Max_rate には DRBD 間または DRBD-Proxy 間の帯域幅あるいはディスク帯域幅を指定する。

plan_time のデフォルト値は 0 で、0.1 秒単位で指定する。Fill_target のデフォルト値は 0 でセクタ数を指定する。Delay_target のデフォルト値は 1 (100 ミリ秒) で 0.1 秒単位で指定する。Max_rate のデフォルト値は 10240 (100MiB/s) で、 KiB/s 単位で指定する。

動的な再同期速度の調整と設定は、DRBD 8.3.9 から使用できる。

c-min-rate min_rate

同期元のプライマリノードは、アプリケーションの書き込みと再同期の書き込みの配分を管理する必要がある。min_rate を指定すると、再同期のための帯域幅の最大値が min_rate になり、利用可能な帯域幅の残りの部分をアプリケーション I/O のために確保する。

0 という値には特別な意味がある事に注意が必要である。0 は再同期速度の制限を完全になくすため、アプリケーションの速度を劇的に低下させる可能性がある。アプリケーションの速度低下を避けたい場合には、この値に 1 を指定する。

注意:このパラメータ名は動的な調整速度の下限値のように見えるが、実際は異なる。DRBD-Proxy のバッファが満杯のとき、動的調整機能は c-min-rate の設定から独立して、再同期速度を 0 まで下げることができる。

min_rate のデフォルト値は 250 であり、KiB/s 単位で指定する。

on-no-data-accessible ond-policy

この設定は、ディスクレスモードが発生した際の操作を指定する。設定できるポリシーは io-errorsuspend-io である。

ond-policysuspend-io を設定すると、最後に接続していたデータストレージから、もしくは、 drbdadm resume-io res コマンドにより、 I/O を再開することができる。後者はもちろん I/O エラーを発生させる。

デフォルトは io-error である。この設定は、 DRBD 8.3.9 から有効である。

cpu-mask cpu-mask

DRBD のカーネルスレッドに CPU アフィニティマスクを設定する。cpu-mask のデフォルト値は 0 で、 DRBD のカーネルスレッドがマシン全体の CPU にまたがって動作することを意味している。この値は 16 進表現で指定する必要がある。値が大きすぎると切り捨てられる。

pri-on-incon-degr cmd

このパラメータで指定するハンドラは、ノードがプライマリで、縮退 (片方のノードしか動作していない状態) し、ローカルのコピーデータに不整合がある場合に呼び出される。

pri-lost-after-sb cmd

このパラメータで指定するハンドラはノードが現在プライマリで、スプリットブレイン後の自動回復プロセスが失敗したときに呼び出される。その結果、このノードのデータが放棄されるようにする。

pri-lost cmd

このパラメータに指定したハンドラは、ノードが現在プライマリであるにもかかわらず、 DRBD のアルゴリズムが同期先だと判断した場合に実行される。このような状態になった場合、このノードはプライマリであることをやめるべきである。

fence-peer cmd

このパラメータはフェンシングメカニズムの一部を構成する。このパラメータに指定したハンドラは、対向ノードを無効状態にする必要が生じたときに実行される。呼び出されたコマンドは、 DRBD が使っている通信経路とは別の経路を使うべきである。

local-io-error cmd

このパラメータに指定したハンドラは DRBD がローカルの I/O サブシステムから I/O エラーを受けた時に実行される。

initial-split-brain cmd

DRBD がスプリットブレインを検出した場合に使用される。このハンドラはスプリットブレインが発生した場合に警告を通知する。問題が解決した場合でも通知する。

split-brain cmd

このパラメータに指定したハンドラは、スプリットブレイン状態が検出され、回復できない場合に呼び出される。修復のための手作業が必要なので、このハンドラは、誰かにこのことを通知するのが望ましい。

before-resync-target cmd

このパラメータで指定したハンドラは、同期先で再同期が開始される直前に呼び出される。下位ブロックデバイスのスナップショットを取得する、などの用途が考えられる。

after-resync-target cmd

このパラメータで指定したハンドラは、不整合状態だったノードで、ディスクの再同期が完了した直後に呼び出される。before-resync-target ハンドラで作成したスナップショットを削除する、などの用途が考えられる。

include file-pattern
file-pattern に指定したワイルドカード形式に合致する全てのファイルを組み込む。include ステートメントはトップレベルでのみ使用でき、セクション内では使用できない。

DRBD がミラーしたデータの整合性を保証する方法は 2 つあり、これらはそれぞれ別々のものである。オンライン照合と network セクションの data-integrity-alg である。

どちらのメカニズムの場合でも、データの転送中に DRBD の上位プログラムがディスクに書き込みを行った場合、不整合ではないのに不整合と判断されることがある。それはスワップの発生、グローバル同期中の付加、ワークロードの打ち切りや書き換えであるかもしれず、必ずしもデータ整合性の問題をもたらさない。通常イニシエータがデータ転送を行う際には、データブロックがディスク上のデータ構造の一部でない事を認識しているか、すぐに正確なデータで再実行される。

data-integrity-alg は、"Digest integrity check FAILED: Ns |x\n" というエラーを受信側のログに書きだす。 N は相殺されたセクタのオフセットで、x はバイト単位のリクエストサイズである。それから接続を切り、再接続して、迅速に再同期をする。同時に送信側が変更を検知した場合、"Digest mismatch, buffer modified by upper layers during write: Ns +x\n" という警告がでるが、これは誤検出である。変更されていないデータが tcp バッファにコピーされると、送信側はこれらのバッファの変化をすぐに検出するかもしれない。この場合、受信側はそれに気づかない。

直近の例 (2007 年) では系統的なデータ損傷のケースがあり、ギガビット NIC の TCP/IP オフロードエンジンとドライバが原因だった。メインメモリから NIC への DMA データ転送時にデータ破壊が起きていた。TCP チェックサムは NIC 側で計算されるため、この種のデータエラーは オンライン照合 verify または data-integrity-alg を使わない限り検出できない。

data-integrity-alg は CPU 負荷が大きいため、テスト期間中のみ使うことを推奨する。その後は、たとえば月に 1 回程度、負荷が低い時間帯にオンライン照合を実施するのが望ましい。

このドキュメントは DRBD バージョン 8.4.0 向けに改訂されている。

Written by Philipp Reisner <philipp.reisner@linbit.com> and Lars Ellenberg <lars.ellenberg@linbit.com>.

Report bugs to <drbd-user@lists.linbit.com>.

Copyright 2001-2008 LINBIT Information Technologies, Philipp Reisner, Lars Ellenberg. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

drbd(8), drbddisk(8), drbdsetup(8), drbdmeta(8), drbdadm(8), DRBD User's Guide[1], DRBD web site[3]

1.
DRBD User's Guide
http://www.drbd.org/users-guide/
2.
DRBD の利用者統計
http://usage.drbd.org
3.
DRBD web site
http://www.drbd.org/
6 May 2011 DRBD 8.4.0