Galera Clusterでsst_methodがrsyncのときDONORノードは本当にblockingになるのか

# はじめに
Galera ClusterでrsyncでSSTをしているみなさんこんにちは。

[State Snapshot Transfers — Galera Cluster Documentation](http://galeracluster.com/documentation-webpages/sst.html)

公式ドキュメントによると、rsyncはdonorノードがblockingになるとあります。

本当？

ということで実験です。

# 環境
5.5.45、3台構成。

```
# mysql -uroot -e "show status like 'wsrep_cluster%';"
+--------------------------+--------------------------------------+
| Variable_name            | Value                                |
+--------------------------+--------------------------------------+
| wsrep_cluster_conf_id    | 14                                   |
| wsrep_cluster_size       | 3                                    |
| wsrep_cluster_state_uuid | cf819ec9-e382-11e7-a390-768e47ae6c01 |
| wsrep_cluster_status     | Primary                              |
+--------------------------+--------------------------------------+
```

# SSTの発生方法

1台をサービス停止。そのノードのgrastate.datを削除して起動すると、SSTになります。

その理由はこちらを確認してください。

[Node Provisioning — Galera Cluster Documentation](http://galeracluster.com/documentation-webpages/nodeprovisioning.html)

>When a node joins the cluster, it compares its own state UUID to that of the Primary Component. If the state UUID does not match, the joining node requests a state transfer from the cluster.

ノード加入時、Primary Componentのstate UUIDと、自身のUUIDを比較し、一致しなければstate transferを要求します。

このとき、grastate.datにUUIDとseqnoが記載されてあれば、seqnoの差分だけ追いかけるのですが、そもそもこのファイルがないのでシーケンスの比較ができず、ISTが選択できないため、SSTを行います。

このあたりの動作はログからも確認できます。

```
171219  8:12:50 [Note] WSREP: Flow-control interval: [28, 28]
171219  8:12:50 [Note] WSREP: Shifting OPEN -> PRIMARY (TO: 3189)
171219  8:12:50 [Note] WSREP: State transfer required: 
        Group state: cf819ec9-e382-11e7-a390-768e47ae6c01:3189
        Local state: 00000000-0000-0000-0000-000000000000:-1
171219  8:12:50 [Note] WSREP: New cluster view: global state: cf819ec9-e382-11e7-a390-768e47ae6c01:3189, view# 16: Primary, number of nodes: 3, my index: 2, protocol version 3
171219  8:12:50 [Warning] WSREP: Gap in state sequence. Need state transfer.
171219  8:12:50 [Note] WSREP: Running: 'wsrep_sst_rsync --role 'joiner' --address '192.168.100.102' --auth '' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --parent '8429''
171219  8:12:50 [Note] WSREP: Prepared SST request: rsync|192.168.100.102:4444/rsync_sst
171219  8:12:50 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
171219  8:12:50 [Note] WSREP: REPL Protocols: 7 (3, 2)
171219  8:12:50 [Note] WSREP: Service thread queue flushed.
171219  8:12:50 [Note] WSREP: Assign initial position for certification: 3189, protocol version: 3
171219  8:12:50 [Note] WSREP: Service thread queue flushed.
171219  8:12:50 [Warning] WSREP: Failed to prepare for incremental state transfer: Local state UUID (00000000-0000-0000-0000-000000000000) does not match group state UUID (cf819ec9-e382-11e7-a390-768e47ae6c01): 1 (Operation not permitted)
         at galera/src/replicator_str.cpp:prepare_for_IST():456. IST will be unavailable.
171219  8:12:50 [Note] WSREP: Member 2.0 (maria2) requested state transfer from '*any*'. Selected 0.0 (maria3)(SYNCED) as donor.
171219  8:12:50 [Note] WSREP: Shifting PRIMARY -> JOINER (TO: 3189)
171219  8:12:50 [Note] WSREP: Requesting state transfer: success, donor: 0
171219  8:12:53 [Note] WSREP: (f74577ba, 'tcp://0.0.0.0:4567') turning message relay requesting off
171219  8:14:08 [Note] WSREP: 0.0 (maria3): State transfer to 2.0 (maria2) complete.
171219  8:14:08 [Note] WSREP: Member 0.0 (maria3) synced with group.
WSREP_SST: [INFO] Joiner cleanup. (20171219 08:14:08.820)
WSREP_SST: [INFO] Joiner cleanup done. (20171219 08:14:09.333)
171219  8:14:09 [Note] WSREP: SST complete, seqno: 3189
```

加入時に、Group Communicationをとって、group Stateとlocal stateを比較します。grastate.datに保存されている情報がないので、新規加入(provision)と解釈され、local stateは**00000000-0000-0000-0000-000000000000**になります。

ISTを試そうとするんですが、state UUIDが異なるため、SSTを行います。このときjoinerはmaria2、donorはmaria3が選ばれました。

# 検証
事前にテスト用DBを作成し、データを格納しておきましょう。

```mysql
MariaDB [(none)]> create database sst_blocking_test;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> use sst_blocking_test
Database changed
MariaDB [sst_blocking_test]> CREATE TABLE blocking_test (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)

MariaDB [sst_blocking_test]> INSERT INTO blocking_test (id, name)  VALUES (1, 'hogehoge');
Query OK, 1 row affected (0.00 sec)

MariaDB [sst_blocking_test]> SELECT * FROM blocking_test;
+------+----------+
| id   | name     |
+------+----------+
|    1 | hogehoge |
+------+----------+
1 row in set (0.00 sec)
```

donorを確実にするため、2台体制にしておきます。

grastate.datを削除してサービスを起動します。

```
# rm -f /var/lib/mysql/grastate.dat 
# service mysql start
Starting MySQL....SST in progress, setting sleep higher...... SUCCESS! 
```

約1分で加入しました。その間、donorノードで以下を実行。

```
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+----------------+
| Variable_name             | Value          |
+---------------------------+----------------+
| wsrep_local_state_comment | Donor/Desynced |
+---------------------------+----------------+
1 row in set (0.00 sec)

MariaDB [(none)]> INSERT INTO sst_blocking_test.blocking_test (id, name)  VALUES (2, 'fugafuga');
Query OK, 1 row affected (41.42 sec)

MariaDB [sst_blocking_test]> SELECT * FROM sst_blocking_test.blocking_test;
+------+----------+
| id   | name     |
+------+----------+
|    1 | hogehoge |
|    2 | fugafuga |
+------+----------+
2 rows in set (0.01 sec)
```

40秒ほどINSERTが待たされているので、blockingになってることがわかりました。

# おわりに
1台の状態からクラスタ復旧するときは、その加入時間だけサービスが停止してしまうことがわかりました。

mysqldumpやxtrabackupのSST methodは使ったことないんですが、xtrabackupはBrieflyとのことですが、MyISAMテーブルのロックだけかけるようですね。

>xtrabackup only blocks the donor for the short period of time it takes to copy the MyISAM tables, (for instance, the system tables). 

mysqldumpもinnodbに関しては--single-transaction相当の動きをしてくれればblockingにする必要ないと思うんだけどなー。(MyISAMのロックだけで)

以上、実験でした。