PolarDBとAuroraの性能対決：３倍の結果！

# 1. 目的と前提条件
## 1.1 目的
業務上でAlibaba CloudのPolarDBとAWSのAuroraを両方使用しています。これらは似た位置づけであり、それぞれのクラウドで推奨されるクラウドネイティブデータベースです。
今回は、これら二つをベンチマークし、性能を比較してみます。より実践に近いシナリオで正確に比較するため、中規模のシナリオのテストを設計しました。

::: note info
データベースの規模はテーブルの数や各テーブルの行数だけでなく、データの総量、複雑性、クエリの複雑さ、および性能要求など複数の要因に基づき判断されます。テストのデータベースには3億件のデータがありますが、テストでは複数のテーブル結合、複雑な集約やサブクエリ、高い並行トランザクション処理が必要なクエリは考慮していませんので、このテストは中規模のデータベースに分類されます。
:::

## 1.2 条件
- table数：20
- tableごとの行数：1,000万
- データベーススペック：8 core 16GBメモリ
- データベースのnode数： 1 (一つのmaster nodeのみの構成)
::: note info
PolarDBは、クエリの種類に応じてmaster nodeとread-only node(Auroraにおける`Read replica`)を自動的に分散させるエンドポイントを提供しており、master nodeとread-only nodeを含むクラスター全体の性能テストを容易に実施できます。一方、Auroraにはこのような機能を持つエンドポイントが存在しないため、本テストではread-only nodeを使用しないシナリオに焦点を当て、write nodeのみを使用した場合の性能をPolarDBと比較します。
:::
- VMのスペック：
  - ECS (Alibaba Cloud上のバーチャルマシン)：32core64GB（`ecs.c7.8xlarge`）
  - EC2：36core72GB（`C5.9xlarge`）

:::note info
AWSのEC2には32core64GBのインスタンスタイプがないため、36core72GBの`C5.9xlarge`を選択しました。VMのスペックは十分に高いため、テスト結果に影響はないと考えられます。
:::

- region：VMとデータベースは同じリージョンに配置
- zone：VMとデータベースは同じアベイラビリティーゾーン（AZ）に配置
- VPC：VMとデータベースは同じVPC内に配置

# 2. 結果比較
先にテストした結果をまとめます。
詳細な手順については後ほど詳しく解説します。
| 比較指標 | QPS | TPS |
|:-----------:|:------------:|:------------:|
| PolarDB    | 2638.66 |  52773.26   |
| Aurora     | 835.97  | 16719.47    |
| PolarDB/Aurora倍数 | <font color="red">3.15 |<font color="red"> 3.15 |


# 3. テスト環境構築
## 3.1 Alibaba Cloud
### 3.1.1 PolarDB

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/c3458482-3d24-7c12-919e-7efadde08359.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a7dc0389-53cf-7759-b418-96caf6fd0e31.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/17149cf4-c908-76d0-584c-5b984bb21518.png)
- databaseのaccount作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/8ec25449-8a8a-805d-568d-c6f6ea9ce461.png)

### 3.1.2 ECS
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/9af37c5a-1882-b76b-97da-d09152059e3c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/77e8536d-d22f-a951-941e-64124e20dec7.png)
- 手動で必要なlibraryをインストール
```
$ sudo apt update
$ sudo apt install mysql-client-core-8.0 -y
$ sudo apt install sysbench -y
```
- 環境変数に以下の変数を設定しておく
```
DBHOST=*
DBUSER=*
DBPASS=*
```

:::note info
PolarDB接続endpointの確認方法：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/1f5ab4c0-799c-b863-71db-0ce12c67701a.png)
:::
- sysbenchはデフォルトで`sbtest`というデータベースを利用するため、手動でデータベースを作成しておきます。
```
echo 'CREATE DATABASE sbtest' | mysql -h ${DBHOST} -P 3306 -u ${DBUSER} -p
```
- tableとデータを作成
```
time sysbench --db-driver=mysql \
    --mysql-host=${DBHOST}  \
    --mysql-user=${DBUSER} \
    --mysql-password=${DBPASS} \
    --tables=20 \
    --table_size=10000000 \
    --range_selects=on \
    --db-ps-mode=disable \
    --time=1800 \
    --threads=500 \
    --report-interval=1 \
    oltp_read_write \
    prepare
```

