dockerでクラウドネイティブ分散型RDBのPolarDB-XとWordPressの環境を構築

# [PolarDB-X](url "https://www.alibabacloud.com/help/en/polardb-x/latest/polardb-x-overview")とは
PolarDB-XはAlibaba Cloudで提供されているクラウドネイティブ分散型RDBです。
GCPの[Spanner](url "https://cloud.google.com/spanner?hl=ja")やPingCAPの[TiDB](url "https://pingcap.co.jp/")と同じカテゴリの水平方向にスケーリングするNewSQLに分類されるデータベースです。

# 特徴：
-  分散型データベース
    - データは複数のノードに跨いて保持されていて、つまりどちらのノードでも全てのデータを持っていいるのではなく、一部しかもっていない。
        - AWS RDSは集中型データベースであり、master/slaveや read replicaの場合でも、書くノードはすべてのデータを持っていて、ストレージ容量が限られていて、大量の同時アクセスのシーンでは対応しきれないという課題があります。
    - 水平拡張によって読み取りと書き込み両方の性能向上が可能
        - AWS RDSではread replicaによって全体的な読み取りの性能が上げられるが、書き込みは全部primary instanceで処理されるため、書き込み性能をupさせるにはprimary instanceのスペックをあげるしかない。(数分程度DB停止になってしまう)

- opensourceのデータベース
https://github.com/ApsaraDB/PolarDB-X

