Db2リカバリまとめ

Db2での擬似障害からの復旧のまとめ（クラッシュリカバリではなくリストアが必要なケース）。
以下、意図的に破壊行為を働いているので、間違っても大切な環境でのお試しは禁物。。。

# 前提環境
```bash
cat /etc/redhat-release
uname -a
db2licm -l
```

```
Red Hat Enterprise Linux Server release 7.3 (Maipo)

Linux db2 3.10.0-514.el7.x86_64 #1 SMP Wed Oct 19 11:24:13 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux

Product name:                     "IBM DB2 Developer-C Edition"
License type:                     "Community"
Expiry date:                      "Permanent"
Product identifier:               "db2dec"
Version information:              "11.1"
Max amount of memory (GB):        "16"
Max number of cores:              "4"
Max amount of table space (GB):   "100"
```

# テスト対象DB作成
作成するディレクトリは、実環境では全て別ディスクにする想定（マウントポイント）。
## 循環ログのDB（DB11）
```bash
# ディレクトリ作成
mkdir /db/db11
cd /db/db11; pwd
mkdir bkup database tbsp1 tbsp2 log1 log2

# DB作成
db2 "CREATE DB DB11
    AUTOMATIC STORAGE YES
    ON /db/db11/tbsp1,/db/db11/tbsp2
    DBPATH ON /db/db11/database
"

# ログ設定変更
db2 "UPDATE DB CFG FOR DB11 USING
    NEWLOGPATH    /db/db11/log1
    MIRRORLOGPATH /db/db11/log2
"

# 初期データ生成
db2 "CONNECT TO DB11"
db2 "CREATE TABLE Hogetbl (
    id INTEGER PRIMARY KEY NOT NULL,
    dsc VARCHAR(128))
"
db2 "INSERT INTO Hogetbl VALUES(1, 'hope')"
```

## アーカイブログのDB（DB22）
```bash
# ディレクトリ作成
mkdir /db/db22
cd /db/db22; pwd
mkdir bkup database tbsp1 tbsp2 log1 log2 logarch

# DB作成
db2 "CREATE DB DB22
    AUTOMATIC STORAGE YES
    ON /db/db22/tbsp1,/db/db22/tbsp2
    DBPATH ON /db/db22/database
"

# ログ設定変更
db2 "UPDATE DB CFG FOR DB22 USING
    NEWLOGPATH    /db/db22/log1
    MIRRORLOGPATH /db/db22/log2
    LOGARCHMETH1 DISK:/db/db22/logarch
"

# 初期バックアップ（アーカイブログ方式に変更したのでBACKUP PENDINGになる）
db2 "BACKUP DB DB22 TO /db/db22/bkup"

# 初期データ生成
db2 "CONNECT TO DB22"
db2 "CREATE TABLE Hogetbl (
    id INTEGER PRIMARY KEY NOT NULL,
    dsc VARCHAR(128))
"
db2 "INSERT INTO Hogetbl VALUES(1, 'hope')"
```

# Part1. 循環ログでのバックアップとリストア
## シナリオ１：テーブルスペースのディスク障害
```bash
# バックアップ取得
db2 "FORCE APPLICATIONS ALL"
db2 "TERMINATE"
db2 "DEACTIVATE DB DB11"
db2 "BACKUP DB DB11 TO /db/db11/bkup"

# テーブルスペース擬似障害
rm -rf /db/db11/tbsp[12]/*

# DBアクティベート
db2 "ACTIVATE DB DB11"
```

```
SQL0293N  Error accessing a table space container.  SQLSTATE=57048
```

```bash
# バックアップからリストアして確認
db2 "RESTORE DB DB11 FROM /db/db11/bkup"
db2 "CONNECT TO DB11"
db2 "SELECT * FROM Hogetbl"
ls -l /db/db11/tbsp[12]
```

## シナリオ２：一次トランザクションログのディスク障害
```bash
# 一次ログ擬似障害
rm -rf /db/db11/log1

db2 "INSERT INTO Hogetbl VALUES(2,'hoge')" # エラーなし。ミラーログで業務継続

# 復旧
mkdir /db/db11/log1
db2 "FORCE APPLICATIONS ALL"
db2 "TERMINATE"
db2 "DEACTIVATE DB DB11"
db2 "ACTIVATE DB DB11"
ls /db/db11/log1/NODE0000/LOGSTREAM0000
```

```
S0000000.LOG  S0000002.LOG  S0000004.LOG  S0000006.LOG  S0000008.LOG  S0000010.LOG  S0000012.LOG
S0000001.LOG  S0000003.LOG  S0000005.LOG  S0000007.LOG  S0000009.LOG  S0000011.LOG  SQLLPATH.TAG
```

一次ログが復活した。

# シナリオ３：トランザクションログのディスク障害（一次、二次とも全滅）
```bash
# 擬似障害
rm -rf /db/db11/log[12]

db2 "DELETE FROM Hogetbl" # 戻ってこないしCtrl+cも効かないのでkill -9した

# 再接続を試みる
db2 "CONNECT TO DB DB11"
```

```
SQL1034C  The database was damaged, so all applications processing the 
database were stopped.  SQLSTATE=58031
```

