RDSのインスタンスクラスごとのメモリ量を取得するterraform providerを作った

github.com

これはなに?

RDSのインスタンスクラスごとのメモリ量を習得するterraform provider。

インスタンスクラスごとにデータソースを定義するか、

data "rds_db_instance_memory" "rds" {
  instance_class = "db.t3.micro"
}

#=> {
#     "instance_class" = "db.t3.micro"
#     "memory" = 1
#   }

インスタンスクラスごとのメモリ量のマップを定義するデータソースを使って、メモリ量を取得できる。

date "rds_db_instance_memory_map" "rds" {
}

#=> {
#     "memory_by_instance_class" = tomap({
#       "db.m1.large" = 7.5
#       "db.m1.medium" = 3.75
#       "db.m1.small" = 1.7
#       ...
#     })
#   }

あと、クラスタインスタンスも合わせたすべてのDBインスタンスインスタンスクラスを取得するデータソースも追加した。

data "rds_db_instances" "rds" {
}

#=> {
#     "instances" = tolist([
#       {
#         "instance_class" = "db.t3.micro"
#         "name" = "database-1"
#       },
#       {
#         "instance_class" = "db.t3.small"
#         "name" = "database-2"
#       },
#       ...
#     ])
#   }

用途

terraformでDatadogのアラートを設定するときに、メモリ使用量の閾値をパーセンテージで設定したいときとかに使う想定。

RDS情報の取得先

instances.vantage.sh

Vantageというクラウドコストの最適化サービスをやっている会社のOSSのよう。

https://instances.vantage.sh/rds/instances.json からJSONでRDSの情報を取得できるので

curl -sSfL https://instances.vantage.sh/rds/instances.json \
| jq 'map({key: .instanceType, value: .memory | tonumber}) | sort_by(.key) | from_entries'

とやってインスタンスクラスごとのメモリ量のJSONを生成している。

クエリログを使ったPostgreSQLの負荷テスト

クエリログ

log_statement=allを設定するとpostgresql.logにクエリログされる。

$ cat postgresql.log
2022-05-30 04:59:41 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG:  statement: select now();
2022-05-30 04:59:46 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG:  statement: begin;
2022-05-30 04:59:48 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG:  statement: insert into hello values (1);
2022-05-30 04:59:50 UTC:10.0.3.147(57382):postgres@postgres:[12768]:LOG:  statement: commit;
...

これを自作のツールposlogでndjsonに変換。 log_min_duration_statementで出力されたログもパースできた…はず。

github.com

