Alibaba CloudのPolarDBの徹底分析(8)_PolarDB Serverlessの基礎

# 1. PolarDBの種類
PolarDBには以下の2種類があります。
- ユーザーがインスタンスのスペック(メモリとCPU)を明示的に指定する昔ながらの `Provisioned` 型
- DBへのアクセストラフィック(インスタンスの負荷状況、つまりCPU、メモリ、ネットワークなど)に基づくデータベースのリソースが自動的にスケーリングできる　`Serverless` 型
::: note info
「Serverless」という言葉は、「サーバーがない」という意味ではなく、裏側では実際にインスタンスが存在しています。この言葉は「サーバーの管理を意識する必要がない」という意味で使われます。
:::

| 比較項目 | Provisioned | Serverless |
|:-----------|:------------|:------------|
| オートスケール範囲 | ・ストレージのみ| ・computing(CPU + メモリ)<br> ・ストレージ |
| スケーリング方法 | 手動によるスケールアップ/スケールダウン | 負荷に応じて自動的に変動|
| スケーリング時に切断あるか| 30秒程度接続断発生 | 接続断なし|
| クラスタ構成     | ・master node<br>・read-only node| ・master node<br>・read-only node|
| 課金方法 | 固定(スペック) | 負荷に応じて変動|
| 起動/停止 | 手動 | 自動|
| read-only node台数 | 15台 | 15台 |
| 対応バージョン | 8.0 <br> 5.7 <br> 5.6 | 8.0 <br> 5.7 |


# 2. 従来のProvisioned 型における課題
スケールの観点から見ると、容量が足りなくなる場合は、ストレージはオートスケールしますが、コンピューティングレイヤーのオートスケールにはまだ対応していません。そのため、ワークロードに応じた最適なコンピューティングレイヤー（サーバのスペックや台数）の調整やコスト最適化を行うことは困難です。繁忙期のワークロードに必要なコンピューティングレイヤーを固定する必要があります。

1. 繁忙時間帯のワークロードにも対応できるリソースを多めに＆つねり確保する必要があり、時間帯によってアクセスの変動のあるシナリオではリソースの無駄が大きいです。
![p550765.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/89285240-d692-957d-72cb-315a8172f444.png)

1. ユーザー側でインスタンス管理が必要で、管理コストが高い。(定期updateなど)

:::note info
Provisioned型にも以下のスケールアウト・スケールイン(`水平スケーリング`とも言われていて、read-only nodeの増減)の方法もありますが、実用性が低くて、ほとんど使われていないようです。
- 使われていない理由：
    - スケールアウト・スケールインは数分かかるため、トラフィックの増減になかなか追いつかない。
    - スケールアウト、スケールインはnode単位であるため、無駄が大きい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/871f72b2-2bba-9f63-1b80-11a740148ed0.png)
- Provisioned型におけるスケールアウト・スケールイン(`水平スケーリング`)方法：
    1. Alibaba Cloudの[Function Compute](https://qiita.com/junk87/items/45de5da6bb6f6d6b57fb)(AWSのLamdaのようなサービス)と連携し時刻指定のスケールアウト・スケールインを行う
        - トラフィックが頻繁に変動するシーンでは時刻の指定は難しくなります。
    1. PolarDB auto scaling機能を利用し、指定していたCPU平均使用率(現在はCPU使用率しか指定できなくて、メモリなどの使用率を見てauto scalingすることが対応できていない)を超えると、自動的にauto scalingする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/c54d6f08-ae9e-c138-73d3-d8a787522477.png)
    
    1. サーバーのメトリック監視のサービスCloudMonitor(AWSのCloudWatchに似ているもの)と連携し、CPUだけではなく、メモリなどの使用率も含めて、ある閾値を超えると自動的にスケールアウト・スケールインする仕組みを作る

上記のスケールアウト、スケールインはあくまでもread-only nodeの増減なので、データベースの読み取り性能は拡張できるが、書き込み性能が拡張できません。
primary nodeのスペックを変更することによってスケールアップ/スケールダウン(`垂直スケーリング`)もできなくはないのですが、クラスターの再起動が必要になり、数分サービス停止する必要があるため、本番環境では安易にスペックが変更できないでしょう。
:::