```bash
# 完全に壊れた（当たり前）ので落としてログディレクトリ再作成してリストア
# また、コネクションが残っていたりしてDBを正常に非活性にできないので強制終了
db2 "DEACTIVATE DB DB11"
db2stop force                     # これも効かないのでOS再起動。。。

# ログディレクトリ復旧
mkdir /db/db11/log1 /db/db11/log2

# DBリストアして復旧
db2 "RESTORE DB DB01 FROM /db/db11/bkup"
db2 "ACTIVATE DB DB11"
ls -l /db/db11/log[12]/*/*/*

# 復旧確認
db2 "CONNECT TO DB11"
db2 "SELECT * FROM Hogetbl"
db2 "INSERT INTO Hogetbl VALUES(2, 'hoge')"
db2 "SELECT * FROM Hogetbl"
```

循環ログではアーカイブログを使ってロールフォワードする必要がない（できない）ので壊れたら戻す、ただそれだけ。

# Part2. アーカイブログでのバックアップとリストア
## シナリオ１：テーブルスペースとログの障害
```bash
# オンラインバックアップ取得
db2 "ACTIVATE DB DB22"
db2 "FORCE APPLICATIONS ALL"
db2 "BACKUP DB DB22 ONLINE TO /db/db22/bkup INCLUDE LOGS"
db2 "LIST HISTORY BACKUP ALL FOR DB22" # ロールフォワードに必要なログがわかる

# テーブルスペース擬似障害
rm -rf /db/db22/tbsp[12]/*
# アーカイブログも喪失
rm -f /db/db22/logarch/dbinst/DB22/NODE0000/LOGSTREAM0000/C000000*/*.LOG
# アクティブログも喪失
rm -f /db/db22/log[12]/*/*/*.LOG

# DBリストア
db2 "DEACTIVATE DB DB22"
# バックアップデータ確認
db2ckbkp -H /db/db22/bkup/DB22.0.dbinst.DBPART000.20181031222046.001
# ログも一緒に戻す
mkdir /db/db22/ovflog
db2 "RESTORE DB DB22 LOGS
 FROM /db/db22/bkup TAKEN AT 20181031222046
 LOGTARGET /db/db22/ovflog"

# 戻したログからロールフォワード
db2 "ROLLFORWARD DB DB22 TO END OF LOGS OVERFLOW LOG PATH(/db/db22/ovflog)"
# OKならペンディング解除
db2 "ROLLFORWARD DB DB22 COMPLETE OVERFLOW LOG PATH(/db/db22/ovflog)"

# 復旧確認
db2 "ACTIVATE DB DB22"
db2 "CONNECT TO DB22"
db2 "SELECT * FROM Hogetbl"
db2 "INSERT INTO Hogetbl VALUES(2,'hoge')"
db2 "SELECT * FROM Hogetbl"
```

## シナリオ２：テーブルスペースの障害（ログは残存）
```bash
# 現行ログ確認
db2 "GET DB CFG FOR DB22" | grep "First active"
# オンラインバックアップ取得（ログ含めず）
db2 "BACKUP DB DB22 ONLINE TO /db/db22/bkup EXCLUDE LOGS"
# バックアップ取得開始時点のアクティブログがアーカイブされている
db2 "GET DB CFG FOR DB22" | grep "First active"
db2 "LIST HISTORY BACKUP ALL FOR DB22" # ロールフォワードに必要なログ確認
```

オンラインバックアップ取得前のアクティブログ（First active log）は、"S0000004.LOG"だった。
オンラインバックアップ後に当該ログはアーカイブされ、再度確認するとアクティブログは"S0000005.LOG"になった。
当然、`LIST HISTORY BACKUP ALL FOR DB22`でレポートされるリストアに必要なログは"S0000004.LOG"となる。

```bash
# データ更新
db2 "CONNECT TO DB22"
db2 "INSERT INTO Hogetbl VALUES(3, 'hogehogehoge')"

# テーブルスペース擬似障害
rm -rf /db/db22/tbsp[12]/*

# DBが異常終了したので再起動
db2start

# DBリストア
db2 "DEACTIVATE DB DB22"
db2 "RESTORE DB DB22 FROM /db/db22/bkup TAKEN AT 20181031225356"
db2 "GET DB CFG FOR DB22" | grep "First active" # First active log fileはS0000004.LOGに戻った
db2 "ROLLFORWARD DB DB22 TO END OF LOGS"
db2 "GET DB CFG FOR DB22" | grep "First active" # First active log fileはS0000005.LOGに進んだ
db2 "ROLLFORWARD DB DB22 STOP"
db2 "GET DB CFG FOR DB22" | grep "First active" # First active log fileはS0000006.LOGに進んだ

# 復旧確認
db2 "ACTIVATE DB DB22"
db2 "CONNECT TO DB22"
db2 "SELECT * FROM Hogetbl"
```

先ほど追加したid=3のデータまで戻った。

オンラインバックアップにログも含めてしまえば（`INCLUDE LOGS`でこれがデフォルト動作）、リストア時にログを切り出し（`LOGS LOGTARGET ${overflowLogPath}`）、ロールフォワードさせる（`OVERFLOW LOG(${overflowLogPath})`）ことができて、とてもシンプルになる。

いずれにせよ、RAID10だったりRAID10でさらにLVMミラーリングしたり（本当にそういうケースがありました）、RAID6あたりだったとしても、おおよそ十分なディスクの冗長化があたりまえな昨今において、いきなりデータディスクが飛ぶなどということは、基幹系のシステムではほとんど考えられないくらいになったものの、致命的に壊れても戻せるという安心感は大切。

蛇足で、少なくとも開発環境でのテストでは、リストア完了後に基本的な操作（SELECT,INSERT,UPDATE）ができることを確認すべき。
以前経験したケースでは、RDBMSの機能を使用して静止化＆バックアップしたものをリストアしたら、静止化状態で復旧してきて、それに気がつかなかったということがあったので、、、