クラスターソフトをスクリプトで書いてみよう～実践編

# 概要
- クラスターソフト簡単スクリプトの概要
- クラスターソフト簡単スクリプトのコード
- 実行結果

# はじめに
[前回の理論編](https://qiita.com/tsunenorikan/items/6491dacc8fe042fc193d "クラスターソフトをスクリプトで書いてみよう~理論編")ではクラスターソフトの概要について述べました。今回の実践編ではクラスターソフトの簡単な実装をPowerShellで書いてみて、障害検知させてデータベースをスタンバイに切り替えてみます。

# 環境
Windows 10
PowerShell 5.1.18362.1110
IBM Db2 V11.1
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698263/ebdea5b6-9e92-0be0-fbbc-43610b72ad82.png)

# 使用する方式

### 生死監視
スタンバイからアクティブへpingでハートビートをします。
これだけです。
つまり、アクティブがpingに応答しない場合のみ障害検知して切り替えが発生します。

### データの引き継ぎ
データベースのレプリケーション機能でデータを共有します。
レプリケーションはIBM Db2 HADRを使います。
障害検知した時はデータベースコマンドを用いてスタンバイへの切り替えを行います。

### ネットワークの引き継ぎ
データベースの代替IP機能を使用するため、スクリプトでは実装しません。
IBM Db2 自動クライアントリルートを使います。

### スプリットブレイン防止策
ルーターをネットワークタイブレーカーにしてpingで導通確認します。

# 切り替え条件
以下の条件の場合、障害を検知したとみなしてスタンバイへの切り替えが発生します。

1. 役割がスタンバイなら(データベースコマンドで確認)
2. ネットワークタイブレーカー(ルーター)に導通成功したら
3. アクティブサーバーに導通失敗したら
4. 1~3を繰り返して規定回数に達したら

# スクリプト
スクリプトの概要は以下です。
1. スタンバイへの切り替え条件を永久ループでチェック
2. 切り替え条件を満たしたら、データベースの正常切り替えを試行
3. 正常切り替えできない場合、データベースの強制切り替えを試行
4. 切り替えの試行ののち、スクリプトを終了

```pingDeadOrArrive_Qiita.ps1
$primaryip  = '192.168.0.7' # 本番サーバーのIPアドレス
$nerworkip  = '192.168.0.1' # ネットワーク確認用のIPアドレス
$dbname     = 'TEST01'      # データベース名
$try        = 5             # 試行回数
$sec        = 60            # スリープする秒数

set-item -path env:DB2CLP -value "**$$**" # Db2コマンドラインを使用可能にする
$count   = 0
$outfile = (Split-Path $MyInvocation.MyCommand.Path) + "\" + [io.path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name) + ".log"
"監視開始 " + $MyInvocation.MyCommand.Name | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append

while($true) {
    db2pd -db $dbname -hadr | select-string -pattern "HADR_ROLE" | %{$status =$_} # サーバーの役割を取得

    if($status -match "STANDBY"){
        '役割状況 ' + "$status".trim() | %{(Get-Date).ToString() + " $_"}
        if (Test-Connection -ComputerName $nerworkip -Quiet) {
            '回線接続 ' + $nerworkip | %{(Get-Date).ToString() + " $_"}
            if (Test-Connection -ComputerName $primaryip -Quiet) {
                '導通成功 ' + $primaryip | %{(Get-Date).ToString() + " $_"}
                $count = 0
            } else {
                '導通失敗 ' + $primaryip | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
                $count++
            }
        } else {
            '回線不通 ' + $nerworkip | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
            $count = 0
        }
    } else {
        '役割状況 スタンバイではありません ' + "$status".trim() | %{(Get-Date).ToString() + " $_"}
        $count = 0
    }

    if($count -gt 0) {
        "失敗回数 " + $count | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
    }

    if($count -lt $try) {
        "監視継続 中止するときはCtrl+Cを押してください。" | %{(Get-Date).ToString() + " $_"}
        "スリープ " + $sec.ToString() + "秒間" | %{(Get-Date).ToString() + " $_"}
        Sleep $sec
    } else {
        db2 takeover hadr on db $dbname | select-string -pattern "[SQL|DB2]" | %{$result =$_}
        "通常切替 " + $result | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
        db2pd -db $dbname -hadr | select-string -pattern "HADR_ROLE" | %{$status =$_}

        if($result -notmatch "DB20000I") { # 切り替えが正常終了しなかった場合
            if ($status -match "STANDBY") {
                db2 takeover hadr on db $dbname by force | select-string -pattern "[SQL|DB2]" | %{$result =$_}
                "強制切替 " + $result | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
            } else {
                "切替保留 スタンバイではありません" + "$status".trim() | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
            }
        }
        break
    }
}

"監視終了 " + $MyInvocation.MyCommand.Name | %{(Get-Date).ToString() + " $_"} | Tee-Object $outfile -Append
```
# 実行結果
スクリプトをスタンバイで実行します。障害をシュミレーションするため、アクティブサーバーでpingに応答しないようにします。画面キャプチャーでは5回確認してスタンバイへ切り替わっています。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698263/b890fcfb-e3e6-1dcc-29c6-ffa2fa607e1f.png)
# さいごに
一番簡単な障害検知、つまり、pingの応答ですとスクリプトでクラスターソフトが書けます。言い換えるといかにきめ細やかに障害検知ができ、誤った切り替えが発生しないのがクラスターソフトの巧拙になります。ただし、クラスターソフトは学習コストが高いので、使いこなせないのならスクリプトで監視するのもありだと思います。