# 3. serverlessの詳細
## 3.1 特徴
- 一定時間内にアクセスがなかった場合は、データベースが`完全停止`できる
::: note info
- 完全停止期間中、computingの部分（CPU、メモリ）は無料となりますが、ストレージの部分はデータを削除しない限り、継続的に課金されます。
- 完全停止の状態から起動するまでは数秒かかり、起動している途中ではサービスが利用できません。この問題を回避するために、完全にシャットダウンせず、最低限のリソースを確保しておく方法も考えられます。
:::
- アクセスが来たら、ゼロから自動的に`起動`する
- アクセスの変化に応じて`スケールアップ・ダウン`(nodeのスペックが自動的に増減)する
    - スケーリングの単位は `PCU` (PolarDB Capacity Unit)である
    - 1 PCU = 1 core CPU + 2GB メモリ
        - 最小PCU： 1 PCU
        - 最大PCU： 32 PCU
    - クエリ実行中でも自動スケーリングを行なってくれる
    - スケーリングダウンの際、DBコネクションが切れることはありません。スケーリング中にポーズしたり、スループットが落ちることもありません。
- まず垂直スケーリングし、一つのnodeが対応しきれない場合は、自動的に`スケールアウト`(read-only nodeが自動的に起動してくれる)
  - 一つのclusterの最大のnode数： 16個 (1 primay node + 15 read-only node )
  - 一つのnodeのPCUの範囲： 0 PCU ~ 32 PCU
  - 一つのclusterのPCU範囲: 0 PCU ~ 512 PCU (32*16)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/6e8efdee-0805-8446-6884-ff42ace6da4b.png)

::: note info
AWS Aurora Serverlessは1ACU あたり約2GBのメモリ、対応するCPU、ネットワークが組み合わせられます。
Aurora Serverless v2 インスタンスは、垂直スケーリング（scale up/down）には対応していますが、水平スケーリング（scale out/in）には対応していません。
Serverless v2 Reader nodeを追加するには、手動で追加する必要があります。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/8ae55b8d-8a8e-1e8f-18cf-b467f2561533.png)

- 通常時はスケールアップは 0.5 PCU 刻みで行われ、利用状況に応じて細やかなスケーリングを実現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/af8e5a3c-146d-64a4-7ffd-4ae328aac005.png)

- 現在の容量が大きいほど、スケーリングの増分が大きくなります。突発的に利用増加した場合はちまちま 0.5 PCU ずつスケールアップしていくのではなく、その時の PCU の大きさに応じてグッと大きく増加してくれる、というわけです。この仕組みのおかげで、高速スケーリングを実現しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/28ce74f3-b9c2-ca31-0e99-082dcca2f638.png)

## 3.2 serverlessのメリット
- PCUの範囲とインスタンス数の範囲を指定しておけば、負荷に応じたスケーリングをよしなにやってくれるため、capacity計画などの運用コストが若干低くなります。
- Provisoned instanceはインスタンスタイプによる課金であるのに対し、Serverlessでは秒単位の利用数がメインとなり、Serverlessのほうが（使い方にもよりますが）大抵の場合コスト効率がよく、低い料金で利用できます。

## 3.3 利用シーン
1. 不定期使用のアプリケーション
    - 例：社内でのみ使うアプリケーションであり、基本的に平日＆日中のみ稼働する場合は、自動起動・シャットダウンできればかなりコスト削減できる見込み
1. 可変・予測不能なワークロード(オートスケール狙い)
1. 開発やステージング環境
::: note info
本番環境でもほとんどのケースでは十分に利用できるレベルになっていたと言われていますが、瞬時的にトラフィックが大きく増加している時にスケーリングが間に合わなくて、数秒で想定した性能がでない場合もありうるため、しっかり負荷テストをして、性能を評価することをお勧めします。
:::

