Links:
Linux 3.2.0 に含まれているのは DRBD 8.3.11。 http://www.drbd.org/download/mainline/
Ubuntu のパッケージバージョンは "Version: 2:8.3.11-0ubuntu1"。
ブロックデバイスを他のコンピューターに TCP/IP 等でミラーリングするもの。
同期・非同期が選べるが、データセンター移転用途では非同期に行う。
クラスタリング用途では heartbeat 等と組み合わせることが多い。
heartbeat は split brain の可能性があるときにサービスを停止するが、
keepalived は二つ master ができるという点に大きな違いがある。
商用になるが、DRBD Proxy という遠隔転送用にバッファリング&圧縮するモジュールもあるようだ。
ただ、日本円で 1 システム 36 万円とかなり高額。
drbd.ko
というカーネルモジュールと、drbdadm
をはじめとするユーザーランドツールからなる。
drbdadm
は設定ファイルを読んで drbdmeta
と drbdsetup
を呼び出すラッパーで、
実際に何を呼び出すかは -d
オプションをつけると確認できる。
初期同期中は secondary ディスクは inconsistent 状態にある。
レプリケーションリンクが切れたときは outdated 状態になる。
http://www.drbd.org/users-guide-8.3/s-outdate.html
DRBD 自体の情報を管理するメタデータがある。internal だと underlying block device
内で管理されるが、すでにデータのあるブロックデバイスに外付けのメタデータをつけて DRBD
リソースとして利用することも可能。
external meta data はブロックデバイスで、自分で用意する際はサイズを計算する必要がある。
が、meta-disk
で指定する分には 128 MiB (up to 4 TiB backing disk)固定。
flexible-meta-disk
やるなら計算する感じかな。
$ dd if=/dev/zero of=/path/to/file bs=1M count=128 $ sudo losetup /dev/loop0 /path/to/file |
linux-image-virtual
パッケージに drbd.ko
が含まれていないので、含めるように修正する。
$ sudo apt-get install drbd8-utils |
/etc/drbd.d
に設定ファイルあり。
プロトコル A が asynchronous.
http://www.drbd.org/users-guide-8.3/s-replication-protocols.html
初期同期と切断後の再同期処理。再同期処理は差分のみで効率的。
同期速度は設定可能。50MiB/s 以下にするのがいいかな。
チェックサムベースの同期もあるようだが、今回のような単純レプリケーションでは不要。
http://www.drbd.org/users-guide-8.3/s-configure-checksum-sync.html
DRBD を使用していても、underlying block device のコンシステンシをチェックできる機能。
今回のデータセンター移転用途では、当日に DRBD 解除した後で sha1sum を双方のボリューム
でチェックしてしまえばいいので使わないだろう。
http://www.drbd.org/users-guide-8.3/s-online-verify.html
ネットワークパケットにチェックサムをつける機能。つけるべし。
http://www.drbd.org/users-guide-8.3/s-configure-integrity-check.html
BBU RAID コントローラーでは disable した方が性能がでるのでそうする。
メタデータの flush は害がなければ disable しないほうがいい、のかな。
どのみち external meta data にするので、enable であっても性能に大差はなかろう。
http://www.drbd.org/users-guide-8.3/s-disable-flushes.html
underlying block device のエラーをどうするか。detach
が推奨されているが、
これをすると secondary に直接読み書きするようになってしまい、データセンター移転
の用途にはまったくそぐわない。デフォルトの pass_on
ストラテジーでいい。
http://www.drbd.org/users-guide-8.3/s-configure-io-error-behavior.html
TCP send buffer がいっぱいになったときに inconsistent にデグレさせる機能。
アプリケーション性能を落とさないが、resync が走る。
ただ ML のやりとりを見ると、DRBD proxy がないと意義薄いとか、resync が自動的には
働かなくて接続しなおさないといけないバグあるといったやり取りがあるようだ。一番下のは、
フルに同期しなおさなくてはならないと言っていて、安定性に欠ける印象。
-g, --on-congestion congestion_policy, -f, --congestion-fill fill_threshold, -h, --congestion-extents active_extents_threshold By default DRBD blocks when the available TCP send queue becomes full. That means it will slow down the application that generates the write requests that cause DRBD to send more data down that TCP connection. When DRBD is deployed with DRBD-proxy it might be more desirable that DRBD goes into AHEAD/BEHIND mode shortly before the send queue becomes full. In AHEAD/BEHIND mode DRBD does no longer replicate data, but still keeps the connection open. The advantage of the AHEAD/BEHIND mode is that the application is not slowed down, even if DRBD-proxy's buffer is not sufficient to buffer all write requests. The downside is that the peer node falls behind, and that a resync will be necessary to bring it back into sync. During that resync the peer node will have an inconsistent disk. Available congestion_policys are block and pull-ahead. The default is block. Fill_threshold might be in the range of 0 to 10GiBytes. The default is 0 which disables the check. Active_extents_threshold has the same limits as al-extents. The AHEAD/BEHIND mode and its settings are available since DRBD 8.3.10. |
ホスト名じゃなく、VIP で peer を指定する方法。できて当然な気がするが設定ファイルの
文法的に異なっている。設定ファイルは全 peer で同一のものを共有する前提なので、自ホスト
の設定をみつけるのに普通はホスト名を使うってことか。で、ホスト名が使えない状況では
IP アドレスのどれかで判定するってところかな。
http://www.drbd.org/users-guide-8.3/s-pacemaker-floating-peers.html
/etc/drbd.d/*.res
ここに設定ファイルを置くと、OS 起動時に /etc/init.d/drbd
で起動されてしまう。
square のボリュームマウントを待つなら、ここに設定ファイルを置くのは適当ではない?
当然指定できる。高遅延ネットワークでは大きくするべし。
common { net { sndbuf-size 1048576; } } |
大量の読み書きがある場合は、送信バッファの上限をカーネルで増やす必要があるかもしれない。
やるとしたら net.core.wmem_max
を増やして SO_SNDBUF
で自動チューンは無効化
するので、net.ipv4.tcp_wmem
は設定しなくていいだろう。
pri-on-incon-degr
, pri-lost-after-sb
, local-io-error
のイベントハンドラーが定義されている。
とりあえず我々の用途では無視。
global { usage-count no; } resource ymmt-blob { protocol A; device minor 1; meta-disk /dev/loop0[0]; # 128 MiB loopback device syncer { rate 16M; # Network bandwidth limit c-min-rate 16M; # Disk I/O rate al-extents 3389; # few meta data update rate } net { max-buffers 8000; max-epoch-size 8000; sndbuf-size 0; # TCP send buffer auto tuning data-integrity-alg crc32c; } disk { on-io-error pass_on; no-disk-barrier; no-disk-flushes; } on ymmt2 { address 10.1.1.1:7801; disk /dev/md/ymmt-blob; } on ymmt3 { address 10.1.1.2:7801; disk /dev/md/ymmt-blob; } } |
http://www.drbd.org/users-guide-8.3/ch-admin.html#s-check-status
$ watch -n 1 cat /proc/drbd |
$ dd if=/dev/zero of=/home/ymmt/meta bs=1M count=128 $ sudo losetup /dev/loop0 /home/ymmt/meta $ cat hoge.conf global { usage-count no; } resource hoge { protocol A; device minor 1; meta-disk /dev/loop0[0]; disk /dev/ubuntu/hoge; syncer { rate 16M; # Network bandwidth limit c-min-rate 16M; # Disk I/O rate } on ymmt2 { address 10.1.5.213:7801; } on ymmt3 { address 10.1.5.214:7801; } } $ sudo drbdadm -d -c hoge.conf create-md hoge drbdmeta 1 v08 /dev/loop0 0 create-md $ sudo drbdadm -c hoge.conf create-md hoge Writing meta data... initializing activity log NOT initialized bitmap New drbd meta data block successfully created. $ sudo lvcreate -L 3g -n hoge ubuntu $ sudo drbdadm -d -c hoge.conf attach hoge drbdsetup 1 disk /dev/ubuntu/hoge /dev/loop0 0 --set-defaults --create-device $ sudo drbdadm -c hoge.conf attach hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:StandAlone ro:Secondary/Unknown ds:Inconsistent/DUnknown r----- ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:3145472 $ sudo drbdadm -d -c hoge.conf syncer hoge drbdsetup 1 syncer --set-defaults --create-device --rate=16M --c-min-rate=16M $ sudo drbdadm -c hoge.conf syncer hoge |
ここまででメタデータを作って、DRBD デバイスを作って、同期スピードのパラメーターを調整している。
状態としては standalone で peer なし、secondary で primary じゃないので書き込めず、
inconsistent な状態。
同期開始は後日になるので、とりあえずは primary として使いたい。
$ sudo drbdadm -d -c hoge.conf -- --overwrite-data-of-peer primary hoge drbdsetup 1 primary --overwrite-data-of-peer $ sudo drbdadm -c hoge.conf -- --overwrite-data-of-peer primary hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown r----- ns:0 nr:0 dw:0 dr:664 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:3145472 |
peer がいなくても無事 primary になった。書き込んでみる。
$ sudo mkfs -t ext4 /dev/drbd1 $ sudo mount /dev/drbd1 /mnt $ cd /mnt $ sudo cp -r /etc/network $ cd $ sudo umount /mnt $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown r----- ns:0 nr:0 dw:115836 dr:1401 al:36 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:3145536 |
さて、同期を開始したくなったらどうするか。
内部的には IP アドレスとプロトコルを指定すればつながるようだ。お手軽。
drbdsetup MINOR net ipv4:LOCAL ipv4:REMOTE PROTOCOL --set-defaults
でいける。
$ sudo drbdadm -d -c hoge.conf connect hoge drbdsetup 1 net ipv4:10.1.5.214:7801 ipv4:10.1.5.213:7801 A --set-defaults --create-device $ sudo drbdadm -c hoge.conf connect hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:WFConnection ro:Primary/Unknown ds:UpToDate/DUnknown A r----- ns:0 nr:0 dw:115836 dr:1733 al:36 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:3145536 |
まだ反対側の peer を立ち上げていないと waiting for connection 状態になる。
反対側の peer も作ってみる。
$ dd if=/dev/zero of=/home/ymmt/meta bs=1M count=128 $ sudo losetup /dev/loop0 /home/ymmt/meta $ sudo drbdadm -c hoge.conf create-md hoge $ sudo lvcreate -L 3g -n hoge ubuntu $ sudo drbdadm -d -c hoge.conf attach hoge drbdsetup 1 disk /dev/ubuntu/hoge /dev/loop0 0 --set-defaults --create-device --on-io-error=pass_on --no-disk-barrier --no-disk-flushes $ sudo drbdadm -c hoge.conf attach hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:StandAlone ro:Secondary/Unknown ds:Inconsistent/DUnknown r----- ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:3145472 $ sudo drbdadm -d -c hoge.conf syncer hoge drbdsetup 1 syncer --set-defaults --create-device --rate=16M --c-min-rate=16M --al-extents=3000 $ sudo drbdadm -c hoge.conf syncer hoge $ sudo drbdadm -d -c hoge.conf connect hoge drbdsetup 1 net ipv4:10.1.5.213:7801 ipv4:10.1.5.214:7801 A --set-defaults --create-device --max-buffers=8000 --max-epoch-size=8000 --sndbuf-size=0 --data-integrity-alg=crc32c $ sudo drbdadm -c hoge.conf connect hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:SyncTarget ro:Secondary/Primary ds:Inconsistent/UpToDate A r----- ns:0 nr:128128 dw:128000 dr:0 al:0 bm:7 lo:1 pe:0 ua:1 ap:0 ep:1 wo:d oos:3017728 [>....................] sync'ed: 4.3% (3017728/3145728)K finish: 0:02:44 speed: 18,284 (18,284) want: 16,384 K/sec |
無事 initial full sync が走り出す。
初期同期中にあえて接続を切ると、最初からやり直しになる。
この場合は checksum-based synchronization を有効にすれば少しは速くなるだろう。
なお、disconnect した後は同期速度の設定が消えるので、connect の前に drbdadm syncer
の設定をやり直さないといけない。
デフォルト 10MiB/s を 30MiB/s にする。
$ sudo drbdsetup 1 syncer -r 30M |
なお、-m/--c-min-rate
の制限は secondary 側でしか有効にならないので、注意。
--c-min-rate=1
だとまったく速度でないので、-r
と同じ設定値に secondary 側でするのが吉。
接続を切って underlying block device を detach する。
Primary デバイスは disconnect の後、secondary にしてやらないと detach ができない仕様。
$ sudo drbdadm -d -c hoge.conf disconnect hoge drbdsetup 1 disconnect $ sudo drbdadm -d -c hoge.conf detach hoge drbdsetup 1 detach $ sudo drbdadm -c hoge.conf detach hoge 1: State change failed: (-2) Need access to UpToDate data (失敗するので secondary にしてやり直し) $ sudo drbdadm -c hoge.conf secondary hoge $ sudo drbdadm -c hoge.conf detach hoge $ cat /proc/drbd version: 8.3.11 (api:88/proto:86-96) srcversion: 71955441799F513ACA6DA60 1: cs:Unconfigured |
初期同期中は、アプリケーションへの書き込みは primary で保持するのではなく、
同期的に secondary に転送する。このため、secondary で MD sync やバックアップを
すると primary への書き込みがブロックして障害につながる。
また初期同期が途中で切れると、再度頭からやり直しとなる。
--c-min-rate
でのアプリの I/O 検出は、secondary でアプリケーションへの
書き込みリクエスト数をカウントすることで行っている。primary で設定しても効果は
ないので注意。
drbdsetup MINOR sh-status
すると以下のような情報が得られる。
$ sudo drbdsetup 1 sh-status _minor=1 _res_name=UNKNOWN _known=Configured _cstate=StandAlone _role=Secondary _peer=Unknown _disk=UpToDate _pdsk=DUnknown _flags_susp= _flags_aftr_isp= _flags_peer_isp= _flags_user_isp= _resynced_percent= _sh_status_process |
接続情報や known の値にどんなのが入るかは、この辺みるとわかる。
このデータは Python の shlex.split(data, True)
で楽に解析できる。
残念ながら、backing device 情報をカーネルから取得する手段は提供されていない。
udev が作るシンボリックリンクはあるが、detach しても削除されないのでいまいち。
DRBD はカーネルモジュールなので、種々のイベントを通知するのはユーザーランドのプログラムを呼び出すことになる。
で、この呼び出す仕組みが少々曲者で、drbdsetup
で登録するのではなく、カーネルが直接 drbdadm
を
呼び出して、設定ファイルに記述されたハンドラープログラムをさらに起動するという形式になっている。
設定ファイルではなく直接 drbdsetup
だけで操作しようという Square のようなプログラムには厄介なことに、
例えば before-resync-target
ハンドラーを呼び出そうとして設定ファイルがないのでピアとの通信を諦めて
しまうという問題が発生してしまう。
回避策としては、drbd.ko
のモジュールパラメーター usermode_helper
で drbdadm
以外のプログラム
を指定すると、起動するプログラムを変えることができるのでそうする。
drbd usermode_helper=/bin/true |
もしくは、
$ sudo modprobe drbd usermode_helper=/bin/true |
確認方法:
$ cat /sys/module/drbd/parameters/usermode_helper /bin/true |