# TiDBでゼロダウンタイムを満喫する


### 概要
+ これらの演習では、計画されたスケールインおよびスケールアウト操作、または計画外のシステム障害であっても、TiDBのゼロダウンタイム機能について実践的な経験を積むことができます。
+ 演習 1では、データベース SQL レイヤー (TiDB サーバー) インスタンスが障害を起こした場合でも、お客様のビジネスは稼働し続けることを学習します。
+ 演習 2では、データベースストレージレイヤー（TiKV サーバー）インスタンスの障害が発生しても、お客様のビジネスは引き続き運用可能なことを学習します。
+ 演習 3では、データベースのメタデータレイヤー（Placement Driver サーバー）インスタンスに障害が発生しても、ビジネスに影響がないことを学習します。


### 注意
+ いくつかのステップでは、2つの異なるターミナルウィンドウでコマンドを入力する必要があります。2つのターミナルを起動し、演習の間ずっと開いておくと便利でしょう。
+ この演習で利用する、`IP`、`port`、`username`、`password`、`directory`などは、あなたの環境と異なる場合があります。
+ ターミナルウィンドウの`$`とはOSプロンプトです。
+ ターミナルウィンドウでの "`tidb>`" または "`mysql>`" は、SQLコマンドプロンプトです。
+ これらの演習は、ノートパソコンなどの単一のマシン上で実行することができます。


