Galera Clusterのwsrep_OSU_method='RSU'の動きを確認する

MySQLのALTER TABLEの話を聞く機会があり*1,Galera ClusterのRolling Schema Upgrade(特にパーティションまわりの変更)を試しておきたい気持ちになったので,備忘録的に記録を残しておきます。

wsrep_OSU_method='RSU'でスキーマ変更を実行すると,その変更は実行したノードにのみ反映されます。また,実行中は他のノードとの同期が停止し,変更完了後に差分を適用して追いつきます。

ドキュメントにもある通り,スキーマの互換性を保っていれば問題なさそう*2なので,更新止まってる間の差分とgcacheのサイズに気をつけておけば大丈夫だとは思いますが,気になるので適当なパーティションを作って試してみます。

なおこの記事は所属組織とは関係なく個人的興味によるものなので,念の為。

準備

ローカルにVMを3台建てました(maria01-03)。

  • CentOS 8(VirtualBox
  • MariaDB 10.3.17
  • wsrep_cluster_addressなどのGalera Clusterを組むための最低限の設定以外デフォルト

それっぽいテーブルをつくっておきます。

CREATE TABLE users (
    id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(64) NOT NULL
);
CREATE TABLE user_logs (
    user_id INTEGER NOT NULL,
    action VARCHAR(64) NOT NULL,
    logged_at DATETIME NOT NULL
) PARTITION BY RANGE COLUMNS(logged_at) (
    PARTITION p20200525 VALUES LESS THAN ('2020-05-26'),
    PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE
);

それっぽいデータも入れておきます。

INSERT INTO users VALUES
    (1, 'Taro'),
    (2, 'Hanako');
INSERT INTO user_logs VALUES
    (1, 'MOVE', '2020-05-25 15:00:00'),
    (1, 'ATTACK', '2020-05-26 12:00:00'),
    (2, 'MAGIC', '2020-05-027 06:00:00');

このuser_logsテーブルのpMAXVALUEパーティションを細切れにしていきます。

> SELECT * FROM user_logs PARTITION (p20200525);
+---------+--------+---------------------+
| user_id | action | logged_at           |
+---------+--------+---------------------+
|       1 | MOVE   | 2020-05-25 15:00:00 |
+---------+--------+---------------------+
1 row in set (0.000 sec)

> SELECT * FROM user_logs PARTITION (pMAXVALUE);
+---------+--------+---------------------+
| user_id | action | logged_at           |
+---------+--------+---------------------+
|       1 | ATTACK | 2020-05-26 12:00:00 |
|       2 | MAGIC  | 2020-05-27 06:00:00 |
+---------+--------+---------------------+
2 rows in set (0.000 sec)

いざ

まずはuser_logsのデータ量が少ない状態で試してみます。

maria01をRSUに変更します。

SET GLOBAL wsrep_OSU_method='RSU';

maria01でREORGANIZE PARTITIONを打ちます。

> ALTER TABLE user_logs REORGANIZE PARTITION pMAXVALUE INTO (
    PARTITION p20200526 VALUES LESS THAN ('2020-05-27'),
    PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE
);

> SELECT PARTITION_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'user_logs';
+----------------+
| PARTITION_NAME |
+----------------+
| p20200525      |
| p20200526      |
| pMAXVALUE      |
+----------------+

maria02でも確認して,適当にデータを入れてみます。

> SELECT PARTITION_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'user_logs';
+----------------+
| PARTITION_NAME |
+----------------+
| p20200525      |
| pMAXVALUE      |
+----------------+
> INSERT INTO user_logs VALUES (2, 'WAIT', '2020-05-26 05:00:00');
> INSERT INTO users VALUES (3, 'Saburo');

問題なく実行でき,maria01で確認してもデータは入っています。

では,一旦このALTERを全ノードで流した後,pMAXVALUEにlogged_atが5/27のデータを500万行くらい流し込んで,REORGANIZE PARTITIONに要する時間が長くなるようにしてみます。

まずは,maria01でuser_logのpMAXVALUEを切る,ALTER実行中にmaria02でuserを更新,maria01の別セッションでuserをselect,の一連の操作をしてみます。

maria01 > ALTER TABLE user_logs REORGANIZE PARTITION pMAXVALUE INTO (
    PARTITION p20200527 VALUES LESS THAN ('2020-05-28'),
    PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE
);

maria02 > UPDATE users set name='Sabuko' WHERE id = 3;
maria02 > SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  1 | Taro   |
|  2 | Hanako |
|  3 | Sabuko |
+----+--------+
3 rows in set (0.000 sec)

maria01 > SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  1 | Taro   |
|  2 | Hanako |
|  3 | Saburo |
+----+--------+
3 rows in set (0.000 sec)

-- maria01 ALTER終了
Query OK, 5000001 rows affected (26.793 sec)
Records: 5000001  Duplicates: 0  Warnings: 0

maria01 > SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  1 | Taro   |
|  2 | Hanako |
|  3 | Sabuko |
+----+--------+
3 rows in set (0.303 sec)

ALTER実行中は同期が止まり,終了後に追いつくことが確認できました。

次に,maria02でALTERを実行中に,maria02でuserにINSERTを打ってみたいと思います。

maria02 > SET GLOBAL wsrep_OSU_method='RSU';

maria02 > ALTER TABLE user_logs REORGANIZE PARTITION pMAXVALUE INTO (
    PARTITION p20200527 VALUES LESS THAN ('2020-05-28'),
    PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE
);

maria02 > INSERT INTO users VALUES (4, 'Shiro');
-- ここで固まる

maria01 > SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  1 | Taro   |
|  2 | Hanako |
|  3 | Sabuko |
+----+--------+
3 rows in set (0.000 sec)

-- maria02 ALTER終了
Query OK, 5000001 rows affected (29.922 sec)
Records: 5000001  Duplicates: 0  Warnings: 0

-- maria02のINSERTが流れる
Query OK, 1 row affected (27.968 sec)

maria01 > SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  1 | Taro   |
|  2 | Hanako |
|  3 | Sabuko |
|  4 | Shiro  |
+----+--------+
4 rows in set (0.000 sec)

切り離したノードでINSERTを打ってALTER終了まで固まるのは一瞬おやっと思いましたが,冷静に考えると他のノードからの更新を受け取らなくなっているわけなので,更新できてしまったらまずいわけですね。

最後に,maria03でALTERを打って,実行中にmaria01から100万行user_logsにINSERTしてみます。

maria03 > SET GLOBAL wsrep_OSU_method='RSU';

maria03 > ALTER TABLE user_logs REORGANIZE PARTITION pMAXVALUE INTO (
    PARTITION p20200527 VALUES LESS THAN ('2020-05-28'),
    PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE
);

maria01 > -- 100行ずつ100万行のINSERT

maria02 > SELECT COUNT(1) FROM user_logs;
+----------+
| count(1) |
+----------+
|  5111004 |
+----------+
1 row in set (5.406 sec)

-- maria03 ALTER終了
maria03 >  SELECT COUNT(1) FROM user_logs;
+----------+
| count(1) |
+----------+
|  5015704 |
+----------+
1 row in set (9.183 sec)

ちょっと遅れますが,ALTERが終わってからちゃんとついてくるようです。しばらく待つと全ノードに100万行入りました。

まとめ

Galera ClusterのRolling Schema Upgradeの動きを手を動かして確認できたよという記事なので,特にまとめるような話でもないですが,データ量は多い割にアクセスされないテーブルなどのメンテナンスで試せそうな感じです。