TiDB 検証ライフ(7-ディスク障害の検証2)

すっかりお正月ムードに突入しましたね、皆様いかがお過ごしでしょうか。
前回残してしまった、ディスク障害の検証を続けます。

##　ご報告まで、TiDBコミュニティに2点質問していました

###　質問１ INSERT文を実行した場合、データをメモリに保持せず即座にSSTファイルに書き込む方法はありますか。

回答は、NOでした。
但し、TiDB Lightningというツールが存在し、SQLファイルを直接SSTファイルに変換し、TiKVに投入できるとか。

###　質問2 SSTファイルが破損した場合、自動的にスナップショットなどから復旧する機能はありますか。

回答は、NOでした。
が、破損したSSTファイル情報を出力し(コマンドがあるみたいです)、強制的に破損SSTファイルをオフラインにするか、IGNOREフラグを立ててくださいとのことでした。
ちなみに、破損したSSTファイルをそのまま放置したら、TiKVプロセスがクラッシュする可能性があるようです。
破損ファイルに早く気付き、取り除いた方がよさそうです。

## SSTファイルを壊し、破損したSSTを見つけてくれるかやってみます

tikv-ctl bad-sstsコマンドが使えるようですが、
必ずTiKVインスタンスを止めてから実行してくださいとのことです。

###　TiKVノードにアクセスし、tikv-ctlコマンドを使ってみます

二つのモードが使えるようです。

####　リモートモード

ネットワーク経由の接続でして、まずはkubectl port-forwardコマンドを用いてローカルからTiKVノードへの接続を確立しておく必要があります。

#####　TiKV Pod名を確認します、basic-tikv-0になっています

```
$ kubectl get pods -n tidb-cluster
NAME                              READY   STATUS    RESTARTS   AGE
basic-discovery-f699b74cd-mpgw4   1/1     Running   1          22h
basic-monitor-0                   3/3     Running   3          22h
basic-pd-0                        1/1     Running   1          22h
basic-tidb-0                      2/2     Running   2          22h
basic-tikv-0                      1/1     Running   1          22h
```

#####　ポートフォワードを設定します

```
$ kubectl port-forward -n tidb-cluster basic-tikv-0 20160:20160 &>/tmp/portforward-tikv.log &
```

#####　ローカルからポート番号20160を経由し、TiKVノードにアクセスし、tikv-ctlコマンド実行できます。

```
$ tikv-ctl --host 127.0.0.1:20160 ${subcommands}
```

####　ローカルモード

流れとしては、診断モードに入り、TiKVインスタンスの自動再起動をオフに変更、TiKVプロセスを停止、対象となるTiKV Podにログインしたら、tikv-ctlコマンドを使って操作可能です。

1.　診断モードに切り替え

```
$　kubectl annotate pod basic-tikv-0 -n tidb-cluster runmode=debug
pod/basic-tikv-0 annotated
```

2.　TiKV processを停止

```
$　kubectl exec basic-tikv-0 -n tidb-cluster -c tikv -- kill -s TERM 1
```

3.　TiKVコンテナが再起動できたらログイン

```
$　kubectl exec -it basic-tikv-0 -n tidb-cluster -- sh
```

4.　tikv-ctlを実行

TiKVコンテナ内でデフォルトのdbパスは`/var/lib/tikv/db`のようです。

```
$　./tikv-ctl --data-dir /var/lib/tikv size -r 2
```

今回は、ローカルモードを使用します。


###　SSTファイルの先頭部を覗いてみます

####　SSTファイルが格納されてディレクトリに移動します。

```
/ # cd /var/lib/tikv/db
var/lib/tikv/db # ls -l *.sst
-rw-r--r--    1 root     root        568123 Dec 21 23:49 000012.sst
-rw-r--r--    1 root     root        150661 Dec 21 23:49 000015.sst
-rw-r--r--    1 root     root          1220 Dec 22 01:55 000022.sst
-rw-r--r--    1 root     root         25141 Dec 22 01:55 000023.sst
-rw-r--r--    1 root     root          3377 Dec 22 01:55 000028.sst
```