### 前提条件
+ macOSまたはLinuxを使用していること。
+ [lab repository](https://github.com/pingcap/tidb-course-201-lab.git)をクローン済みであること。
+ 演習1を完了していること。
+ [JDK 8 以降](https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html)がインストールされていること。


## 演習 1：SQL レイヤーのインスタンス障害切り替え例


  <img src="./diagram/2011E021_aa_002_20230409.png" width="50%" align="top"/>


### 所要時間
+ この演習は約15分程度かかります。


### タスク
1. `test`スキーマ内にテーブルを作成します。
2. 作成されたテーブルに行を挿入するために、Javaのワークロードを開始します。
3. SQLレイヤーでのスケールインとスケールアウトを実施します。
4. 意図的にTiDB Playgroundクラスタ内のSQLレイヤー（TiDBサーバー）インスタンスを終了します。
5. Javaのワークロードが影響を受けていないことを確認します。
6. TiDB Playgroundクラスタに正常なSQLレイヤーインスタンスを追加します（スケールアウト）。


### 手順
1. 演習 1で作成した`demo` PlaygroundクラスタのTiDBサーバーに`root`ユーザでログインし、リージョンにおける最大レプリカ数を3に設定します。
   ```
   $ cd tidb-course-201-lab/scripts/
   $ ./connect-4000.sh
   ```


   ```sql
   SET CONFIG PD `replication.max-replicas`=3;
   SELECT SLEEP(1);
   SHOW CONFIG WHERE type='pd' AND name='replication.max-replicas';
   ```
   ```
   tidb:4000> SET CONFIG PD `replication.max-replicas`=3;
   Query OK, 0 rows affected (0.47 sec)


   tidb:4000> SELECT SLEEP(1);
   +----------+
   | SLEEP(1) |
   +----------+
   |        0 |
   +----------+
   1 row in set (1.01 sec)


   tidb:4000> SHOW CONFIG WHERE type='pd' AND name='replication.max-replicas';
   +------+----------------+--------------------------+-------+
   | Type | Instance       | Name                     | Value |
   +------+----------------+--------------------------+-------+
   | pd   | 127.0.0.1:5380 | replication.max-replicas | 3     |
   | pd   | 127.0.0.1:5379 | replication.max-replicas | 3     |
   | pd   | 127.0.0.1:5381 | replication.max-replicas | 3     |
   +------+----------------+--------------------------+-------+
   3 rows in set (0.02 sec)
   ```


2. TiDB Playgroundクラスタの状態を確認するには、新しいターミナルを開き、スクリプト`playground-check.sh`を実行します。 2つのTiDBサーバーインスタンスの状態に注意してください。
   ```
   $ ./playground-check.sh
   ...
   Pid   Role     Uptime
   ---   ----     ------
   ...
   2760  tidb     33m21.006866672s
   2761  tidb     33m20.948299789s
   ...
   ```


3. `02-demo-jdbc-endless-insert-dummy.sh`を実行してワークロードを開始します。このスクリプトは、架空のクリックストリームイベントをシミュレートするダミーのJavaプログラムを呼び出します。プログラムには、`worker1`と`worker2`という2つの並行スレッドがあり、それぞれがTiDB Playgroundクラスタ内の2つのTiDBサーバーインスタンスにラウンドロビン方式で接続できます。このJavaプログラム用のテーブルが作成されていないため、（ポート4000とポート4001の）どちらのTiDBサーバーでもタスクを正常に実行することはできないことに注意してください。
 
   スクリプトを確認します。
   ```
   $ cat 02-demo-jdbc-endless-insert-dummy.sh
   #!/bin/bash


   # Run ./02-demo-jdbc-endless-insert-dummy.sh


   rm -f DemoJdbcEndlessInsertDummyV3.class
   javac -cp .:misc/mysql-connector-java-5.1.36-bin.jar DemoJdbcEndlessInsertDummyV3.java
   sleep 1
   java -cp .:misc/mysql-connector-java-5.1.36-bin.jar DemoJdbcEndlessInsertDummyV3 $*
   ```


   ワークロードスクリプトを実行し、演習の残りのステップのためにこのターミナルウィンドウを開いたままにしておいてください。
   ```
   $ ./02-demo-jdbc-endless-insert-dummy.sh
   Error - Worker 2 - TiDB Server (port:4001) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:27 CST 2023
   Error - Worker 1 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:27 CST 2023
   Error - Worker 1 - TiDB Server (port:4001) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:27 CST 2023
   Error - Worker 2 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:27 CST 2023
   Error - Worker 1 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:27 CST 2023
   Error - Worker 2 - TiDB Server (port:4001) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:28 CST 2023
   Error - Worker 2 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:43:28 CST 2023
   ...
   ```


4. MySQL CLIプログラムに戻り、`test`スキーマの下に`dummy`という名前のテーブルを作成します。ちなみに、TiDBは`JSON`データ型もサポートしていることがわかります。
   ```sql
   DROP TABLE IF EXISTS test.dummy;
   CREATE TABLE test.dummy (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(80), event JSON);
   ```
   ```
   tidb:4000> DROP TABLE IF EXISTS test.dummy;
   Query OK, 0 rows affected, 1 warning (0.00 sec)


   tidb:4000> CREATE TABLE test.dummy (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(80), event JSON);
   Query OK, 0 rows affected (0.59 sec)
   ```


5. Javaワークロードターミナルウィンドウ上でプログラムが正常に機能を開始したことを確認します。サンプルJavaプログラムでは、短い接続がデモ目的で使用されていますが、JDBCベースのアプリケーションでは一般的に推奨されない手法であることに注意してください。
   ```
   Error - Worker 2 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:52:17 CST 2023
   Error - Worker 2 - TiDB Server (port:4001) Table 'test.dummy' doesn't exist at Sat Apr 15 20:52:17 CST 2023
   Error - Worker 1 - TiDB Server (port:4000) Table 'test.dummy' doesn't exist at Sat Apr 15 20:52:17 CST 2023
   Error - Worker 1 - TiDB Server (port:4001) Table 'test.dummy' doesn't exist at Sat Apr 15 20:52:17 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:18 CST 2023
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:18 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 20:52:18 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 20:52:19 CST 2023
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:19 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:19 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 20:52:19 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 20:52:20 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:20 CST 2023
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 20:52:20 CST 2023
   ```


6. MySQL CLIプログラムに戻り、`test.dummy`テーブルの行数が増えていることを確認します。
   ```sql
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   SELECT SLEEP(1);
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   ```
   ```
   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   30676 |          683 |
   | worker2 |   30677 |          672 |
   +---------+---------+--------------+
   2 rows in set (0.01 sec)


   tidb:4000> SELECT SLEEP(1);
   +----------+
   | SLEEP(1) |
   +----------+
   |        0 |
   +----------+
   1 row in set (1.00 sec)


   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   30679 |          687 |
   | worker2 |   30680 |          674 |
   +---------+---------+--------------+
   2 rows in set (0.01 sec)
   ```


7. 新しいターミナルウィンドウを開き、スクリプト`02-1-planned-scale-in-tidb-server.sh`を実行して、SQLレイヤーをスケールインし、TiDBサーバーインスタンスを1つ削除します。もし2台のサーバーを管理する必要性がないと思った時、1つのTiDBサーバーですべてのワークロードを効率的に管理できます。
 
   計画済みのスケールインスクリプトをレビューします。
   ```
   $ cd tidb-courses-201-lab/scripts/


   $ cat 02-1-planned-scale-in-tidb-server.sh
   #!/bin/bash


   # Scale-in the first TiDB server (its port should be 4000)


   TIDB_SERVER_1_PID=`~/.tiup/bin/tiup playground display 2>/dev/null | grep -i tidb | sort -g | head -n 1 | awk -F" " '{print $1}'`
   ~/.tiup/bin/tiup playground scale-in --pid ${TIDB_SERVER_1_PID}


   ~/.tiup/bin/tiup playground display
   ```


   計画済みのスケールインスクリプトを実行します。
   ```
   $ ./02-1-planned-scale-in-tidb-server.sh
   ...
   Pid   Role     Uptime
   ---   ----     ------
   ...
   2761  tidb     1h29m16.989845496s
   ...
   ```


8. Javaワークロードが実行されているターミナルウィンドウを観察すると、`worker1`と`worker2`が現在`TiDB Server (port:4001)`にあることがわかります。


   ```
   ...
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:49 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:50 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:51 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:06:52 CST 2023
   ...
   ```


9. `test.dummy` テーブルの行数がまだ増加していること、ワークロードがまだ実行されていることを確認するために、`port:4001` を介して残りの TiDB サーバーインスタンスに接続します。興味深い観察結果として、2つのクエリ間で `MAX(id)` カラムの戻り値が同じである可能性があること、一方で `COUNT(event)` の値が増加していることです。ただし、どんな状況でも、演習の後のステップには影響しません。TiDB の分散環境における `AUTO_INCREMENT` の動作に関する情報については、無料ワークショップの[TiDB基本ワークショップ](https://pingcap.co.jp/education)に参加して詳細を学びましょう。


   ```
   $ ./connect-4001.sh
   ```
   ```sql
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   SELECT SLEEP(1);
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   ```
   ```
   tidb:4001> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   33009 |         2359 |
   | worker2 |   33010 |         2352 |
   +---------+---------+--------------+
   2 rows in set (0.05 sec)


   tidb:4001> SELECT SLEEP(1);
   +----------+
   | SLEEP(1) |
   +----------+
   |        0 |
   +----------+
   1 row in set (1.00 sec)


   tidb:4001> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   33014 |         2362 |
   | worker2 |   33013 |         2353 |
   +---------+---------+--------------+
   2 rows in set (0.01 sec)
   ```


10. 現在どんな状況でしょうか。潜在的なリスクはありますか。ワークロードが増加した場合や、単一の TiDB サーバーでは高可用性の要件を満たすことができない場合、単一のサーバーに依存してワークロードを処理し、想定されるような高可用性の SLA を満たすには不十分です。この課題に対処するために、クラスタに追加の TiDB サーバーを追加する必要があります。実際に実施する場合、必要な TiDB サーバーの数は、システムの SQL ワークロードに基づいて決定する必要があります。

    スケールアウトスクリプトをレビューします。
    ```
    $ cat ./02-2-planned-scale-out-tidb-server.sh
    #!/bin/bash


    # Scale-out one TiDB server


    ~/.tiup/bin/tiup playground scale-out --db 1


    ~/.tiup/bin/tiup playground display
    ```


    TiDBサーバーを1つ追加し、SQLレイヤーをスケールアウトするために、スクリプトを実行します。
    ```
    $ ./02-2-planned-scale-out-tidb-server.sh
    ...
    Pid   Role     Uptime
    ---   ----     ------
    ...
    2761  tidb     1h43m49.828035701s
    7192  tidb     6.022653957s
    ...
    ```


11. Javaワークロードを実行するターミナルウィンドウを観察すると、`worker1`と`worker2`が再び`TiDB Server (port:4000)`と`TiDB Server (port:4001)`を使用していることがわかります。


    ```
    ...
    Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:25 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:26 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:26 CST 2023
    Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:27 CST 2023
    Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:27 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:27 CST 2023
    Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:27 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:27 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:28 CST 2023
    Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:28 CST 2023
    Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 21:46:28 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:46:29 CST 2023
    ```


12. これまでに、SQLレイヤーの計画的なスケールインとスケールアウトが行われてきました。`02-3-unplanned-destroy-tidb-server.sh`スクリプトを実行して、予期しないTiDBサーバーシステムの障害をシミュレートします。


    障害を発生させるスクリプトをレビューします。
    ```
    $ cat 02-3-unplanned-destroy-tidb-server.sh
    #!/bin/bash


    # Kill one TiDB server instance.


    TIDB_SERVER_1_PID=`~/.tiup/bin/tiup playground display 2>/dev/null | grep -i tidb | sort -g -r | head -n 1 | awk -F" " '{print $1}'`
    kill -9 ${TIDB_SERVER_1_PID}


    ~/.tiup/bin/tiup playground display
    ```


    TiDBサーバーのひとつのインスタンスを強制的に終了させるために、スクリプトを実行します。
    ```
    $ ./02-3-unplanned-destroy-tidb-server.sh
    Pid   Role     Uptime
    ---   ----     ------
    ...
    2761  tidb     2h13m30.567709922s
    7192  tidb     signal: killed
    ```


13. `worker1`と`worker2`がシングルTiDBサーバー上で動作していることを再確認します。`test.dummy`テーブルの行数がまだ増加しており、ワークロードは引き続き実行されています。


    Javaワークロードのターミナルウィンドウを観察します。
    ```
    ...
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:53:57 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:53:58 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:53:58 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:53:58 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 21:53:58 CST 2023
    ```




    ```sql
    SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    SELECT SLEEP(1);
    SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    ```
    ```
    tidb:4001> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    +---------+---------+--------------+
    | name    | MAX(id) | COUNT(event) |
    +---------+---------+--------------+
    | worker1 |   63431 |         7351 |
    | worker2 |   63432 |         7338 |
    +---------+---------+--------------+
    2 rows in set (0.05 sec)


    tidb:4001> SELECT SLEEP(1);
    +----------+
    | SLEEP(1) |
    +----------+
    |        0 |
    +----------+
    1 row in set (1.00 sec)


    tidb:4001> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    +---------+---------+--------------+
    | name    | MAX(id) | COUNT(event) |
    +---------+---------+--------------+
    | worker1 |   63431 |         7355 |
    | worker2 |   63432 |         7341 |
    +---------+---------+--------------+
    2 rows in set (0.03 sec)
    ```


14. スクリプト`02-4-recover-capacity-tidb-server.sh`を実行し、ダウンしたTiDBサーバーをクリーンアップし、クラスタに1つのTiDBサーバーを追加し、SQLレイヤーのTiDBサーバーキャパシティを2に回復します。


    スクリプトを確認します。
    ```
    $ cat 02-4-recover-capacity-tidb-server.sh
    #!/bin/bash


    # Clean killed TiDB servers, should be only 1 TiDB server need to be cleaned as per the exercise workflow. However, this routine will clean all killed TiDB servers.
    for PID in `~/.tiup/bin/tiup playground display 2>/dev/null | egrep -i '(killed|exit)' | grep -i tidb | sort -g -r | awk -F" " '{print $1}'`; do
    ~/.tiup/bin/tiup playground scale-in --pid ${PID}
    done;


    sleep 3;


    # Scale-out 1 TiDB server
    ~/.tiup/bin/tiup playground scale-out --db 1


    ~/.tiup/bin/tiup playground display
    ```


    スクリプトを実行します。
    ```
    $ ./02-4-recover-capacity-tidb-server.sh
    ...
    To connect new added TiDB: mysql --comments --host 127.0.0.1 --port 4000 -u root -p (no password)
    ...
    Pid   Role     Uptime
    ---   ----     ------
    ...
    2761  tidb     2h29m58.446768313s
    9234  tidb     6.138662531s
    ...
    ```


15. `worker1`と`worker2`が再び2つのTiDBサーバーで動作していることを確認します。また、`test.dummy`テーブルの行数がまだ増加しており、ワークロードが実行されていることを確認します。


    ```
    ...
    Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:30:11 CST 2023
    Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:30:11 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:30:11 CST 2023
    Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:30:11 CST 2023
    Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:30:12 CST 2023
    Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:30:12 CST 2023
    ```


    ```sql
    SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    SELECT SLEEP(1);
    SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    ```
    ```
    tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    +---------+---------+--------------+
    | name    | MAX(id) | COUNT(event) |
    +---------+---------+--------------+
    | worker1 |   90482 |         9145 |
    | worker2 |   90481 |         9133 |
    +---------+---------+--------------+
    2 rows in set (0.02 sec)


    tidb:4000> SELECT SLEEP(1);
    +----------+
    | SLEEP(1) |
    +----------+
    |        0 |
    +----------+
    1 row in set (1.00 sec)


    tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
    +---------+---------+--------------+
    | name    | MAX(id) | COUNT(event) |
    +---------+---------+--------------+
    | worker1 |   90484 |         9146 |
    | worker2 |   90483 |         9135 |
    +---------+---------+--------------+
    2 rows in set (0.02 sec)
    ```


16. 再接続ロジックが実装されているため、Javaのワークロードには影響がありません。これまでに、「計画済み」のSQLレイヤースケールインに続いてスケールアウト、また「計画外」のSQLレイヤーのインスタンス障害（ハードスケールイン）に続いてスケールアウトを発生させました。TiDBサーバーは、通常ロードバランサーの背後にデプロイされます。これにより、クライアントが各TiDBサーバーの個別の接続詳細を認識する必要がなくなります。さらに、PingCAPは[TiProxy](https://github.com/pingcap/TiProxy)を提供し、接続の永続性とサービスの検出を確実にし、TiDBサーバーの計画外の停止および計画済みのスケールインをクライアントが切断することなくシームレスに処理できます。さらに、ロードバランサーとTiProxyの両方が[TiDB Cloud Dedicated](https://tidbcloud.com/free-trial/?utm_source=edu&utm_medium=referral&utm_campaign=201.1.E2)では事前構成されています。次の[link](https://pingcap.co.jp/contact-us/?utm_source=edu&utm_medium=referral&utm_campaign=201.1.E2)から、PingCAPプロフェッショナルによる詳細な情報を入手できます。




## 演習 2: ストレージレイヤーのインスタンス障害切り替え例


  <img src="./diagram/2011E022_aa_003_20230409.png" width="50%" align="top"/>



### 所要時間
+ この演習は約10分程度かかります


### タスク
1. TiKVサーバーを強制的に終了します。
2. Javaワークロードが影響を受けないことを確認します。


### 手順
1. `playground-check.sh`スクリプトを実行して、TiDB Playgroundクラスタの状態を確認します。TiKVサーバーは3つあるはずです。
   ```
   $ ./playground-check.sh
   ...
   Pid   Role     Uptime
   ---   ----     ------
   2754  pd       2h47m33.055713498s
   2755  pd       2h47m32.998182468s
   2756  pd       2h47m32.932384756s
   2757  tikv     2h47m32.863143492s
   2758  tikv     2h47m32.79121259s
   2759  tikv     2h47m32.731007068s
   2761  tidb     2h47m32.607392002s
   9234  tidb     17m40.299286264s
   2794  tiflash  2h46m35.83098919s
   ```


2. TiDB内のストレージレイヤー（TiKVサーバー）は、SQLレイヤーと同様に、スケールインとスケールアウトの操作を実行できるようになっています。また、データベースクライアントアプリケーションのストレージレイヤーにおける水平スケールインとシステムフェールオーバーの透過性は、SQLレイヤーによって可能になっています。TiKVノードの故障をシミュレートするには、単純に`02-6-unplanned-destroy-tikv-server.sh`スクリプトを実行します。


   次のスクリプトを実行し、1つのTiKVサーバーが強制的に終了されたことに注意してください。
   ```
   $ ./02-6-unplanned-destroy-tikv-server.sh
   ...
   Pid   Role     Uptime
   ---   ----     ------
   ...
   2757  tikv     signal: killed
   2758  tikv     2h54m57.742433044s
   2759  tikv     2h54m57.682216051s
   ...
   ```


3. サンプルのワークロードに影響がないことを観察します。
 
   `worker1`と`worker2`は両方のTiDBサーバーで作業しています。もし偶然にも、今挿入しているデータリージョンのRaft LeaderであるTiKVサーバーが終了した場合、1桁秒の一時停止が発生する可能性があります。
   ```
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:51:38 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:51:38 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:51:38 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:51:39 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:51:39 CST 2023
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:51:39 CST 2023
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:51:40 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 22:51:40 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 22:51:40 CST 2023
   ```


   テーブル`test.dummy`の行が生成されていることを確認します。`connect-4000.sh`または`connect-4001.sh`のどちらかを使用して接続を確立できます-両方のオプションが有効です。
   ```
   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   93341 |        12047 |
   | worker2 |   93342 |        11950 |
   +---------+---------+--------------+
   2 rows in set (0.12 sec)


   tidb:4000> SELECT SLEEP(1);
   +----------+
   | SLEEP(1) |
   +----------+
   |        0 |
   +----------+
   1 row in set (1.00 sec)


   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   93345 |        12050 |
   | worker2 |   93344 |        11952 |
   +---------+---------+--------------+
   2 rows in set (0.03 sec)
   ```


4. 現在の状況を評価します。2つのTiKVサーバーに3つのレプリカがあります。潜在的なリスクはありますか。ビジネスは中断されていませんが、`replication.max-replicas`が3であるため、TiDB Playgroundクラスタは1つのTiKVサーバーを失うとデータが損失してしまいます。このため、ストレージレイヤーに新しいメンバーを追加し、少なくとも3つのメンバーとすることが必要です。ただし、ストレージレイヤーの管理を包括的に説明することは本コースの範囲を超えますし、リアルなTiDBクラスタが必要であり、追加のスキルも必要です。そのため、TiDBクラスタを管理するための高度なスキルと知識を習得するためには、講師主導のトレーニング「TiDBの運用」に参加することをお勧めします。また、別の方法として、フルマネージドのTiDBサービスである[TiDB Cloud ServerlessまたはDedicated](https://tidbcloud.com/free-trial/?utm_source=edu&utm_medium=referral&utm_campaign=201.1.E2)使用する方法があります。


5. `02-6-discard-failed-tikv-server.sh`を実行して、失敗したTiKVストアを破棄します。
   ```
   $ 02-6-discard-failed-tikv-server.sh
   ...
   tikv will be stop when tombstone
   ```


6. これまでのところ、Javaワークロードに影響やデータ損失はありませんでした。私たちは「非計画的な」TiKVインスタンスの障害（ハードスケールイン）を経験しました。プロダクション環境ではPlaygroundを利用しないことについて、再度注意する必要があります。




## 演習 3：メタデータレイヤーインスタンス障害切り替え例


  <img src="./diagram/2011E023_aa_003_20230409.png" width="50%" align="top"/>



### 所要時間
+ この演習は約10分程度かかります


### タスク
1. システム障害をシミュレートするため、Placement Driverの1つを強制的に終了します。
2. システム障害が Java ワークロードに対して透過的であることを確認します。
3. Placement Driverのインスタンス数を3に復元するには、失敗したインスタンスに代わる新しいインスタンスを追加します。


### 手順
1. Placement Driver インスタンスの障害をシミュレートするには、`02-7-unplanned-destroy-pd-server.sh`スクリプトを実行して、アクティブなPlacement Driver インスタンスを3つから2つに減らすことができます。前回の演習 2-2では、1つのTiKVサーバーをダウンさせたままでした。追加でPlacement Driver サーバーを停止させることで、同時に1つのPlacement Driver サーバーと1つのTiKVサーバーが失われる、可用性ゾーン（データセンター）レベルの障害をシミュレートすることができます。幸いなことに、このシナリオでも、各レイヤーの過半数のコンポーネントが操作可能である限り、TiDBはビジネスをシームレスにサービスし続けることができます。障害があった場合に最大で数秒間（障害がLeadersに影響を与える場合）一時停止することがあるかもしれませんが、クラウドプロバイダーは復旧に数分または数時間かかる場合があります。

   ```
   $ ./02-7-unplanned-destroy-pd-server.sh
   ...
   Pid   Role     Uptime
   ---   ----     ------
   2754  pd       signal: killed
   2755  pd       3h25m38.538802911s
   2756  pd       3h25m38.472993959s
   2757  tikv     signal: killed
   2758  tikv     3h25m38.331398029s
   2759  tikv     3h25m38.271188632s
   2761  tidb     3h25m38.147573414s
   9234  tidb     55m45.839467817s
   2794  tiflash  3h24m41.37116303s
   ```


2. Javaワークロードが影響を受けないことを確認します。前のステップでLeader Placement Driverを正常終了できた場合、ワークロードには数秒間の僅かな中断が発生し、フェイルオーバーが開始されたことを示します。サンプルワークロードには、多数の小規模なトランザクションの高速な実行が含まれており、それらは多数のTSOリクエストをPD Leaderに発行します。[DBAのためのTiDB基礎](https://pingcap.co.jp/education/)という無料のコースに登録することで、 Placement Driver、TiKVサーバー、TiDBサーバー、そしてTSOなどの主要なコンポーネントに関する包括的な知識を習得することができます。このコースでは、これらについて詳細な解説が提供されます。


   テーブル`test.dummy`の行が生成されていることを確認します。接続は、`connect-4000.sh`または`connect-4001.sh`のいずれかを使用して確立できます - 両方のオプションが有効です。
   ```sql
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   SELECT SLEEP(1);
   SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   ```
   ```
   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   97242 |        15948 |
   | worker2 |   97241 |        15849 |
   +---------+---------+--------------+
   2 rows in set (0.11 sec)


   tidb:4000> SELECT SLEEP(1);
   +----------+
   | SLEEP(1) |
   +----------+
   |        0 |
   +----------+
   1 row in set (1.00 sec)


   tidb:4000> SELECT name, MAX(id), COUNT(event) FROM test.dummy GROUP BY name ORDER BY name;
   +---------+---------+--------------+
   | name    | MAX(id) | COUNT(event) |
   +---------+---------+--------------+
   | worker1 |   97243 |        15951 |
   | worker2 |   97244 |        15850 |
   +---------+---------+--------------+
   2 rows in set (0.03 sec)
   ```


3. 現在、1つのLeaderと2つのFollowersが2つのPlacement Driverインスタンスに分散されています。もし別のPlacement Driverインスタンスが失敗した場合、Raft分散合意アルゴリズムが妨害されることになります。単に`02-8-recover-capacity-pd-server.sh`スクリプトを実行して、アクティブなPlacement Driverインスタンスを3に再設定します。


   ```
   $ ./02-8-recover-capacity-pd-server.sh
   ...
   Pid    Role     Uptime
   ---    ----     ------
   2755   pd       3h40m11.836368008s
   2756   pd       3h40m11.770562606s
   12310  pd       2.227006522s
   ...
   ```


4. `Ctrl-C`を押して、Javaのワークロードを終了します。
 
   ```
   Worker 2 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 23:36:43 CST 2023
   Worker 2 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 23:36:43 CST 2023
   Worker 1 - TiDB Server (port:4000) - INSERTING INTO test.dummy at Sat Apr 15 23:36:44 CST 2023
   Worker 1 - TiDB Server (port:4001) - INSERTING INTO test.dummy at Sat Apr 15 23:36:44 CST 2023
   ^C
   ```


5. TiDB Playground クラスタを終了し、すべてのデータを削除します。


   以前に`playground-start-demo.sh`を実行したターミナルに移動して、`Ctrl-C`を押します。
   ```
   ^CPlayground receive signal:  interrupt
   ...
   ```


   Playground データを削除します。
   ```
   $ ~/.tiup/bin/tiup clean demo
   Clean instance of `playground`, directory: /Users/username/.tiup/data/demo
   ```


## まとめ
TiDBは、計画されたダウンタイムと非計画のダウンタイムの両方を排除するために特別に設計されており、すべてのコンポーネントのレベルでオンラインのスケールイン/アウトをサポートし、オンラインのローリングアップデートとオンラインのDDLもサポートしています。また、計算、ストレージ、およびメタデータレイヤーで内蔵の自己修復能力が有効になっており、ソフトウェアの障害、ハードウェアの故障、アベイラビリティゾーン（データセンター）の停止に直面してもビジネスの継続性を確保しています。さらに、TiDB Cloudを使用すると、追加の設定無しにこれらの利点を享受できます。[TiDB基本ワークショップ](https://pingcap.co.jp/education/)の無料コースと、講師主導のトレーニング[TiDBの運用](https://pingcap.co.jp/education/)に参加して、オンラインのローリングアップデート、オンラインのDDL、実際のTiDBクラスタでの災害復旧に備えたデプロイメントなどを学んでください。


## 演習終わり

