DRBD 8.4 インストールから必要な操作まで

# DRBDについて調べたのでまとめた
DRBDを使う上で必要そうな部分を調べたのでまとめです。
もしかすると、通知関連を調べて後日載せるかもしれません。

# インストール
## 前提
* CentOS 7 + [ELRepo](http://elrepo.org/)のDRBDを想定しています。
* Primary NodeとSecondary NodeはIP Reachableである必要があります。
* /dev/sdbを同期する設定としています。(/dev/sdaはOSが利用。)
* DRBD 8.4のドキュメントは[こちら](https://blog.3ware.co.jp/drbd-users-guide-8.4/drbd-users-guide.html)。

ここでは、CentOS 7(+ yum update)がインストール済みでIP Reachableな環境がすでに存在する所から説明します。

具体的には[IDCF Cloud](http://www.idcf.jp/cloud/)に[標準で用意されているCentOS 7](http://www.idcf.jp/cloud/spec/os.html)へ[データディスク](http://www.idcf.jp/cloud/spec/disk.html)を1台接続し、[追加ネットワーク](http://www.idcf.jp/cloud/spec/vlan.html#SEC02)を利用してDRBDの同期セグメントとしました。また、余談ですが[プライベートコネクト](http://www.idcf.jp/cloud/connect/)を利用し、[ゾーン間やリージョン間](http://www.idcf.jp/cloud/spec/region_zone.html)でも問題なくDRBDの同期セグメントとして利用できることを確認しています。

## ELRepoを有効に
[ELRepo](http://elrepo.org/)のトップページに**Get started**があるため、特に迷うことはないと思いますが、簡単に記載しておきます。基本的にはレポジトリのrpmをいれれば有効にできます。

```:ELRepoのrpmを入れる。
# yum -y install http://elrepo.org/linux/elrepo/el7/x86_64/RPMS/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
```

最新版はのrpmは[この辺](http://elrepo.org/linux/elrepo/el7/x86_64/RPMS/)から確認しましょう。

## DRBDをインストール

```:DRBDを入れる
# yum -y install drbd84-utils kmod-drbd84
```

## DRBDの設定
コンフィグファイルとしては`/etc/drbd.d/global_common.conf`と`/etc/drbd.d/*.res`となります。`*.res`は各リソースの設定(要するにsyncさせたいディスクの設定)となります。今回は`*.res`は`r1.res`としています。

`/etc/drbd.d/global_common.conf`については基本的には変更不要です。
`global_common.conf`の**globalセクション**にある**usage-count**はDRBDプロジェクトがDRBDの利用状況についての統計を取るための設定であり、DRBDがインストールされるたびにHTTP接続が発生します。情報取得とHTTP接続を気にされるようであれば、設定で`no`に変更してください。

```:/etc/drbd.d/global_common.conf
global {
        usage-count no;
        # minor-count dialog-refresh disable-ip-verification
        # cmd-timeout-short 5; cmd-timeout-medium 121; cmd-timeout-long 600;
}
```

リソース設定は、今回`/etc/drbd.d/r1.res`へ記載します。色々と確認したのですが、現状では下記のコンフィグがベストとしています。

```:/etc/drbd.d/r1.res
resource r1 {
    floating ipv4 192.168.15.xxx:7788 {
        volume 0 {
            device       /dev/drbd0 minor 0;
            disk         /dev/sdb;
            meta-disk    internal;
        }
    }
    floating ipv4 192.168.15.xxx:7788 {
        volume 0 {
            device       /dev/drbd0 minor 0;
            disk         /dev/sdb;
            meta-disk    internal;
        }
    }
    net {
        protocol           C;
        max-buffers      8000;
        max-epoch-size   8000;
    }
    disk {
        al-extents       3389;
        disk-barrier      no;
        disk-flushes      no;
    }
}
```

* [チューニングガイド](https://blog.3ware.co.jp/drbd-users-guide-8.4/ch-throughput.html#s-throughput-tuning)を参考に設定値を色々変えてみましたが、MySQLでsysbenchかける程度では差がほとんど無かったです。
* [レプリケーションのモード](https://blog.3ware.co.jp/drbd-users-guide-8.4/ch-features.html#s-replication-protocols)のProtocol Cは完全同期モードで、BやAは準同期、非同期だが、B,Aでもパフォーマンスは上がらなかったです。(同様にMySQLでsysbench程度では。)
* [設定例](https://blog.3ware.co.jp/drbd-users-guide-8.4/ch-configure.html#s-drbdconf-example)などでは、`on hostname { address ... }`と記載されていますが、_hostname_など書きたくなかったので`floating`を利用しています。
* 異論はありそうですが、とりあえずはこんな感じです。

## メタデータを作成と起動
この手順は初めてDRBDを起動するときにだけ必要な操作です。
この操作はPrimary/Seconday両ノードに対して実行します。

```:メタデータを作成
# drbdadm create-md r1
New drbd meta data block successfully created.
```

```:DRBDの起動
# drbdadm up r1
```

`r1`はr1.resで定義した物です。
メタデータはディスクの末尾の領域に確保されます。

drbdの状態は`/proc/drbd`を見ることで確認できます。

```:/proc/drbd
# cat /proc/drbd
version: 8.4.6 (api:1/proto:86-101)
GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R7, 2015-04-10 05:13:52
 0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C 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:41941724
```

両ノードで`drbdadm up r1`まで実行すると、`cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent`になります。

## データシンク
`cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent`ここまで来たら、どちらかのノードをPrimaryとしてデータを同期するのですが、空っぽのディスクを同期しても時間の無駄なので、初期同期をスキップします。

```:初期同期をスキップ
# drbdadm new-current-uuid --clear-bitmap r1/0

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:21879057 dw:21879057 dr:0 al:8 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

`r1/0`は`r1.res`で定義したリソース名とボリューム番号です。
ds:UpToDate/UpToDateになれば同期完了の意味です。
これで、同期が完了している状態となるので、利用する側をPrimaryとして設定します。

```:Primaryにする
# drbdadm primary r1

# cat /proc/drbd
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:0 dw:0 dr:912 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```
`ro:Secondary/Secondary`から`ro:Primary/Secondary`に変わりました。なお、Secondary側で実行すると`ro:Secondary/Primary`となります。自ノードが先に表示されるので、自分がPrimaryなのかSecondaryなのかが分かります。

なお、フル同期する場合は、Primary側で下記のように実行します。

```:フル同期
# drbdadm --force primary resource1
```

こちらは強制的にPrimaryになり、Secondary側はデータ同期が自動的に始まります。
同期進行中は次のようになります。

```:同期進行中
# cat /proc/drbd
version: 8.4.6 (api:1/proto:86-101)
GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R7, 2015-04-10 05:13:52
 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
    ns:794524 nr:0 dw:0 dr:795436 al:0 bm:0 lo:0 pe:1 ua:0 ap:0 ep:1 wo:f oos:41147712
        [>....................] sync'ed:  2.0% (40180/40956)M
        finish: 0:37:18 speed: 18,372 (14,980) K/sec
```

## フォーマットして使う
drbdを起動してどちらかをPrimaryとすると、Primary側で`/dev/drbd0`が作成されます。`/dev/drbd0`は通常のブロックデバイスとして利用できます。Secondary側は`/dev/drbd0`が作成されないため利用することはできません。

普通のブロックデバイスと何も変わらないため、LVMしたり、そのままフォーマットしたりして利用できます。
今回は、前提に書いた通り[IDCF Cloud](http://www.idcf.jp/cloud/)を利用しています。[IDCF Cloud](http://www.idcf.jp/cloud/)では、[ボリュームのリサイズ](https://www.faq.idcf.jp/app/answers/detail/a_id/120/c/15/related/1/session/L2F2LzEvdGltZS8xNDU3NTE2NDY0L3NpZC8xRDNKTSpLbQ%3D%3D)がオンラインで可能です。そして、DRBDもオンラインでディスク拡張をサポートしています。
といことで、LVMせずにオンライン拡張をやりたいので、そのままフォーマットして使います。(ディスクを束ねたり、パーティションを切るのであればLVMしましょう。)

書くまでもないですが、次のとおりです。

```:普通にフォーマット
# mkfs.xfs -b size=1024 /dev/drbd0
```

ブロックサイズを指定していますが、単純にMySQLで利用する場合に1024の方が早かったからです。環境に依存する部分ですね。

これも書くまでもないですが、マウントです。

```:マウント
# mount -t xfs -o noatime,nodiratime,nobarrier /dev/drbd0 /var/lib/mysql/
```

オプションも適当です。なんでも使えます。

## DRBDの起動と停止とPrimary

```:起動
# drbdadm up r1
```

```:停止
# drbdadm down r1
```

```:Primary
# drbdadm primary r1
```

起動しただけでは`ro:Secondary/Secondary`になるので、どちらかをPrimaryとする必要があります。なお、Primaryで既に利用中の場合(マウントしている場合)はdownさせることはできません。
なので、Primaryにする側で`drbdadm primary r1`を実行してください。

# ディスク拡張
一つ前にも書きましたが、[IDCF Cloud](http://www.idcf.jp/cloud/)では、[ボリュームのリサイズ](https://www.faq.idcf.jp/app/answers/detail/a_id/120/c/15/related/1/session/L2F2LzEvdGltZS8xNDU3NTE2NDY0L3NpZC8xRDNKTSpLbQ%3D%3D)がオンラインで可能です。そして、DRBDもオンラインでディスク拡張をサポートしています。
やってみましょう。

## IDCF Cloud側でボリュームのリサイズ
[Cloudコンソール](https://idcfcloud.com/)([もしくはAPI](http://www.idcf.jp/cloud/spec/api.html))のボリュームメニューから対象ボリュームを選択し、リサイズを実行したください。Primary/Secondary双方で実行しておきます。
仮想マシン選択 => ボリューム => ボリューム操作へ、の方がたどりやすいと思います。

## OSに認識させる
ディスクが拡張されたことをOS側に認識させる必要があります。
CentOS 7ではblockdevを使って簡単に認識させる事ができます。

```:blockdevで認識させる
# fdisk -l /dev/sdb

Disk /dev/sdb: 53.7 GB, 53687091200 bytes, 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト

# blockdev --rereadpt /dev/sdb

# fdisk -l /dev/sdb

Disk /dev/sdb: 64.4 GB, 64424509440 bytes, 125829120 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
```

53.7GBから64.4GBになっている事がわかります。
なお、以下でも同様にOSに拡張されたことを認識させる事ができます。

```:別のやり方
# echo 1 > /sys/class/scsi_device/<device>/device/rescan
```

**注意:** なお、この段階で`drbdadm down r1`などとdownさせてしまうとメタデータが発見できなくなり(メタデータがディスクの末尾に存在するため。拡張されて末尾が変わったから。)`drbdadm up r1`できなくなってしまいますので、注意してください。(もちろん1回ハマった。)

## drbd側を拡張
Primary側で下記を実行します。なお、このやり方は追加した領域の同期をスキップさせるやり方です。初期同期と同様に空の部分を同期しても仕方ない為です。

```:drbd側で拡張&同期スキップ
# drbdadm -- --assume-clean resize r1
```

メタデータの移動などもすべて自動で行ってくれます。

## ファイルシステムを拡張
今回はXFSでフォーマットしていますので、xfs_growfsで拡張します。これもオンラインで可能です。ext4であれば、resize2fsでオンラインのまま拡張できます。

```:オンラインでファイルシステムを拡張
# xfs_growfs /var/lib/mysql/
meta-data=/dev/drbd0             isize=256    agcount=4, agsize=2621351 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=1024   blocks=10485404, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal               bsize=1024   blocks=10240, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 10485404 to 47184444
```

# ディスクが壊れた時の対応と壊れたときの動作を確認
Cloudの場合、ディスクだけ壊れる事はほとんど無いと思いますが、ディスクの取り外しなども容易に試せるので、実験してみます。
また、DRBDはディスクが故障した時に故障したことを上位レイヤー(ファイルシステム)に通知しない、と行った設定が可能(デフォルト)で、そうするとどうなるかというと、Secondary側からデータを引っ張ってきてディスクは生きているかのように振舞ってくれます。つまり上で動いているサービスは継続されることになります。凄いですね！

## ディスク(ボリューム)を取り外す
[IDCF Cloud](http://www.idcf.jp/cloud/)の[Cloudコンソール](https://idcfcloud.com/)([もしくはAPI](http://www.idcf.jp/cloud/spec/api.html))から対象のボリュームを選択しデタッチします。この時仮想マシンはオンラインのままデタッチします。
OSから見ると、いきなりSCSI Diskが無くなった様に見えます。

```:detachVolumeする前
# lsscsi
[0:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR00 1.00  /dev/sr0
[2:0:0:0]    disk    VMware   Virtual disk     1.0   /dev/sda
[2:0:1:0]    disk    VMware   Virtual disk     1.0   /dev/sdb

# cat /proc/drbd
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:0 dw:0 dr:912 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# df -h /var/lib/mysql
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/drbd0        45G  3.7G   42G    9% /var/lib/mysql

# echo "ABC" > /var/lib/mysql/write_ok.txt
# sync
# ls -la /var/lib/mysql/write_ok.txt 
-rw-r--r-- 1 root root 4  3月 10 11:58 /var/lib/mysql/write_ok.txt
```

```:detachVolumeの後
# lsscsi 
[0:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR00 1.00  /dev/sr0 
[2:0:0:0]    disk    VMware   Virtual disk     1.0   /dev/sda 
[2:0:1:0]    disk    VMware   Virtual disk     1.0   /dev/sdb 

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:Diskless/UpToDate C r-----
    ns:2076 nr:24580 dw:26624 dr:3720 al:3 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# df -h /var/lib/mysql
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/drbd0        45G  3.7G   42G    9% /var/lib/mysql

# echo "ABC" > /var/lib/mysql/write_ok2.txt
# ls -la /var/lib/mysql/write_ok2.txt
-rw-r--r-- 1 root root 4  3月 10 13:46 /var/lib/mysql/write_ok2.txt
```

表面上は何事もなく利用できている事がわかります。
`/proc/drbd`で`ds:Diskless/UpToDate`とDisklessと言うステータスに代わっていることぐらいです。

```:OS上のログ
# # dmesg | tail -n 20
[172736.739903] sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
[172736.739916] sd 2:0:1:0: [sdb] CDB: Read(10) 28 00 00 00 00 02 00 00 01 00
[172736.739921] blk_update_request: I/O error, dev sdb, sector 2
[172736.739964] block drbd0: local READ IO error sector 2+1 on sdb
[172736.739971] block drbd0: disk( UpToDate -> Failed ) 
[172736.739987] block drbd0: Local IO failed in __req_mod. Detaching...
[172736.740103] sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
[172736.740106] sd 2:0:1:0: [sdb] CDB: Write(10) 2a 00 05 9f f4 78 00 00 08 00
[172736.740108] blk_update_request: I/O error, dev sdb, sector 94368888
[172736.740131] block drbd0: IO ERROR -5 on bitmap page idx 0
[172736.740162] block drbd0: bitmap WRITE of 1 pages took 0 jiffies
[172736.740163] block drbd0: we had at least one MD IO ERROR during bitmap IO
[172736.740186] block drbd0: 4 KB (1 bits) marked out-of-sync by on disk bit-map.
[172736.740211] sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
[172736.740213] sd 2:0:1:0: [sdb] CDB: Write(10) 2a 00 05 9f ff f8 00 00 08 00
[172736.740214] blk_update_request: I/O error, dev sdb, sector 94371832
[172736.740361] block drbd0: drbd_md_sync_page_io(,94371832s,WRITE) failed with error -5
[172736.740396] block drbd0: meta data update failed!
[172736.740414] block drbd0: disk( Failed -> Diskless ) 
[172736.742766] block drbd0: receiver updated UUIDs to effective data uuid: 757734BAC87B2EC0

# tail -n 22 /var/log/messages
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] CDB: Read(10) 28 00 00 00 00 02 00 00 01 00
Mar 10 13:43:36 localhost kernel: blk_update_request: I/O error, dev sdb, sector 2
Mar 10 13:43:36 localhost kernel: block drbd0: local READ IO error sector 2+1 on sdb
Mar 10 13:43:36 localhost kernel: block drbd0: disk( UpToDate -> Failed ) 
Mar 10 13:43:36 localhost kernel: block drbd0: Local IO failed in __req_mod. Detaching...
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] CDB: Write(10) 2a 00 05 9f f4 78 00 00 08 00
Mar 10 13:43:36 localhost kernel: blk_update_request: I/O error, dev sdb, sector 94368888
Mar 10 13:43:36 localhost kernel: block drbd0: IO ERROR -5 on bitmap page idx 0
Mar 10 13:43:36 localhost kernel: block drbd0: bitmap WRITE of 1 pages took 0 jiffies
Mar 10 13:43:36 localhost kernel: block drbd0: we had at least one MD IO ERROR during bitmap IO
Mar 10 13:43:36 localhost kernel: block drbd0: 4 KB (1 bits) marked out-of-sync by on disk bit-map.
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] FAILED Result: hostbyte=DID_NO_CONNECT driverbyte=DRIVER_OK
Mar 10 13:43:36 localhost kernel: sd 2:0:1:0: [sdb] CDB: Write(10) 2a 00 05 9f ff f8 00 00 08 00
Mar 10 13:43:36 localhost kernel: blk_update_request: I/O error, dev sdb, sector 94371832
Mar 10 13:43:36 localhost kernel: block drbd0: drbd_md_sync_page_io(,94371832s,WRITE) failed with error -5
Mar 10 13:43:36 localhost kernel: block drbd0: meta data update failed!
Mar 10 13:43:36 localhost kernel: block drbd0: disk( Failed -> Diskless ) 
Mar 10 13:43:36 localhost kernel: block drbd0: receiver updated UUIDs to effective data uuid: 757734BAC87B2EC0
```

流石にOSのログにはそこそこ色々出ていますね。DRBDのStatusはUptoDate -> Failed -> Disklessと変わって行った事がわかります。

# 壊れたディスクを交換
一つ前でdetachVolumeしてしまったディスクは捨てて、新規にディスクを接続しPrimaryのディスクを復元してみます。

## 壊れたディスクをOSから切り離す
detachVolumeしてしまっているので、既に接続はされいないのですが、OSはまだあるものとして処理しています。まず、壊れたディスクをOSから切り離します。
SCSI Diskは`echo 1 > /sys/block/sdb/device/delete`で切り離す事ができます。

```:ディスクの切り離し
# lsscsi
[0:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR00 1.00  /dev/sr0 
[2:0:0:0]    disk    VMware   Virtual disk     1.0   /dev/sda 
[2:0:1:0]    disk    VMware   Virtual disk     1.0   /dev/sdb 

# echo 1 > /sys/block/sdb/device/delete 

# lsscsi
[0:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR00 1.00  /dev/sr0 
[2:0:0:0]    disk    VMware   Virtual disk     1.0   /dev/sda 
```

これで`/dev/sdb`を切り離せました。

## ディスク(ボリューム)の追加
[IDCF Cloud](http://www.idcf.jp/cloud/)の[Cloudコンソール](https://idcfcloud.com/)([もしくはAPI](http://www.idcf.jp/cloud/spec/api.html))からボリュームを作成(Secondary側と同サイズ)してPrimary Nodeの仮想マシンへアタッチします。(ボリューム => ボリューム作成 => できたボリューム選択 => アタッチ)
仮想マシンはオンラインのままボリュームのアタッチを行います。

## OSに追加したディスクを認識させる
SCSIは`echo "- - -" > /sys/class/scsi_host/host?/scan`とすることで、SCSI Busのrescanができます。rescanすることで、オンラインのままディスクを認識させる事ができます。

```:Diskを認識させる
# echo "- - -" > /sys/class/scsi_host/host0/scan
# echo "- - -" > /sys/class/scsi_host/host1/scan
# echo "- - -" > /sys/class/scsi_host/host2/scan
# echo "- - -" > /sys/class/scsi_host/host3/scan
# echo "- - -" > /sys/class/scsi_host/host4/scan
# echo "- - -" > /sys/class/scsi_host/host5/scan
# echo "- - -" > /sys/class/scsi_host/host6/scan

# lsscsi
[0:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR00 1.00  /dev/sr0 
[2:0:0:0]    disk    VMware   Virtual disk     1.0   /dev/sda 
[2:0:1:0]    disk    VMware   Virtual disk     1.0   /dev/sdb 
```

[IDCF Cloud](http://www.idcf.jp/cloud/)の仮想マシンはなぜかSCSI Cardが4枚も接続されているらしく、ATAと合わせるとSCSI Cardが6枚もあることになっています。
大抵はhost2へディスクが接続されるようなのですが、良くわからないのでSCSI Card分rescanしてしまいましょう。(rescanしても特に問題ありません。)

## DRBDのメタデータを再作成
基本的には新規インストールと同じです。

```:メタデータ作成
# drbdadm create-md r1
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.
success
```

## DRBDのリソースを再接続
リソースを再接続すれば完了です。

```:リソースを再接続
# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:Diskless/UpToDate C r-----
    ns:2095 nr:24580 dw:26624 dr:3720 al:3 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# drbdadm attach r1 

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:SyncTarget ro:Primary/Secondary ds:Inconsistent/UpToDate C r-----
    ns:0 nr:3740 dw:3304 dr:20 al:3 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:47181140
	[>....................] sync'ed:  0.1% (46072/46076)M
	finish: 7:16:51 speed: 1,652 (1,652) want: 2,160 K/sec

# echo "ABC" > /var/lib/mysql/write_ok3.txt

# ls -la /var/lib/mysql/write_ok3.txt 
-rw-r--r-- 1 root root 4  3月 10 14:33 /var/lib/mysql/write_ok3.txt

```

同期が完了していなくても、問題なく利用できています。
同期が完了すると、`ds:UpToDate/UpToDate`になります。

ディスクが壊れただけであれば、再構築まですべてオンラインで完結し、止まることもないのでサービスの継続性も失われません。(遅くはなりますが。とは言え、[IDCF Cloud](http://www.idcf.jp/cloud/)はネットワークもディスクも速いので、よっぽどディスクアクセスがない限りは結構使えると思います。)

# Primary/Secondaryの切り替え
* どちらか一方が既にPrimaryの場合は、切り換えられません。
* 利用中の場合はdownしたSecondaryに切り替えることはできません。

```:primaryがいたらprimaryにはなれない
# drbdadm primary r1
0: State change failed: (-1) Multiple primaries not allowed by config
Command 'drbdsetup-84 primary 0' terminated with exit code 11
```

```:利用中はダメ
# drbdadm secondary r1
0: State change failed: (-12) Device is held open by someone
Command 'drbdsetup-84 secondary 0' terminated with exit code 11
```

```:mountしてなければOK
# unmount /var/lib/mysql

# drbdadm secondary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:34 nr:47184880 dw:47184478 dr:20 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

ということで、以下が正しい順番になります。
1. サービス停止 (ex:systemctl stop mysqld)
2. unmount (ex: unmount /dev/drbd0)
3. primary側で `drbdadm secondary r1`
4. secondary側で、`drbdadm primary r1 `


# Primary側がOSごと死んだ時
この場合、まずはサービス復旧しないといけないので、SecondaryをPrimaryに昇格し、マウントしてサービスを起動します。
これは既にPrimaryが死んでいるので普通にPrimaryに昇格してしまって問題ありません。

```:Primaryに昇格してマウント
# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:WFConnection ro:Secondary/Unknown ds:UpToDate/DUnknown C r-----
    ns:47212713 nr:8448 dw:8448 dr:47212713 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# drbdadm primary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:WFConnection ro:Primary/Unknown ds:UpToDate/DUnknown C r-----
    ns:47212713 nr:8448 dw:8448 dr:47213625 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# mount -t xfs -o noatime,nodiratime,nobarrier /dev/drbd0 /var/lib/mysql/
```

この後は、壊れた元Primaryを復旧するわけですが、これは新規インストールと同様に進めて問題ありません。`drbdadb up r1`した時点で同期が開始されます。

一つ問題があるとすると、IPアドレスだと思います。DRBDでは後からIPを変更する事ができません。(と思う。方法があるのかもしれないが。)[IDCF Cloud](http://www.idcf.jp/cloud/)の場合特に何も考えないとDHCPになってしまいます。[IDCF Cloud](http://www.idcf.jp/cloud/)はIPをstaticで管理することも可能なので、同期セグメントのIPはstaticに管理した方がいいと思います。

# スプリットブレインについて
スプリットブレインとは両方のノードがPrimayになってしまった状態のことを言います。これはどちらも書き込みができてしまう大変危険な状態です。
今までの説明でもわかるように、勝手にPrimary/Primaryの状態にはなりません。人為的ミスやクラスターソフトウェアのミスにより発生する可能性があります。
例えば、ネットワークの分断が発生して、両ノードがお互いを認識できない状態の時、Secondary側で`drbdadm primary r1`などすると発生します。

障害が発生してSecondary Nodeで`drbdadm primary r1`する時は、必ず元Primaryをシャットダウンしてから実行するようにしましょう。
もし、スプリットブレイン状態になってしまったら、どちらか片方のデータを諦めるしかありません。

## スプリットブレインの実験
ここではネットワーク分断を再現して、実験してみましょう。

### ネットワークを停止
単純にネットワークインターフェースをダウンして再現します。
今回はPrimary側でネットワークをダウンさせます。

```:ネットワークを分断
# nmcli connection down f773ed44-f459-490e-acef-568376f1126b
Connection 'eno33557248' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/0)
```

### ネットワーク分断時のDRBDの状態

```:Primary側
# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown   r-----
    ns:2056 nr:0 dw:0 dr:3880 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

ネットワーク分断が発生すると`cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown`となり、StandAloneとなるようです。StandAloneはリソースがdisconnect状態なので、ファイルシステムとしては使えているが、drbdからは切り離されているような状態になります。(正確ではないかも。)

この時、Secondary側を見ると、次のようになっています。

```:Secondary側
# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:WFConnection ro:Secondary/Unknown ds:UpToDate/DUnknown C r-----
    ns:0 nr:2056 dw:4106 dr:13380 al:4 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

Secondary側はStandAloneモードにはならないようです。

### Secondary側をPrimaryに昇格
この状態の場合、SecondaryはPrimaryが居ないのでPrimaryに昇格できます。

```:Primaryに昇格させる
# drbdadm primary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:WFConnection ro:Primary/Unknown ds:UpToDate/DUnknown C r-----
    ns:0 nr:2056 dw:4106 dr:14292 al:4 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

# mount -t xfs -o noatime,nodiratime,nobarrier /dev/drbd0 /var/lib/mysql/
```

これで両方が「自分はPrimaryだ」と言っている状態になりました。どっちらにも書き込めてしまう厄介な状態です。両方に書き込むとデータが分断してしまいますね。

## スプリットブレインの解消
こうなってしまったら、どちらかのデータを捨てるしかありません。残す方を決めて、必要なデータを捨てる方から取り出し、スプリットブレインを解消します。
今回はネットワークを停止した、最初からPrimaryの方のデータを残す形でスプリットブレインを解消してみます。

## 両ノードにデータを書き込む
動きを確認したいので、両ノードからデータを書き込んでおきます。

```:元からPrimaryに書き込み
# echo "ABC" > /var/lib/mysql/write_ok_primary.txt

# ls -la /var/lib/mysql/write_ok_primary.txt
-rw-r--r-- 1 root root 4  3月 10 17:55 /var/lib/mysql/write_ok_primary.txt
```

```:元はSecondaryに書き込み
# echo "ABC" > /var/lib/mysql/write_ok_new_primary.txt

# ls -la /var/lib/mysql/write_ok_new_primary.txt
-rw-r--r-- 1 root root 4  3月 10 17:54 /var/lib/mysql/write_ok_new_primary.txt
```

### ネットワークの復旧
先ずはネットワークをダウンした元々Primary側でネットワークを復旧しましょう。

```:ネットワークを復旧
# nmcli connection up f773ed44-f459-490e-acef-568376f1126b 
接続が正常にアクティベートされました (D-Bus アクティブパス: /org/freedesktop/NetworkManager/ActiveConnection/3)
```

### 元SecondaryをStandAloneへ切り替え
次に元SecondaryをStandAloneの接続状態へ切り替えます。データを捨てるノードはStandAlone状態である必要があります。

```:StandAloneへ移行
# drbdadm disconnect r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown   r-----
    ns:0 nr:2056 dw:8268 dr:19428 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:2096
```

### 元SecondaryをSecondaryに戻す
次に元SecondaryをSecondaryに戻します。マウントしているとsecondaryにできないため、unmountしておく必要があります。

```:Secondaryに変更する
# umount /var/lib/mysql/

# drbdadm secondary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:StandAlone ro:Secondary/Unknown ds:UpToDate/DUnknown   r-----
    ns:0 nr:2056 dw:8271 dr:19428 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:2096
```

### 元SecondaryのStandAloneの回復とデータ破棄
次にStandAloneからの回復と、スプリットブレインが起きてから書き込んだデータを破棄します。

```:書き込んだデータを破棄
# drbdadm connect --discard-my-data r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:WFConnection ro:Secondary/Unknown ds:UpToDate/DUnknown C r-----
    ns:0 nr:0 dw:8271 dr:19428 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:2096
```

### 元々Primaryの方をStandAloneから回復
元々Primaryの方がまだStandAlone状態なので、これを回復します。

```:元々PrimaryをStandAloneから回復
# drbdadm connect r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:2096 nr:0 dw:0 dr:5976 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

元々Primaryの方に書き込んだデータがSecondaryに同期され、`ds:UpToDate/UpToDate`になれば、復旧完了です。

### Secondaryのデータを確認
Secondaryのデータが破棄されて、元々Primaryと同じ状態になっているか確認してみます。

```:Primaryのデータを確認
# ls -la /var/lib/mysql/write_ok_primary.txt 
-rw-r--r-- 1 root root 4  3月 10 18:23 /var/lib/mysql/write_ok_primary.txt
```

```:PrimaryをSecondaryに降格
# umount /var/lib/mysql/

# drbdadm secondary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:2090 nr:0 dw:2082 dr:10876 al:5 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

```:元々SecondaryをPrimaryに昇格
# drbdadm primary r1

# cat /proc/drbd 
version: 8.4.7-1 (api:1/proto:86-101)
GIT-hash: 3a6a769340ef93b1ba2792c6461250790795db49 build by phil@Build64R7, 2016-01-12 14:29:40
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:2090 dw:16587 dr:23609 al:6 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
```

```:データを確認
# mount -t xfs -o noatime,nodiratime,nobarrier /dev/drbd0 /var/lib/mysql/

# ls -la /var/lib/mysql/write_ok_primary.txt
-rw-r--r-- 1 root root 4  3月 10 18:23 /var/lib/mysql/write_ok_primary.txt

# ls -la /var/lib/mysql/write_ok_new_primary.txt
ls: /var/lib/mysql/write_ok_new_primary.txt にアクセスできません: そのようなファイルやディレクトリはありません
```

スプリットブレイン時に書き込んだ`write_ok_new_primary.txt`が無く、`write_ok_primary.txt`が同期できている事がわかります。

# クラスタソフト
DRBDだけではPrimaryノードの障害時に障害を検知して、SecondaryノードをPrimaryへ昇格などといったことはできません。
これらは別のクラスターソフトウェアを利用する必要があります。
DRBDのドキュメントではPacemaker、Red Hat Cluster Suiteとの組み合わせが記載されています。
今のところ自分はこの部分に興味がないので、ドキュメント見て頑張ってください！