DRBD 調査メモ
General information
Links:
Linux 3.2.0 に含まれているのは DRBD 8.3.11。 http://www.drbd.org/download/mainline/
Ubuntu のパッケージバージョンは "Version: 2:8.3.11-0ubuntu1"。
What is DRBD?
ブロックデバイスを他のコンピューターに TCP/IP 等でミラーリングするもの。
同期・非同期が選べるが、データセンター移転用途では非同期に行う。
Clustering
クラスタリング用途では heartbeat 等と組み合わせることが多い。
heartbeat は split brain の可能性があるときにサービスを停止するが、
keepalived は二つ master ができるという点に大きな違いがある。
DRBD Proxy
商用になるが、DRBD Proxy という遠隔転送用にバッファリング&圧縮するモジュールもあるようだ。
ただ、日本円で 1 システム 36 万円とかなり高額。
How it works
Components
drbd.ko
というカーネルモジュールと、drbdadm
をはじめとするユーザーランドツールからなる。
drbdadm
は設定ファイルを読んで drbdmeta
と drbdsetup
を呼び出すラッパーで、
実際に何を呼び出すかは -d
オプションをつけると確認できる。
States
初期同期中は secondary ディスクは inconsistent 状態にある。
レプリケーションリンクが切れたときは outdated 状態になる。
http://www.drbd.org/users-guide-8.3/s-outdate.html
Meta data
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
- http://lists.linbit.com/pipermail/drbd-user/2008-June/009628.html
- http://www.drbd.org/users-guide-8.3/ch-internals.html#s-metadata
- http://web.archiveorange.com/archive/v/1XS1v3R2g9iBX9UXsT64
- 4TB Soft Limit when using External Meta Disk
Setup
linux-image-virtual
パッケージに drbd.ko
が含まれていないので、含めるように修正する。
$ sudo apt-get install drbd8-utils
/etc/drbd.d
に設定ファイルあり。
Features
Replication mode
プロトコル A が asynchronous.
http://www.drbd.org/users-guide-8.3/s-replication-protocols.html
Synchronization
初期同期と切断後の再同期処理。再同期処理は差分のみで効率的。
同期速度は設定可能。50MiB/s 以下にするのがいいかな。
チェックサムベースの同期もあるようだが、今回のような単純レプリケーションでは不要。
http://www.drbd.org/users-guide-8.3/s-configure-checksum-sync.html
On-line verification
DRBD を使用していても、underlying block device のコンシステンシをチェックできる機能。
今回のデータセンター移転用途では、当日に DRBD 解除した後で sha1sum を双方のボリューム
でチェックしてしまえばいいので使わないだろう。
http://www.drbd.org/users-guide-8.3/s-online-verify.html
Replication traffic integrity checking
ネットワークパケットにチェックサムをつける機能。つけるべし。
http://www.drbd.org/users-guide-8.3/s-configure-integrity-check.html
Disabling backing device flushes
BBU RAID コントローラーでは disable した方が性能がでるのでそうする。
メタデータの flush は害がなければ disable しないほうがいい、のかな。
どのみち external meta data にするので、enable であっても性能に大差はなかろう。
http://www.drbd.org/users-guide-8.3/s-disable-flushes.html
Configuring I/O error handling strategies
underlying block device のエラーをどうするか。detach
が推奨されているが、
これをすると secondary に直接読み書きするようになってしまい、データセンター移転
の用途にはまったくそぐわない。デフォルトの pass_on
ストラテジーでいい。
http://www.drbd.org/users-guide-8.3/s-configure-io-error-behavior.html
AHEAD/BEHIND mode
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.
Floating peers
ホスト名じゃなく、VIP で peer を指定する方法。できて当然な気がするが設定ファイルの
文法的に異なっている。設定ファイルは全 peer で同一のものを共有する前提なので、自ホスト
の設定をみつけるのに普通はホスト名を使うってことか。で、ホスト名が使えない状況では
IP アドレスのどれかで判定するってところかな。
http://www.drbd.org/users-guide-8.3/s-pacemaker-floating-peers.html
Configurations
/etc/drbd.d/*.res
ここに設定ファイルを置くと、OS 起動時に /etc/init.d/drbd
で起動されてしまう。
square のボリュームマウントを待つなら、ここに設定ファイルを置くのは適当ではない?
TCP send buffer size
当然指定できる。高遅延ネットワークでは大きくするべし。
common { net { sndbuf-size 1048576; } }
大量の読み書きがある場合は、送信バッファの上限をカーネルで増やす必要があるかもしれない。
やるとしたら net.core.wmem_max
を増やして SO_SNDBUF
で自動チューンは無効化
するので、net.ipv4.tcp_wmem
は設定しなくていいだろう。
Ubuntu default
pri-on-incon-degr
, pri-lost-after-sb
, local-io-error
のイベントハンドラーが定義されている。
とりあえず我々の用途では無視。
Sample for us
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; } }
Operations
同期状態の確認
http://www.drbd.org/users-guide-8.3/ch-admin.html#s-check-status
$ watch -n 1 cat /proc/drbd
Initializing meta data
$ 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 な状態。
Promote to primary
同期開始は後日になるので、とりあえずは 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
Connecting peers
さて、同期を開始したくなったらどうするか。
内部的には 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 が走り出す。
Disconnect during initial synchronization
初期同期中にあえて接続を切ると、最初からやり直しになる。
この場合は checksum-based synchronization を有効にすれば少しは速くなるだろう。
なお、disconnect した後は同期速度の設定が消えるので、connect の前に drbdadm syncer
の設定をやり直さないといけない。
Change synchronization rate temporarily
デフォルト 10MiB/s を 30MiB/s にする。
$ sudo drbdsetup 1 syncer -r 30M
なお、-m/--c-min-rate
の制限は secondary 側でしか有効にならないので、注意。
--c-min-rate=1
だとまったく速度でないので、-r
と同じ設定値に secondary 側でするのが吉。
Disconnection and detach
接続を切って 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
Internals
Initial sychronization
初期同期中は、アプリケーションへの書き込みは primary で保持するのではなく、
同期的に secondary に転送する。このため、secondary で MD sync やバックアップを
すると primary への書き込みがブロックして障害につながる。
また初期同期が途中で切れると、再度頭からやり直しとなる。
--c-min-rate
でのアプリの I/O 検出は、secondary でアプリケーションへの
書き込みリクエスト数をカウントすることで行っている。primary で設定しても効果は
ないので注意。
Device status
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