## 3.4 料金
| Left align | Provisioned | Serveless |
|:-----------|------------:|:------------:|
| computing| 0.124$/時間 <br> (g2.medium: 2 cores + 4GB memory) | 1PCU 0.0977$/時間 * 2 = 0.1954$/時間|
| Proxy     | 無料      | 1PCUあたり 0.0489$/時間       |
| storage       | 0.000552 USD/GB/時間        | 同様        |
| I/O         | 無料          | 無料           |


https://www.alibabacloud.com/help/en/polardb-for-mysql/latest/billing-rules-of-pay-as-you-go-compute-nodes

https://www.alibabacloud.com/help/en/polardb-for-mysql/latest/billing-of-serverless-clusters

■ 料金計算の例
・1ヶ月間の料金(以下の金額は全部米ドルで計算)
・メモリ最大16G
・ただし、常に16Gのメモリを使うわけではない。
・1日のうち4時間は16G(8PCU)、8時間は2G(1PCU)の処理を行い、それ以外は処理しないと想定する。

- Provisioned型の場合
    - polar.mysql.mmg4.xlargeを選ぶこととする。
    - 0.982 × 24時間 × 30日 = 707.04

- Serverless型の場合
    - 最小PCUを2、最大PCUを8とする。
    - (0.0977$ + 0.0489$) × 8PCU × 4時間 = 4.6912
    - (0.0977$ + 0.0489$) × 2PCU × 8時間 = 2.3456
    - (4.6912$ + 2.3456$) × 30日 = 211.104


## 3.5 気をつける点
- 対応バージョン
    - 現時点では`MySQL 8.0`と `MySQL 5.7`しか対応できていない。
    - これからPostgreSQLも対応できるようになるそうです。

# 4. PolarDB Serverlessを使ってみる
## 4.1 新規作成
- read-only nodeの数と 一つのnodeのPCU数を設定
    - read-only node数の範囲： 0 ~ 15個
    - 一つノードのPCU範囲： 1 ~ 32 PCU(今後64, 128にも拡張できるようになるようです。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/f4446ad0-191d-249e-cbee-0ff8496d13c4.png)

- 完全停止するかどうかを設定
    - デフォルトはoffになっています
    - onにする場合は、さらに検出の時間間隔を設定します。(その時間以内にアクセスが来なければ、cluster全体が停止になる。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/31063e9a-d7f9-5fc6-bc0b-96374ec1ae5f.png)
- 作成できたserverlessのcluster
    - `Minimum Read-Only Node`数を1に設定したため、read-only node + primary nodeは合計2つノードがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/79e4fbb2-ecf9-2378-fe88-b087ffb048b7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/aa44c397-b7ee-1667-4921-14e7efb94410.png)
- 既存のインスタンスに対して、アクセス来ない場合は、完全停止にさせる方法：
新規作成する時に、完全停止をONにしていない場合は、インスタンス作成後でも変更可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/35762e10-a733-d52e-923e-cc61c5746d6b.png)


## 4.2 read-only node数を減らしてみる
- 以下の`Serverless`のボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/f90eefee-ef79-c5ab-dbac-059d563f52d0.png)
- 最大read-only node数と最初read-only node数両方を0に変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/10770c46-6a79-423e-cb6f-8198bdcb63fb.png)
- read-only nodeが削除されている最中
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/8a679056-ce04-8443-a358-f128c2b71fe8.png)
- read-only nodeが削除されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/1c4a0cf4-73bb-25f1-d928-1542068f128b.png)


## 4.3 完全停止から起動
- 一定時間以内にアクセスこなければ、clusterが完全停止になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/49d2b934-91e9-441e-1446-b8c789e7abf5.png)
- 手動起動と自動起動両方可能です。
    - 手動起動：　cluster一覧画面で、該当のclusterを選択して、`Start Cluster`ボタンをクリックして、起動する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/38b3e8db-844c-973b-2d27-3be2486f4d34.png)
    - 自動起動：コマンドラインから接続してみると、だいたい10秒程度経ってから結果が戻ることがわかりました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/15429021-185c-98f4-b3cc-5a1d8116b2a8.png)