| **Component Name** | **Repository** |
| --- | --- |
| CN (Compute Node) | [galaxysql](https://github.com/ApsaraDB/galaxysql)|
| GMS (Global Meta Service) | [galaxyengine](https://github.com/ApsaraDB/galaxyengine)|
| DN (Data Node) | [galaxyengine](https://github.com/ApsaraDB/galaxyengine)|
| CDC (Change Data Capture) | [galaxycdc](https://github.com/ApsaraDB/galaxycdc)|

PolarDB-XはCN,GMS,DN,CDC４つのコンポーネントから構成されている。　上記はそれぞれのgithub repoです。

- [MySQLと高い互換性](url "https://www.alibabacloud.com/help/en/polardb-x/latest/compatibility-with-the-mysql-ecosystem")
    - 基本的にMySQLと互換性があり、web frameworkからPolarDB-Xを利用するにはmysqlのライブラリがあれば、そのままPolarDB-Xに接続できる。

- 透明的なパーティション分割
    - 従来のdatabaseでsharding(パーティション分割)を行うには、アプリケイーション側でどのノードにどのデータを持っているのを意識する必要があり、アプリケイーションのロジックが非常に複雑になりがちです。
    - PolorDB-Xではauto incrementのprimary keyをパーティションkeyとしてデフォルトで利用、hash関数で自動的に複数のパーティションに分散される。従来のシングルノードのMySQLと同じ感覚で分散型のデータベースが利用できる。


# ローカル環境(macOS)にdocker-composeを利用してPolarDB-XとWordPressをinstall
## dockerのインストール

## 任意のディレクトリにdocker-compose.ymlを作成
```
version: '3'

services:
  polardbx:
    image: polardbx/polardb-x
    restart: always
    container_name: polardbx
    ports:
      - "8527:8527"

  wordpress:
    depends_on:
      - polardbx
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: polardbx:8527
      WORDPRESS_DB_USER: polardbx_root
      WORDPRESS_DB_PASSWORD: 123456
      WORDPRESS_DB_NAME: wordpress
```
- polardb-x:
    - デフォルト設定のuser名とpasswordを利用してください。
        - user名: `polardbx_root`
        - password: `123456`
    - [dockerhub](https://hub.docker.com/layers/polardbx/polardb-x/latest/images/sha256-7a29520f6a77b7adcb0ead5ac62c0134172ffb072acc9b6e5daca81652e14aec?context=explore) にpolardb-xのdockerfileがなさそうなので、デフォルトのuser名とpasswordの変更方法が不明です。
- wordpress: 
    - depends_onでコンテナの依存関係を定義しているので、この例ですとpolardbxを起動してから、wordpressが起動される設定となります。
    - hostやuserなどの環境変数設定方法は https://hub.docker.com/_/wordpress をご参考ください。

## docker-composeを実行
```
docker compose up -d
[+] Running 1/2
[+] Running 2/2lardbx                        Starting                                           0.5s
 ⠿ Container polardbx                        Started                                            0.5s
 ⠿ Container wordpresspolardb-x-wordpress-1  Star...                                            1.0s
```
```
docker compose ps
NAME                             COMMAND                  SERVICE             STATUS              PORTS
polardbx                         "/bin/sh -c /home/ad…"   polardbx            running             0.0.0.0:8527->8527/tcp
wordpresspolardb-x-wordpress-1   "docker-entrypoint.s…"   wordpress           running             0.0.0.0:8000->80/tcp
```

## polardb-xにログインし、wordpressに必要なdatabaseを作成しておく
```
$ mysql -h127.0.0.1 -P8527 -upolardbx_root -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.6.29 Tddl Server (ALIBABA)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```
- 以下のエラーが発生している場合は、polardb-xクラスター準備している途中なので、三四分程度経ってから再度ログインしてください。
```
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
```

- databaseを作成
```
mysql> create database wordpress MODE='AUTO';

mysql> show databases;
+--------------------+
| DATABASE           |
+--------------------+
| information_schema |
| wordpress          |
+--------------------+
```

## WordPressを設定
- wordpressのアカウント情報を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/221f5f77-7773-55f3-04f8-0b70c15b23b8.png)
- [Log in]ボタンをクリックし、ログイン画面に遷移
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/767a5cc7-dc2c-5786-9659-8485f7f4fde6.png)
- 認証情報を入力し、ログイン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a76717e5-da8d-3e80-765d-60e41d7d5d74.png)
- 下記の画面が表示されたら、ログインができた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/6580fe06-8b40-3566-216c-775121c19397.png)

## DBの中身の確認
```
mysql> use wordpress;
Database changed

mysql> show tables;
+-----------------------+
| TABLES_IN_WORDPRESS   |
+-----------------------+
| wp_commentmeta        |
| wp_comments           |
| wp_links              |
| wp_options            |
| wp_postmeta           |
| wp_posts              |
| wp_term_relationships |
| wp_term_taxonomy      |
| wp_termmeta           |
| wp_terms              |
| wp_usermeta           |
| wp_users              |
+-----------------------+

mysql> select * from wp_users;
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| ID     | user_login | user_pass                          | user_nicename | user_email          | user_url              | user_registered     | user_activation_key | user_status | display_name |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| 100001 | dennis     | $P$BkGz1QgYBqElISzywtQl7hzAEB47f3. | dennis        | ****                | http://localhost:8000 | 2022-07-25 05:35:30 |                     |           0 | dennis       |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
```

- wp_usersテーブルのpartition状況確認：
自動的に8つのpartitionに分割されていることが確認できる

```
mysql> show topology from wp_users;
+----+------------------------+---------------------+----------------+
| ID | GROUP_NAME             | TABLE_NAME          | PARTITION_NAME |
+----+------------------------+---------------------+----------------+
|  0 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00000 | p1             |
|  1 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00001 | p2             |
|  2 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00002 | p3             |
|  3 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00003 | p4             |
|  4 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00004 | p5             |
|  5 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00005 | p6             |
|  6 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00006 | p7             |
|  7 | WORDPRESS_P00000_GROUP | wp_users_d0DM_00007 | p8             |
+----+------------------------+---------------------+----------------+
```

- テーブルの作成コマンドでprimary keyの`ID`はpartion keyとして利用していることが分かる。
```
mysql> show full create table wp_users;
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE    | CREATE TABLE                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| wp_users | CREATE PARTITION TABLE `wp_users` (
	`ID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	`user_login` varchar(60) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_pass` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_nicename` varchar(50) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_email` varchar(100) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_url` varchar(100) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
	`user_activation_key` varchar(255) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	`user_status` int(11) NOT NULL DEFAULT '0',
	`display_name` varchar(250) COLLATE utf8mb4_unicode_520_ci NOT NULL DEFAULT '',
	PRIMARY KEY (`ID`),
	GLOBAL INDEX /* user_email_$34fb */ `user_email` (`user_email`) PARTITION BY KEY (`user_email`, `ID`) PARTITIONS 8,
	GLOBAL INDEX /* user_login_key_$377b */ `user_login_key` (`user_login`) PARTITION BY KEY (`user_login`, `ID`) PARTITIONS 8,
	GLOBAL INDEX /* user_nicename_$b701 */ `user_nicename` (`user_nicename`) PARTITION BY KEY (`user_nicename`, `ID`) PARTITIONS 8,
	LOCAL KEY `_local_user_login_key` (`user_login`),
	LOCAL KEY `_local_user_nicename` (`user_nicename`),
	LOCAL KEY `_local_user_email` (`user_email`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 DEFAULT COLLATE = utf8mb4_unicode_520_ci
PARTITION BY KEY(`ID`)
PARTITIONS 8
/* tablegroup = `tg1` */ |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```

- userはどのpartitionに保持されているのかを確認
- ID=1のuserはP2に保持されていることが分かる。
```
mysql> SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='wp_users';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p1             |          0 |
| p2             |          1 |
| p3             |          0 |
| p4             |          0 |
| p5             |          0 |
| p6             |          0 |
| p7             |          0 |
| p8             |          0 |
+----------------+------------+
```
- wordpress上で新規user作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/9870dc40-048d-c50c-79ef-5c5d69157f92.png)

```
mysql> select * from wp_users;
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| ID     | user_login | user_pass                          | user_nicename | user_email          | user_url              | user_registered     | user_activation_key | user_status | display_name |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| 100001 | dennis     | $P$BkGz1QgYBqElISzywtQl7hzAEB47f3. | dennis        | outanwang@gmail.com | http://localhost:8000 | 2022-07-25 05:35:30 |                     |           0 | dennis       |
| 100002 | test       | $P$BhNx08hRmtRynzmRWWBOex6glWZtwO0 | test          | test4@example.com   | http://test           | 2022-07-25 06:26:19 |                     |           0 | test         |
| 100003 | test2      | $P$B.ednrTvBfGla87FEXgBdGK/w1PPoe. | test2         | test2@example.com   | http://test2          | 2022-07-25 07:29:13 |                     |           0 | test2        |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
```

- INFORMATION_SCHEMA.PARTITIONSから取得した情報はあくまでも統計情報(概算)であり、反映されていない場合がある。
- ３つのレコードがあるにも関わらず、一つしか表示されていない。
```
mysql>  SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='wp_users';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p1             |          0 |
| p2             |          1 |
| p3             |          0 |
| p4             |          0 |
| p5             |          0 |
| p6             |          0 |
| p7             |          0 |
| p8             |          0 |
+----------------+------------+
```
- partitionを指定し、件数を確認
  - P2,P5,P7にそれぞれ一件のデータがあることが分かる。
```
mysql> select * from wp_users PARTITION (p1);
Empty set (0.01 sec)

mysql> select * from wp_users PARTITION (p2);
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| ID     | user_login | user_pass                          | user_nicename | user_email          | user_url              | user_registered     | user_activation_key | user_status | display_name |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
| 100001 | dennis     | $P$BkGz1QgYBqElISzywtQl7hzAEB47f3. | dennis        | outanwang@gmail.com | http://localhost:8000 | 2022-07-25 05:35:30 |                     |           0 | dennis       |
+--------+------------+------------------------------------+---------------+---------------------+-----------------------+---------------------+---------------------+-------------+--------------+
1 row in set (0.01 sec)

mysql> select * from wp_users PARTITION (p3);
Empty set (0.00 sec)

mysql> select * from wp_users PARTITION (p4);
Empty set (0.01 sec)

mysql> select * from wp_users PARTITION (p5);
+--------+------------+------------------------------------+---------------+-------------------+-------------+---------------------+---------------------+-------------+--------------+
| ID     | user_login | user_pass                          | user_nicename | user_email        | user_url    | user_registered     | user_activation_key | user_status | display_name |
+--------+------------+------------------------------------+---------------+-------------------+-------------+---------------------+---------------------+-------------+--------------+
| 100002 | test       | $P$BhNx08hRmtRynzmRWWBOex6glWZtwO0 | test          | test4@example.com | http://test | 2022-07-25 06:26:19 |                     |           0 | test         |
+--------+------------+------------------------------------+---------------+-------------------+-------------+---------------------+---------------------+-------------+--------------+
1 row in set (0.01 sec)

mysql> select * from wp_users PARTITION (p6);
Empty set (0.01 sec)

mysql> select * from wp_users PARTITION (p7);
+--------+------------+------------------------------------+---------------+-------------------+--------------+---------------------+---------------------+-------------+--------------+
| ID     | user_login | user_pass                          | user_nicename | user_email        | user_url     | user_registered     | user_activation_key | user_status | display_name |
+--------+------------+------------------------------------+---------------+-------------------+--------------+---------------------+---------------------+-------------+--------------+
| 100003 | test2      | $P$B.ednrTvBfGla87FEXgBdGK/w1PPoe. | test2         | test2@example.com | http://test2 | 2022-07-25 07:29:13 |                     |           0 | test2        |
+--------+------------+------------------------------------+---------------+-------------------+--------------+---------------------+---------------------+-------------+--------------+
1 row in set (0.01 sec)

mysql> select * from wp_users PARTITION (p8);
Empty set (0.02 sec)
```

# まとめ
- polardb-xは分散型RDBであり、デフォルトはPrimary keyをpartition keyとして利用するため、MySQLのpartition関連のノウハウを持っていなくても簡単にpartition利用できて、分散型のデータベースを体験できる。
    - primary keyのないテーブルに対して、自動的にBIGINTのprimary key(userから見れないkey)を作成し，partition keyとして利用することにになる。
- 特に分散やpartitionを意識しなくてもシングルノードのMySQLと同じ感覚で、分散型データベース利用できる（もちろん同時処理の性能が水平的に拡張できるという分散型のデータベースの最大のメリットを活かすにはpartiton関連の知識がある程度必要です。）
- polardb-xはopensourceのデータベースであり、ローカル環境でもdockerで簡単に実行できる。