FreeBSDのHASTを触ってみた。
FreeBSDのHASTを触ってみた。
こういうのは最近ならQiitaあたりに書いた方がいいんだろうけど。
特徴など
- ストレージをBlock Deviceレベルで同期
- 実際にファイルを扱うにはBlock Deviceに対してufsやZFSでフォーマット/マウントする
- PrimaryからSecondaryへの同期
- 同時利用はできない
- 基本的にはActive-Standbyとして利用
- 同期対象サーバの変更は可能
- /etc/hast.confを修正し、service hastd reload で無停止で変更可能と思われる
- サイズの拡張はできない
- FreeBSD 11.0では標準で利用可能
- マニュアルなど
- https://www.freebsd.org/doc/handbook/disks-hast.html
- http://www.jp.freebsd.org/cgi/mroff.cgi?sect=8&cmd=&lc=1&subdir=man&dir=jpman-11.0.2%2Fman&subdir=man&man=hastd
- http://www.jp.freebsd.org/cgi/mroff.cgi?sect=5&cmd=&lc=1&subdir=man&dir=jpman-11.0.2%2Fman&subdir=man&man=hast.conf
- http://www.jp.freebsd.org/cgi/mroff.cgi?sect=8&cmd=&lc=1&subdir=man&dir=jpman-11.0.2%2Fman&subdir=man&man=hastctl
インストール・設定
- インストールは特に必要なし(FreeBSD 11.0)
- 設定ファイル: /etc/hast.conf
replication memsync resource shared1 { local /dev/vtbd1p1 on host1 { remote 192.168.0.102 } on host2 { remote 192.168.0.101 } } resource shared2 { local /var/hast/shared.img on host1 { remote 192.168.0.102 } on host2 { remote 192.168.0.101 } }
- replicationはmemsyncがデフォルト、fullsyncが安全で遅い
- execでイベント発生時にプログラムの実行が可能
- ブロックデバイスを利用する場合はそのまま指定する
- パーティションは切っておいたほうがよいと思われる
- サイズを一致させるため
- ストレージのサイズが大きくなった時(仮想環境など)に後ろのブロックを利用するため
- パーティションは切っておいたほうがよいと思われる
# gpart create -s gpt vtbd1 # gpart add -t freebsd-ufs -s 10G vtbd1 # gpart show vtbd1
- ファイルを使う場合は必要なサイズのファイルを作る
# mkdir /var/hast # dd if=/dev/zero of=/var/hast/shared.img bs=10m count=1024
- ※ただし、ファイルを使った場合に問題が生じるケースがある模様
- ブロックデバイスにしろファイルにしろ、サイズが不一致の場合は同期できない
- /var/log/messagesにエラーが残る
- 逆にサイズさえ合っていればブロックデバイスとファイルとの同期もされる模様
hastctl による操作
- 初期化
# hastctl create shared1
- create でリソースを初期化する
- 初めてアクセスする前に実行する
- 問題が生じて再初期化時にも利用
- 状態変更
# hastctl role primary shared1
- role primary 時に /dev/hast/{リソース名} にアクセス可能になる
- 同時に両方primaryにできる(排他制御などはしてない模様)
# hastctl role secondary shared1
- role secondary にすることで、primaryと同期される
- hastd起動時はrole init なので、secondaryにする必要がある
- 状態確認
# hastctl status shared1 # hastctl list shared1
- 同期の状態などを確認可能
- Split-brainになった場合
- /var/log/messages にSplit-brainを検知した旨と対象のリソース名が残る(Primary Secondary共)
- Split-brain時にconfのexecで指定したものが起動されるので、そこで対応は可能(ただしSplit-brain時以外にも呼ばれる)
- セカンダリ側で下記を実行すると復旧する:
- /var/log/messages にSplit-brainを検知した旨と対象のリソース名が残る(Primary Secondary共)
# hastctrl role init {リソース名} # hastctrl create {リソース名} # hastctrl role secondary {リソース名}
状態について
- roleはinit, primary, secondaryの3種類
- role initの時は動作していない
- role primaryの時に /dev/hast/{リソース名} として参照可能になる
- role secondaryの時にprimaryからの同期データを受信している
- role primaryの排他制御などはしていないらしく、同時にprimaryにしてしまうことができる
- これを回避する方法は特にない?(primaryに変えるときに注意するしかない?)
- 切替え時には両方をsecondaryにしてから、片方をprimaryにする必要がある
- 両方primaryにするとhastdが刺さった状態になる模様。プロセスをkillする必要がある。
# kill -KILL `cat /var/run/hastd.pid`
- hastctl statusでcompleteになっていても、同期は完了していない模様
- hastctl listで表示されるdirtyが0になった時に完了している?
- HASTデバイスを利用するサービスはrc.confで有効にしないほうがよい
- role primary & mount後にアクセスする必要があるため
- 上記でアクセス可能になったあとでservice {サービス名} onestart で起動
- 起動時はrole initのため、なんらかの方法でrole secondaryにする必要がある
- CARPを使った事例ではcarpの状態変更に合わせてroleを変更する
- pacemaker + corosyncでの対応もおそらく可能
- ※corosyncのports/pkgが動かなくて未検証
ファイルシステムについて
ufsで利用する場合
- 初期化
# newfs -U -j /dev/hast/shared1
# hastctl role primary shared1 # fsck -y -t ufs /dev/hast/shared1 # mount -o noatime /dev/hast/shared1 /mnt/shared # application_start
ZFSで利用する場合
- 初期化
# zpool create hast-zfs /dev/hast/shared2 # zfs create -o mountpoint=/mnt/shared hast-zfs/shared
- role prymary以外にする時にzpool exportしておかないと問題が生じる
- また、zpool exportしておかないとshutdownに失敗する(どこかで刺さっている?)
# zpool export hast-zfs # hastctl role secondary shared2
- zpool import時は正常にexportされていない可能性があるため(ダウン時のリカバリ等)、-fオプションを常に付けたほうがよいかもしれない
# hastctl role primary shared2 # zpool import -f -d /dev/hast/ hast-zfs
- 異常終了時はzpool exportされていないため、zpool statusを見るとstate:UNAVAILになっている
- この時はzpool exportしておいたほうがよいかもしれない
- exportしていないときにrole primaryになると自動的にONLINEになる(mountはされない)
簡易ツール
dirtry値のチェック
#!/bin/sh # check options while getopts aq opt do case $opt in a) option_all=1 ;; q) option_quiet=1 ;; esac done # target resources shift $(($OPTIND - 1)) if [ "$*" ]; then resources="$*" else resources=$(/sbin/hastctl dump | /usr/bin/awk '/^ *resource: / {print $2}') fi # view dirty dirtycount=0 for res in $resources; do dirty=$(/sbin/hastctl list $res | /usr/bin/awk '/^ *dirty: / {print $2}') [ $dirty -ne 0 ] && dirtycount=$(($dirtycount + 1)) [ $option_quiet ] && continue if [ $dirty -ne 0 -o "$option_all" ]; then echo "$res $dirty" fi done exit $dirtycount
- オプションなしの場合、dirty値があるリソースとそのdirty値が表示される
- オプション-aでdirty値がないリソース(とそのdirty値)も表示される
- オプション-qで何も表示しない
- リソース名を渡すと、そのリソースのみチェックする
- 終了ステータスにdirty値があるリソースの数を返す
Sprit-brain時の同期状態リセット
#!/bin/sh syslog_facility="user.notice" syslog_tag="hast-event" logger="/usr/bin/logger -p $syslog_facility -t $syslog_tag" resource=$1 [ $resource ] || exit 1 # check role secondaryj roletype=$( /sbin/hastctl list $resource | /usr/bin/awk '/^[\t ]*role:[\t ]+/ {print $2}' ) [ "$roletype" = "primary" ] && exit # recover $logger "HAST [$resource] recover" /sbin/hastctl role init $resource /sbin/hastctl create $resource /sbin/hastctl role $roletype $resource
- リソース名を渡すと、そのリソースの同期状態をリセットする
- ただし、role primaryの時は何もしない
- role init の時はrole secondaryに変更しないため、そのままでは同期されない(role secondaryに変更する必要がある)