## 4.4 負荷をかけてみる
### 実行前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/5a44f99a-d55a-9b11-c831-b2ce8f8180c8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/4a3f8db6-070a-45b5-d2e7-38e2dae18931.png)

### sysbenchで負荷テスト用のデータを準備
- データをinsertする時にCPU使用率が高くなると、PCUが上がることがわかります。
```
DBHOST= ***
DBPASS= ***
DBUSER= ***
echo 'CREATE DATABASE benchmarktest' | mysql -h ${DBHOST} -P 3306 -u ${DBUSER} -p

sysbench --db-driver=mysql \
      --mysql-host=${DBHOST}  \
      --mysql-user=${DBUSER} \
      --mysql-password=${DBPASS} \
      --mysql-db=benchmarktest \
      --table_size=50000000 \
      oltp_read_write \
      prepare
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/17044c1c-0b79-2eb0-a897-56e97d14afbf.png)

::: note info
- sysbenchを実行するために、Alibaba Cloud上でPolarDB Serveless instanceと同一VPC、どういつAZのsubnetを使っている[ECS](https://qiita.com/jobbin/items/6c232daf585c361c6a9f)(仮想サーバーのサービス、AWSでいうとEC2になります)を利用することがお勧めです。ローカルPCあるいは異なるAZ上のECSインスタンスからテストすると、ネットワークがボトルネックになりがちで、Serveless instanceのCPUの負荷がなかなか上がらないため、結果的にはscale up(PCU数の増加)がなかなか観測しにくいということです。
- 以下のテストではECS `ecs.g7.6xlarge`(24vCPU,96 GiBメモリ)のインスタンスを使っています。

:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/02f520c9-590e-044e-bf12-08d109b590a2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/9b72a710-2e14-b90d-6edf-c8e1b92df2f6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/f0f8525c-93e0-0b9c-1486-d6a9ce5aafc4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/d76d4d89-6b72-b0ea-cb5a-5f6c7db6ab1c.png)

### 実行時
- 実行コマンド
```
sysbench --db-driver=mysql \
      --mysql-host=${DBHOST}  \
      --mysql-user=${DBUSER} \
      --mysql-password=${DBPASS} \
      --mysql-db=benchmarktest \
      --time=600 \
      --threads=100 \
      --range_selects=off \
      --db-ps-mode=disable \
       --report-interval=10 \
      oltp_read_write \
      run
