運用から見る逆引きRDS for PostgreSQL

本記事は [PostgreSQL Advent Calendar 2018](https://qiita.com/advent-calendar/2018/postgresql) の5日目の記事です。

# 記事を書いた背景

* 理由
  * [AWS RDS for PostgreSQL](https://aws.amazon.com/jp/rds/postgresql/)がリリースされてから数年が経ち、PostgreSQLのクラウド運用が増えているため
  * クラウドは便利で多機能だが、やりたいことの情報にたどり着くのが大変なため
* 上記のことから(自分含め)逆引き辞典があれば便利かもと思った次第です

# 前提条件

* 本記事の情報は執筆日(2018/12/01)現在のものです
* PostgreSQL以外の汎用的な話もあります

# 運用逆引き索引

## PostgreSQLをデプロイしたい

PostgreSQLをデプロイするには[CreateDBInstance API](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)を発行します。この時`Engine`パラメータを`postgres`にしてください。
またAWSコンソールからポチポチするだけで簡単にデプロイできます。(以降のAPI操作も大体コンソールからできます)

### 冗長構成を組みたい

[CreateDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)の`MultiAZ`パラメータを`True`にすることで冗長構成にできます。
MultiAZにすることでZoneレベル(データセンターレベル)の完全冗長性が担保されます。
また、障害時に待機系が昇格してきた時はエンドポイント(CNAME)が自動で切り替わります。
そのため、アプリケーションからCNAMEにアクセスすることで障害時も自動復旧できます。

### 既にあるPostgreSQLから移行したい

以下のような手段があります。

* PostgreSQLの機能を使って移行する
  * `pg_dump` -> `pg_restore`
  * `\copy to` -> `\copy from`
* AWSの機能を使って移行する
  * [AWS DMS](https://aws.amazon.com/jp/dms/)
     * 最近某社が実運用に基づいたスライドを公開していたので興味がある方は調べてみてください

詳細はAWSのページにも紹介されています
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/PostgreSQL.Procedural.Importing.html

PostgreSQLのデータインポート時は以下の点に注意してください。

* DBインスタンスのバックアップを無効にしてください。
* `MultiAZ`を`Fales`(無効)にしてください。

これはインポート速度の向上=不要なお金をかけないためだと思います。
インポートの高速化の要因は

* バックアップを無効=WALの書き出しがなくなるため
* `MultiAZ`を止めると書き出し量が1/2になるため

大量データの高速投入は以下の記事が参考になります。
https://lets.postgresql.jp/documents/technical/bulkload/1

### バージョンを指定したい

[CreateDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)の`EngineVersion`パラメータを指定します。
執筆日現在の最新サポートバージョンはv10.5です。(v11もプレビュー版があるので時間の問題だと思います)
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts

### アクセス制限をしたい

[SecurityGroup](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_AuthorizeDBSecurityGroupIngress.html)を利用してCIDRIPかSecurityGroupを指定して制限をかけます。
PostgreSQL自身は`pg_hba.conf`ファイルで制限をかけますが、RDSはOSにアクセスできないのでSecurityGroupを利用します。

## バックアップを取りたい

バックアップはDBMS運用の宿命であると言えます。
PostgreSQLでは以下のようなバックアップ手法がとられます。

* `pg_dump` or `pg_dumpall`
* 物理バックアップ
* `pg_rman`
    * http://ossc-db.github.io/pg_rman/index-ja.html 
* etc...

RDSでも`pg_dump`などを用いてバックアップを取得できます。
しかし、RDSはバックアップも強力にサポートしています。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_WorkingWithAutomatedBackups.html

### 自動でバックアップをとりたい

[CreateDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)の`BackupRetentionPeriod`パラメータを`1`以上にしてください。
これでパラメータ日数分のバックアップを自動で取ります。
自動バックアップには以下のような特徴があります。

* 通常5分以内までのバックアップが常に取得されます。
* 1日に1度DBインスタンス全体のバックアップを取得します。
  * MultiAZ構成をとっていないとI/Oの瞬断があるので`PreferredBackupWindow`でバックアップの時間を調整できます。
* 指定した日数を過ぎるとバックアップは順次削除されてしまうことに注意してください。
  * 静止点を残しておきたい場合は[手動でバックアップを取得](#手動でバックアップをとりたい)してください。

[リストア方法](#自動バックアップからリストアしたい)は後述します。

### 手動でバックアップをとりたい

[CreateDBSnapshot](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBSnapshot.html)、または`pg_dump` or `pg_dumpall`を使用してください。
OSにアクセスできないため、物理バックアップは手動で取得できません。

## バックアップからリストアしたい

バックアップを取得するだけでは運用としては不十分です。
リストアができて初めてバックアップができていると言えます。
PostgreSQLでは以下のようなリストア方法があります。

* `pg_restore`
* 物理バックアップからのリストア
    * `recovery.conf`を利用したPoint In Time Recovery(PITR)

RDSで取得したバックアップは簡単にリストアができます。
リストアすることで新しいDBInstanceが生成されることに注意してください。

### 自動バックアップからリストアしたい

[RestoreDBInstanceToPointInTime](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_RestoreDBInstanceToPointInTime.html)を利用します。
自動バックアップ元は`SourceDBInstanceIdentifier`パラメータでDBInstanceのIDで指定し、`RestoreTime`パラメータで任意の時間の状態にリストアできます。

### 手動バックアップからリストアしたい

[RestoreDBInstanceFromDBSnapshot](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html)を利用します。
`DBSnapshotIdentifier`パラメータでDBSnapshotのIDを指定します。

## バージョンアップしたい

運用中に悩まされるのがPostgreSQLのバージョンアップです。
簡単にはできないですし、`pg_upgrade`などの様々な検証が必要です。
RDSはメジャー/マイナーバージョンアップグレードをサポートしています。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.PostgreSQL.html

### メジャーバージョアップしたい

[APIを使って手動でメジャーバージョンを上げます。](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.PostgreSQL.html#USER_UpgradeDBInstance.PostgreSQL.MajorVersion)
[ModifyDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)の`EngineVersion`パラメータを変更します。
この時パラメータグループに互換性のないパラメータがあるとDBInstanceが起動しないため、十分な検証をしてください。

### マイナーバージョンアップしたい

マイナーバージョンはRDSで試験されており、自動でアップグレードできます。
[CreateDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)の`AutoMinorVersionUpgrade`を`True`にしてください。

## 死活監視をしたい

RDSサービスが死活監視をするのでユーザで監視する必要はありません。
一般的には`Zabbix`や`mackerel`などの監視ソフトウェアで監視したり、`SELECT 1`を打ったりなど...その手間がありません。

## 性能監視をしたい

PostgreSQLの性能監視は様々な手法があります。

* 監視ソフトウェア
    * `pg_statsinfo`  
    http://pgstatsinfo.sourceforge.net/documents/statsinfo3.2/pg_statsinfo-ja.html
* 自前スクリプトで取得
* etc...

### マシンリソース情報を取りたい

RDSは[CloudWatch](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/MonitoringOverview.html)を使って自動的に収集します。
コンソールから簡単に確認できます。
また、CloudWatchで閾値を設定することでアラートを飛ばせます。

### Slow Queryを知りたい

一般的なPostgreSQL運用と同様に`log_min_duration_statement`をパラメータグループで設定します。
遅いクエリはコンソールのログから確認できます。

## 性能を上げたい

RDBMSの性能が足りなくなった場合、スケールアップやチューニングやクエリの改善などで対応します。
RDSはクラウドサービスのため、スケールアップの選択肢を簡単に取れます。

### CPU & メモリを増設したい

[ModifyDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)の`DBInstanceClass`パラメータを変更します。
[DBInstanceの性能](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html)は幅広く揃えられています。
しかし、執筆時は最新の`db.m5`世代にPostgreSQLが対応していません。
(個人の見解ですが、MySQL, MariaDB, Oracleが最初に対応されるイメージがあります。)

### IO性能をあげたい & ディスク容量を増やしたい

ディスク性能はディスクの大きさに比例します。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_Storage.html#Concepts.Storage.GeneralSSD
> ボリュームが 100 GiB のベースラインパフォーマンスは 300 IOPS、ボリュームが 1 TiB の場合は 3000 IOPS となります。3.34 TiB 以上のボリュームのベースラインパフォーマンスは 10,000 IOPS です。

ただし、一時的な負荷の場合はバーストして性能を担保する機能があります。
> 1 TiB 未満のボリュームサイズでも、長期間にわたって 3000 IOPS をバーストする性能があります

変更する場合は[ModifyDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)の`AllocatedStorage`パラメータを設定します。

また、それ以上の性能を担保したい場合はPorvisionedIOPSを利用してください。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_Storage.html#USER_PIOPS
変更する場合は[ModifyDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)の`StorageType`パラメータを`io1`にして`Iops`パラメータを設定します。

## パラメータをチューニングしたい

PostgreSQLのパラメータチューニングは[パラメータグループ](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html)で設定できます。
DBInstanceとParameterGroupはN:Mで紐づくので、[作成したパラメータグループ](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBParameterGroup.html)を[ModifyDBInstance](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)の`DBParameterGroupName`で設定します。
実際の`postgresql.conf`の値は[ModifyDBParameterGroup](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_ModifyDBParameterGroup.html)でパラメータグループに設定します。

## 拡張機能を使いたい

PostgreSQLには多くの拡張機能があります。
残念ながらマネージドサービスであるRDSでは制限がかかります。
また、OSにログインできないのでユーザによる拡張もできません。

### 手続き言語を使いたい

手続き言語は各種対応しています。
https://aws.amazon.com/jp/rds/postgresql/
> PostgreSQL には 4 つの言語拡張が含まれており、Perl、pgSQL、Tcl、および JavaScript (V8 JavaScript エンジンにより) がサポートされます。

純正のPostgreSQLとは少し品揃えが違うことに注意してください。
https://www.postgresql.jp/document/10/html/server-programming.html

### 拡張機能を使いたい

RDSは様々な拡張機能をサポートしています。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeaturesExtensions
PostGISをサポートしていますが、contrib全てはサポートしていません。
利用するDBInstance内でコマンドを打つと対応拡張機能のリストが出てきます。

```sql
SHOW rds.extensions; 
```

## レプリケーション構成(参照分散)をとりたい

[CreateDBInstanceReadReplica](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_CreateDBInstanceReadReplica.html)を発行することで冗長化とは別に参照分散用のリードレプリカを作成できます。

# 最後に

* 間違っていたり、もっとよい方法があれば教えて欲しいです👏
* 明日は @kaigai さんの担当になります🙏