- 並行実行しているconnections数を確認してみる('--threads'に500のthreadを指定しましたが、20個のテーブルしかないため、20個のconnectionしかありません。
```
sudo netstat -antp | grep sysbenc
sudo netstat -antp | grep sysbench | wc -l
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/565fb6a3-2ad0-4931-4009-23b7bfc4fbc8.png)
- データの準備は11分弱かかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/e8559f03-4c48-978d-0b95-041c6bacbe74.png)
- データベースの中身を確認(`sbtest1`~ `sbtest20`まで20個のテーブル、それぞれ1000万のレコードがあります)
```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| __recycle_bin__    |
| sbtest      |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

mysql> use sbtest;

mysql> show tables;
+-------------------------+
| Tables_in_sbtest |
+-------------------------+
| sbtest1          |
| sbtest10         |
| sbtest11         |
| sbtest12         |
| sbtest13         |
| sbtest14         |
| sbtest15         |
| sbtest16         |
| sbtest17         |
| sbtest18         |
| sbtest19         |
| sbtest2          |
| sbtest20         |
| sbtest3         |
| sbtest4          |
| sbtest5          |
| sbtest6          |
| sbtest7          |
| sbtest8          |
| sbtest9          |
+------------------+

mysql> show create table sbtest1;
+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                         |
+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sbtest1 | CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8 |

mysql> select count(*) from sbtest1;
+----------+
| count(*) |
+----------+
|    10000000 |
+----------+
```

## 3.2 AWS
### 3.2.1 Aurora
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a3aa3295-069b-77e0-1ddb-518a716fe610.png)

### 3.2.2 EC2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/df2a9bb6-c57f-4515-2e9b-ee2e6498a65d.png)
- 手動で必要なlibraryをインストール
```
$ sudo apt update
$ sudo apt install mysql-client-core-8.0 -y
$ sudo apt install sysbench -y
```
- 環境変数に以下の変数を設定しておく
```
DBHOST=*
DBUSER=*
DBPASS=*
```
::: note info
Auroraの接続endpoint確認方法：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/7c6d6368-521b-d6e4-a189-60a424185148.png)
:::
- sysbenchはデフォルトで`sbtest`というデータベースを利用するため、手動でデータベースを作成しておきます。
```
echo 'CREATE DATABASE sbtest' | mysql -h ${DBHOST} -P 3306 -u ${DBUSER} -p
```
- tableとデータを作成
```
time sysbench --db-driver=mysql \
    --mysql-host=${DBHOST}  \
    --mysql-user=${DBUSER} \
    --mysql-password=${DBPASS} \
    --tables=20 \
    --table_size=10000000 \
    --range_selects=on \
    --db-ps-mode=disable \
    --time=1800 \
    --threads=500 \
    --report-interval=1 \
    oltp_read_write \
    prepare
```
- データの準備は39分程度かかりました。PolarDBの約４場合の時間
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/9905a4d2-e097-941f-26a1-d58b5475acf4.png)


# 4. テスト実施
## 4.1 PolarDB
- テスト実施(コマンドの最後の`prepare`を`run`に修正しただけ)：
  - tables: 生成されるテーブルの数、デフォルト値は１
  - table_size: テーブルごとのデータ件数
  - db-ps-mode：事前コンパイルが必要かどうか、デフォルトはdisable（すべてのトランザクションクエリが素のSQLの形式で実行されること）
  - time: コマンドの実行時間、デフォルトは10秒
  - threads: データベースに同時にいくつの接続を確立するかを制御する、デフォルト値は1
  - report-interval: 何秒ごとにテストの進行状況レポートを出力するか

```
sysbench --db-driver=mysql \
      --mysql-host=${DBHOST}  \
      --mysql-user=${DBUSER} \
      --mysql-password=${DBPASS} \
      --tables=20 \
      --table_size=10000000 \
      --range_selects=on \
      --db-ps-mode=disable \
      --time=600 \
      --threads=500 \
      --report-interval=1 \
      oltp_read_write \
      run
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/803aa6d0-c48a-d4e1-af57-e3b0d5e706ca.png)
- connections数を確認
```
sudo netstat -antp | grep sysbenc
sudo netstat -antp | grep sysbench | wc -l
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/ca7eee00-7c98-a6b1-cc33-0c65bf76dc4c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/5498cc6e-f7b7-c1a8-68bb-28440d384d64.png)
- コンソール上でCPU使用率、TPS、QPSの変化状況を確認
:::note info
変化の度合いをより明瞭に把握するために、デフォルトの60秒監視間隔を5秒に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/cd714b2c-fc97-50ab-d5cd-8c6907fc8634.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/3b8355e9-d2e0-27d7-f4a8-c0eb68ea9d57.png)
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/7bed22ae-8ebd-29fb-ce8b-dd52f341cb3e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/0c77be45-caa5-b098-4689-6f9e2e7d69d2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/7a890292-bae2-33be-9642-b497c48317c4.png)

- TPSとQPSを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/e1326cfc-7af8-b709-caf2-80d4d1eb2f0e.png)

:::note info
- データクリア作業（`run`コマンドを`cleanup`に変え、他のパラメーターは変更せずに）：
複数回のテストを行う場合、`prepare`、`run`、`cleanup`の三つのコマンドを正確な順序で実行することが必須です。`cleanup`のステップを省略して何度も`run`を行うことは避けてください。その理由は、以前のテストから一時テーブルや接続といったリソースが残っている可能性があり、これらを事前にクリアしておかないと、新たなテストデータと衝突し、エラーが発生したりテストの精度に影響を及ぼす恐れがあるからです。
```
sysbench --db-driver=mysql \
      --mysql-host=${DBHOST}  \
      --mysql-user=${DBUSER} \
      --mysql-password=${DBPASS} \
      --tables=20 \
      --table_size=10000000 \
      --range_selects=on \
      --db-ps-mode=disable \
      --time=600 \
      --threads=500 \
      --report-interval=1 \
      oltp_read_write \
      cleanup
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/2b5de558-30ae-7ab7-d050-743a9c1b2bc0.png)
```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| __recycle_bin__    |
| information_schema |
| mysql              |
| performance_schema |
| sbtest             |
| sys                |
+--------------------+

mysql> show tables from sbtest;
Empty set (0.00 sec)
```
:::