```
- 実行結果
    - コマンドラインから10間隔でtps, qpsなどがかんたんに確認できる。
    - Servless instanceのCPUが食われると、PCUが自動的に上がることが観測しやすいため、PCUが変わらない場合は、`time`と`threads`を調整してみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/2a4897b8-87e0-b859-c1f7-8ea31981e286.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/84c30b72-30b4-a6da-018c-3ae75b18bed4.png)

- 監視メトリックス：
    - CPU使用率,QPS,TPSなどのメトリックスの変化はPCUの数の変化とだいたい同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/11e03db5-6a76-9e49-8625-ef85db828fee.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/3f2065fc-18b8-2072-5939-a0910f45d814.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/75135a89-114d-52ee-fe46-8d1dbdb44d0f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/dad65abb-60f7-c146-4eb8-9b5defd9b546.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a8094d5b-9ca0-bb4e-f461-e1b0272d4055.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/723e8ff0-7b97-e715-be7b-efe1dfa1cf12.png)

- scale upとCPU上昇とのタイムラグを確認してみる
    - 詳細なタイムラグを確認しやすくためには、まず監視データ表示の時間間隔をデフォルトの60Sから5Sに変更する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/fc1401ec-ca90-3878-6095-d6c8cb4ce70e.png)
- 5秒単位で確認する場合は、ほぼscale upとCPU上昇はほぼ同じペースで変化しているため、タイムラグは5秒以内であることが言えそうです。
::: note info
追記： 
- PolarDBの開発チームに確認したところで、やはりscale upのタイムラグは平均で10秒前後です。
- テストの結果は5秒ぐらいもありましたが、必ず５秒とは保証できないようです。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/95b01a90-69fd-012a-c0f7-20e6245d59b6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a891d3f3-b450-e587-babc-6dbde7c8c4df.png)

# 5. まとめ
- 「PolarDB Serverlessは、DBの負荷に応じたスケーリングを自動で行ってくれます。そのため、これまで必要だったDBのキャパシティ計画や手動でのスペック変更といった運用が不要になり、専門のDBAがいなくてもデータベースの運用が容易になります。
- DBへのアクセスが変動する利用シーンでは、従来のプロビジョンドインスタンスに比べてコストが半分以下になることも多いです（利用方法によります）。
- CPUやメモリの変化に応じた自動スケーリングは、`5秒以内`に行えるそうです。開発環境やテスト環境、社内環境などの負荷の低いワークロードだけでなく、変動の多い本番環境にも十分対応できるレベルになっています。

# 6. Q＆A
1. Q：スケールインあるいはスケールダウンする時に、既存のコネクションや実行しているトランザクションに影響がありますか。
A：既存のコネクションや実行しているトランザクションに影響がありません。
最大コネクション数を超える新しいコネクションで接続しようとすると、エラーになります。

1. Q：　手動によるノードの追加や削除やノードのスペック変更ができますか。
A: そもそもServerlessのコンセプトとしては自動scalingすることでコスト削減と運用保守に必要な人的なリソース削減するため、手動変更はできません。

1. Q：CPUやメモリなどの使用率を設定することによって、スケーリングのタイミングを制御することができますか。
A： 手動で制御できません。　ServerlessはCPU、メモリ、コネクション数の変化を総合的に見て、スケーリングのタイミングを自動制御する仕組みです。
この仕組はこれからも徐々に改善しづつ、最適化することになります。

1. Q: 既存のProvisoned instanceをどうやってSevervlessに変更できますか。
A: 現在は新しいSevervles instanceを作成して、Alibaba Cloudの`DTS`サービスを利用して、データをProvisoned instanceからSevervles instanceに移行するという方法があります。この方法はちょっと手間掛かりそうです。
これからは以下の２つ方法も計画しているようです。
    - 既存のProvisoned instanceをかんたんに(コンソール画面上で直接変更)変更できること
    - Provisoned instanceのsnapshotを作成して、snapshotからSevervles instanceを作成すること

1. Q: 今現在消費されているPCU数をどうやって確認できますか。
    - 方法１： clusterの監視ページでPCU数やCPUとメモリの使用率などのメトリック数が確認できる。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/6efb6788-35b8-9aa5-e67d-589f40eb0c73.png)

    - 方法２： Billing Managementで一時間単位で各リソースの消費状況も確認できます。

1. Q: 完全停止期間内では、本当にリソース(PCU)を消費しないのですか。
A: その通りです。

1. Q: 垂直スケーリング(scale up/down)と水平スケーリング(scale out/in)は順番ありますか。
A：まず垂直スケーリングを行い、一つのノードだけでは対応しきれなくなった場合に、次に水平スケーリングを行う。

1. Q: Serverless instance と Provisoned instanceをどう使い分けしますか。
    - Serverless instance：変動のあるworkloadに適しています。
    - Provisoned instance：
    安定したworkloadに適しています。メモリサイズ、CPU パワー、I/O 帯域幅などが事前定義された DB インスタンスクラスを選択します。ワークロードが変更された場合、ライターとリーダーのインスタンスクラスを手動で変更します。クラスター内のライターとリーダーのインスタンスクラスを変更しながら、短時間の停止の発生が許容される場合は有効に機能します。

1. Q: Serverless instanceの最大ストレージ容量？
A: 必要の分に応じて完全に自動拡張し、最大のストレージ容量はインスタンスのスペック(ACU数)と関係なくて、一律100Tです。
:::note info
Provisoned instanceでは最大ストレージ容量がインスタンスのスペックと関係があります。
:::

https://www.alibabacloud.com/help/en/polardb-for-mysql/latest/specifications-of-compute-nodes#concept-2035312