####　odコマンドで、000012.sstの先頭200バイトを覗いてみます。

```
/var/lib/tikv/db # od -N200 -c 000012.sst
0000000  \0  \n  \f 001 001 001 001  \0  \0  \0  \0  \0  \0  \b 252 206
0000020 345 276 224 357 314 340   a 020 001 001  \t  \0 002  \0 005  \0
0000040  \0  \0  \0  \0  \0  \0   > 364  \a   z   m   D   B   :   1  \0
0000060  \0  \0 377  \0 373  \0  \0  \0  \0  \0  \0 377  \0   h   T   a
0000100   b   l   e   : 377   5   3 377  \0  \0  \0  \0  \0 377  \0  \0
0000120  \0 367  \0  \0  \0  \0 373 372  \b 222 337 324 357 377 376 001
0000140   j 030  \0  \0  \0  \0  \0   {   "   i   d   "   :   5   3   ,
0000160   "   n   a   m   e   "   :   {   "   O   "   :   "   t   e   s
0000200   t   "   ,   "   L   "   :   "   t   e   s   t   "   }   ,   "
0000220   c   h   a   r   s   e   t   "   :   "   u   t   f   8   m   b
0000240   4   "   ,   "   c   o   l   l   a   t   e   "   :   "   u   t
0000260   f   8   m   b   4   _   b   i   n   "   ,   "   c   o   l   s
0000300   "   :   [   {   "   i   d   "
0000310
```

4行目の末尾ぐらいに、hTableの文字列が見え、そのあと、

```
"id":53,
"name":{"O":"test",...
```

のようにテーブルのスキーマ定義らしき内容が。
id 53?なんだろう。

####　別端末から、TiDBに接続しtestテーブルのスキーマ定義を確認

TiDBサービス名を確認します。

```
$ kubectl get svc -n tidb-cluster
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)               AGE
basic-discovery          ClusterIP   10.96.222.171   <none>        10261/TCP,10262/TCP   26h
basic-grafana            ClusterIP   10.96.87.28     <none>        3000/TCP              26h
basic-monitor-reloader   ClusterIP   10.96.209.73    <none>        9089/TCP              26h
basic-pd                 ClusterIP   10.96.149.28    <none>        2379/TCP              26h
basic-pd-peer            ClusterIP   None            <none>        2380/TCP              26h
basic-prometheus         ClusterIP   10.96.205.157   <none>        9090/TCP              26h
basic-tidb               ClusterIP   10.96.162.173   <none>        4000/TCP,10080/TCP    26h
basic-tidb-peer          ClusterIP   None            <none>        10080/TCP             26h
basic-tikv-peer          ClusterIP   None            <none>        20160/TCP             26h
```

ローカルからTiDBへ接続するため、ポートフォワードを設定し、mysqlコマンドで接続します。

```
$ kubectl port-forward -n tidb-cluster svc/basic-tidb 4000 > pf4000.out &
$ mysql -h 127.0.0.1 -P 4000 -u root
```

testテーブルのスキーマ定義を確認すると、tidb_table_idが53でした。

```
mysql> use information_schema;
Database changed

mysql> select tidb_table_id,table_name from tables where table_name='test';
+---------------+------------+
| tidb_table_id | table_name |
+---------------+------------+
|            53 | test       |
+---------------+------------+
1 row in set (0.04 sec)
```

###　SSTファイルを壊します

TiKVノードにログインしていた端末に戻ります。

####　ddコマンドで000012.sstの先頭部分を0で上書きします

```
/var/lib/tikv/db #　dd if=/dev/zero of=/var/lib/tikv/db/000012.sst bs=512 count=1
```

###　破損されたSSTファイルを検知できるか