## 4.2 Aurora
```
sysbench --db-driver=mysql \
      --mysql-host=${DBHOST}  \
      --mysql-user=${DBUSER} \
      --mysql-password=${DBPASS} \
      --tables=20 \
      --table_size=10000000 \
      --range_selects=on \
      --db-ps-mode=disable \
      --time=1800 \
      --threads=500 \
      --report-interval=1 \
      oltp_read_write \
      run
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/3444a245-fa7b-4700-15e2-b5a58c69f917.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/7b79b3b7-43b1-f8c1-8887-b2832175f4d5.png)

# 5. まとめ
- Auroraがクエリの種類に応じて書き込みノードと読み取りノードを自動的に分散するエンドポイントを提供していないため、今回のテストでは、読み取りノードを使用しないシナリオ、つまり書き込みノードのみを用いた場合の性能を、同等条件下のPolarDBと比較しました。PolarDBはAuroraの3倍強の性能結果がでました。
- 基本的に、同じスペックのPolarDBはAuroraに比べて約20〜30%安価な価格設定です（使用方法にもよりますが）。そのため、総合的なコストパフォーマンスを考慮すると、PolarDBはAuroraに比べて約4倍の価値があると考えてよいでしょう

次回はPolarDBの ServerlessとAuoraのServerlessの性能を比較しようと考えています。