$ poslog postgresql.log > data.jsonl
$ cat data.jsonl
{"Timestamp":"2022-05-30 04:59:41 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" select now();"}
{"Timestamp":"2022-05-30 04:59:46 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" begin;"}
{"Timestamp":"2022-05-30 04:59:48 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" insert into hello values (1);"}
{"Timestamp":"2022-05-30 04:59:50 UTC","Host":"10.0.3.147","Port":"57382","User":"postgres","Database":"postgres","Pid":"[12768]","MessageType":"LOG","Duration":"","Statement":" commit;"}
...

-fingerprintオプションを付けるとpt-fingerprintのようなinsert into hello values(?+);という感じのFingerprintフィールドも付与される。 「SELECTだけ」みたいなテストデータのフィルタリングに使えると思う。 あとは、似たようなクエリの集計とか。

また、-fill-paramsを付けるとStatementフィールドのプレースホルダ$1 $2…が実際の値で置換される。*1

負荷テスト

自作のツール qrn を使って、上記ndjsonをテストデータとした負荷テストを実行できる。

https://github.com/winebarrel/qrn

こんな感じ。

qrn -dsn "postgres://pgx_md5:secret@localhost:5432/pgx_test" \
  -data data.jsonl -rate 5 -time 300 -nagents 10

上の場合、5エージェント(ユーザー)で5分間、エージェントごとに5 qpsでDBに負荷を与える。

トランザクション

テストデータを複数与えるとエージェントごとに異なるテストデータを実行できるが、簡易化のために -commit-rate というオプションを用意していて、エージェントがNクエリ実行するごとにcommit; beginを実行して新しいトランザクションを開始することができるようにしている。

*1:適当なテキストの置換なのでプレースホルダー以外の$1を含むクエリだとうまく置換できないかも

ridgepoleのパーティショニング対応を削除することを考えています

ridgepoleの1.0.2でパーティショニングの対応が入ったのですが、これを削除することを考えています。 理由としては、パーティショニングの機能は多岐にわたりそのすべてをサポートするのは難しいのですが 現状では本体に密結合になっているため、オプショナルな動作にすることができず、 サポートされていない機能を使おうと思うとridgepoleそのものが使用不可になる状態のためです。

オプショナルな動作にするための改修を進めたいのですが、ちょっと時間がとれず いったんすべてをrevertすることを考えてます。

6月中にはなにか対応入れます

PR: https://github.com/ridgepole/ridgepole/pull/392

追記

RDS(PostgreSQL)のクエリログの有無によるpgbenchの差異

RDS(PostgreSQL)でクエリログをON(log_statement=all)・OFF(log_statement=none)、さらにexportしたときの性能の変化が気になったので、pgbenchで負荷テストを行ってみた。

テスト環境

クライアント

#!/bin/bash
echo "$(date +%FT%TZ): start"

for i in 64 128 192 256; do
  echo "$(date +%FT%TZ): $i"
  pgbench -q -i -s 100
  sleep 10
  pgbench -c $i -T 180

  if [ $i -ne 256 ]; then
    sleep 60
  fi
done

echo "$(date +%FT%TZ): end"

サーバ

  • PostgreSQL 12.8
  • m4.2xlarge(都合により旧世代…)
  • Parameter Groupはデフォルトからlog_statementだけ変更
  • Encryption有効
  • Performance Insights有効
  • Enhanced Monitoring有効
  • Multi-AZ
  • ストレージはgp2/500GB

結果

docs.google.com

tps

latency

CPU使用率

Performance Insights

log_statement=none

log_statement=all

log_statement=all (export)

参考リンク

MySQLでTPC-B likeなテストを実行するツールを作った

MySQLでpgbenchと同じようなTPC-B likeなテストを実行するツールを書いた。

github.com

これは何?

pgbenchと同様のtcpb-likeなテストを実行する負荷テストツール。

github.com

pgbenchとだいたい同じSQLが実行されると思うが、TPC-Bの仕様をきちんと満たしているかは不明。

先日の記事MySQLでの同様のテストを行った場合の結果が気になったので作成してみた。 初期データの投入が遅かったりバグがなにかありそうだけれど、とりあえず簡単なテストではうまく動いた。

使い方

READMEにあるとおりで、pgbenchと似たような感じで使える。

$ qb -d root@/ -i -s 10
dropping old database...
creating database...
creating tables...
generating data...
analyzing tables...

$ qb -d root@/ -n 10
01:00 | 10 agents / run 2603958 queries (2559 tps)

{
  "DSN": "root@/",
  "StartedAt": "2022-05-08T17:36:46.173678+09:00",
  "FinishedAt": "2022-05-08T17:37:46.177411+09:00",
  "ElapsedTime": 60,
  "NAgents": 10,
…

PostgreSQLMySQLのきちんとした性能の比較にはならないが、同様のテストを両方で実行したい向きには手軽だと思う。

その他

かるーくMySQLエンジンでAuroraとRDSの比較を行ったが、PostgreSQLほど性能に差異がない感じだった。 追記型アーキテクチャはAuroraと相性悪いのかなぁ…よくわからない。

PostgreSQLエンジンでのAuroraとRDSのベンチマーク

PostgreSQLエンジンでAuroraとRDSでpgbenchを使った負荷テストを行った。

テスト環境

クライアント

#!/bin/bash
. .rds
for i in 8 16 32 48 64; do
  echo "--- $(date +%FT%TZ) RDS $i"
  pgbench -i -s 100 -q
  pgbench -c $i -T 210
  sleep 60
done
echo "--- $(date +%FT%TZ) RDS end"

サーバ

  • PostgreSQL 13.6
  • インスタンス数はそれぞれ1台ずつ(冗長化なし)
  • Parameter Groupはデフォルト
  • クライアントインスタンスと同じAZ
  • Encryption有効
  • Performance Insights有効
  • Enhanced Monitoring有効
  • ログはエクスポートしていない
  • RDSのストレージはgp2/1000GB

結果

docs.google.com

tps

latency

CPU使用率

Performance Insights(それぞれdb.r6.2xlarge)

RDS

Aurora

雑感

  • 実際のワークロードに合わせたテストでないとプロダクション投入時の性能はなんともいえないと思う…と前置きしつつ
  • Auroraのtps限界が想定よりずいぶん低い
  • Auroraには可用性やフェイルオーバーの速さなどのメリットがあるが、うーん…
  • Auroraのアーキテクチャ的に細かいトランザクションが多いワークロードでは遅くなりそうな気はする
  • ただ、MySQLエンジンではこんなワークロードでもAurora > RDSだったのでPostgreSQLエンジンでも同様だと思っていた
  • Googleで調べた感じAuroraのほうがtpsが高い結果が見られるので、なにか設定を間違えている気もする…
  • インスタンスクラスをもっと大きくしたら結果が違うのかもしれない
  • RDSのストレージサイズによる性能の違いも調べたいところ

参考リンク

追記

RDSがSingle-AZだったのでMulti-AZで追試。

tps

latency

CPU使用率

Performance Insights(db.r6.2xlarge)

追記2

MySQLエンジンでTPC-B(tpcb-like)を軽く検証したので、結果を張っておく。

ツールが違うのでPostgreSQLエンジンの値とは直接比較できない点に注意のこと