tikv-ctl bad-sstsコマンドを以下のパラメータを指定し、実行します。
--dbパラメータ、dbパスを指定
--pdパラメータ、PDサービスのCLUSTER-IPを指定(`kubectl get svc -n tidb-cluster`コマンドで確認したbasic-pdサービス)。

```
/var/lib/tikv/db # /tikv-ctl bad-ssts --db /var/lib/tikv/db --pd 10.96.149.28:2379

... ...

--------------------------------------------------------
corruption info:
/var/lib/tikv/db/000012.sst: Corruption: Bad table magic number: expected 9863518390377041911, found 0 in /var/lib/tikv/db/000012.sst

sst meta:
12:568123[1 .. 6281]['0101' seq:1, type:1 .. '7A7480000000000000FF0F5F728000000000FF0000870000000000FAFA0895315D0FFFFA' seq:2394, type:1] at level 0 for Column family "default"  (ID 0)
it isn't easy to handle local data, start key:0101

overlap region:
RegionInfo { region: id: 2001 end_key: 7480000000000000FF0500000000000000F8 region_epoch { conf_ver: 1 version: 2 } peers { id: 2002 store_id: 1 }, leader: Some(id: 2002 store_id: 1) }
RegionInfo { region: id: 2003 start_key: 7480000000000000FF0500000000000000F8 end_key: 7480000000000000FF0700000000000000F8 region_epoch { conf_ver: 1 version: 3 } peers { id: 2004 store_id: 1 }, leader: Some(id: 2004 store_id: 1) }
RegionInfo { region: id: 2005 start_key: 7480000000000000FF0700000000000000F8 end_key: 7480000000000000FF0900000000000000F8 region_epoch { conf_ver: 1 version: 4 } peers { id: 2006 store_id: 1 }, leader: Some(id: 2006 store_id: 1) }
RegionInfo { region: id: 2007 start_key: 7480000000000000FF0900000000000000F8 end_key: 7480000000000000FF0B00000000000000F8 region_epoch { conf_ver: 1 version: 5 } peers { id: 2008 store_id: 1 }, leader: Some(id: 2008 store_id: 1) }
RegionInfo { region: id: 2009 start_key: 7480000000000000FF0B00000000000000F8 end_key: 7480000000000000FF0D00000000000000F8 region_epoch { conf_ver: 1 version: 6 } peers { id: 2010 store_id: 1 }, leader: Some(id: 2010 store_id: 1) }
RegionInfo { region: id: 2011 start_key: 7480000000000000FF0D00000000000000F8 end_key: 7480000000000000FF0F00000000000000F8 region_epoch { conf_ver: 1 version: 7 } peers { id: 2012 store_id: 1 }, leader: Some(id: 2012 store_id: 1) }
RegionInfo { region: id: 2013 start_key: 7480000000000000FF0F00000000000000F8 end_key: 7480000000000000FF1100000000000000F8 region_epoch { conf_ver: 1 version: 8 } peers { id: 2014 store_id: 1 }, leader: Some(id: 2014 store_id: 1) }

suggested operations:
tikv-ctl ldb --db=/var/lib/tikv/db unsafe_remove_sst_file "/var/lib/tikv/db/000012.sst"
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2001 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2003 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2005 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2007 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2009 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2011 --pd <endpoint>
tikv-ctl --db=/var/lib/tikv/db tombstone -r 2013 --pd <endpoint>
--------------------------------------------------------
corruption analysis has completed

```

破損した000012.sstが見事に検知されたようです。
破損原因と対処法まで親切にコマンドベースで提示してくれています。

## 終わりに

ディスク障害によりSSTファイルが破損した、といったシナリオで検証してみました。
自動復旧まではいかないものの、早いうちに破損ファイルを検知、対策を打つことはできそうです。

次回は、個人的に一番やってみたかった、TiDBの分散トランザクション検証を予定しております。
お楽しみに。