ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

AWS RDS の Max Connections を Prometheus 形式で Export する OSS を作って current connections / max connections 比率でアラートを出す

作った。

github.com

これは何か

RDS の設定値、max_connections は PostgreSQLMySQL ともにある。接続数がこの数値を超えるとエラーとなるため、この数値を超えないように監視できることが望ましい。

しかしこの max_connections、RDS の parameter group の value の1つであり、cloudwatch metrc に存在しない。そのため Datadog Integration でも取ることができない。

というわけでそれを取って Prometheus 形式で Export することにした。

なお、現在の接続数 database_connections は取れる。

docs.datadoghq.com

これとの比で、例えば9割になったら Alert みたいなことができるようになって便利。

また、新規サービスリリース前に Production Readiness Checklist でも DB の接続数大丈夫?みたいな項目があるが、それを減らすことができる。

結果

こんな感じ。まぁ Maxcon を可視化しても全然面白くはない。そうそう変わるもんではないしね。Datadog 上に metric として値が欲しかっただけである。

f:id:take_she12:20210209040027p:plain

アラート

ここで気づくが、aws.rds.database_connections はよしなにタグに値をつけてくれるが、この Exporter でもつけている、DB Instance Identifier と DB Instance Class の Key 名を合わせないと Alert が作れない。

雑に GitHub で調べると、付与されるタグはこのように決まっていることがわかる。

github.com

RDS auto_minor_version_upgrade、dbinstanceclass、dbclusteridentifier、dbinstanceidentifier、dbname、engine、engineversion、hostname、name、publicly_accessible、secondary_availability-zone

snake case かと思ったらそうでもなかったりしてポリシーがよくわからないが、とにかく同じ tag として扱いたければ dbinstanceclass dbclusteridentifier に変える必要があった。

タグさえ一致させればこんな風に欲しい値が手に入った。

f:id:take_she12:20210209044016p:plain

こんな感じで monitor を作る。

f:id:take_she12:20210209044531p:plain

いったん低めの8割で作った。

課題

Issue にあげているが、、、

Max Connection の値の確からし

一応 autora-postgresql の場合、デフォルトは以下のような計算式で max connections は決まる。

Aurora PostgreSQL: "LEAST({DBInstanceClassMemory/9531392},5000)"

ただ、この計算式がイマイチ実際の default と違うような予感がしているので、要検証だと思っている。

ちなみにこの default 値の場合の instance class に対する maxcon はこのように map を持っている。

github.com

   auroraPostgresMaxcon := map[string]int{
        "db.r4.large":    1600, // Memory  15.25 GB
        "db.r4.xlarge":   3200, // Memory  30.5  GB
        "db.r4.2xlarge":  5000, // Memory  61    GB
        "db.r4.4xlarge":  5000, // Memory 122    GB
        "db.r4.8xlarge":  5000, // Memory 244    GB
        "db.r4.16xlarge": 5000, // Memory 488    GB
        "db.r5.large":    1800, // Memory  16    GB
        "db.r5.xlarge":   3600, // Memory  32    GB
        "db.r5.2xlarge":  5000, // Memory  64    GB
        "db.r5.4xlarge":  5000, // Memory 128    GB
        "db.r5.8xlarge":  5000, // Memory 256    GB
        "db.r5.12xlarge": 5000, // Memory 384    GB
        "db.r5.16xlarge": 5000, // Memory 384    GB
        "db.r5.24xlarge": 5000, // Memory 768    GB
        "db.m4.large":    900,  // Memory   8    GB
        "db.m4.xlarge":   1800, // Memory  16    GB
        "db.m4.2xlarge":  3600, // Memory  32    GB
        "db.m4.4xlarge":  5000, // Memory  64    GB
        "db.m4.10xlarge": 5000, // Memory 160    GB
        "db.m4.16xlarge": 5000, // Memory 256    GB
        "db.m5.large":    900,  // Memory   8    GB
        "db.m5.xlarge":   1800, // Memory  16    GB
        "db.m5.2xlarge":  3600, // Memory  32    GB
        "db.m5.4xlarge":  5000, // Memory  64    GB
        "db.m5.8xlarge":  5000, // Memory 128    GB
        "db.m5.12xlarge": 5000, // Memory 192    GB
        "db.m5.16xlarge": 5000, // Memory 256    GB
        "db.m5.24xlarge": 5000, // Memory 384    GB
        "db.t2.micro":    125,  // Memory   1    GB
        "db.t2.small":    250,  // Memory   2    GB
        "db.t2.medium":   450,  // Memory   4    GB
        "db.t2.large":    900,  // Memory   8    GB
        "db.t2.xlarge":   1800, // Memory  16    GB
        "db.t2.2xlarge":  3600, // Memory  32    GB
        "db.t3.micro":    125,  // Memory   1    GB
        "db.t3.small":    250,  // Memory   2    GB
        "db.t3.medium":   450,  // Memory   4    GB
        "db.t3.large":    900,  // Memory   8    GB
        "db.t3.xlarge":   1800, // Memory  16    GB
        "db.t3.2xlarge":  3600, // Memory  32    GB
    }

これが多分ちょっとあやしいので確認したい。

RDS MySQL / Aurora MySQL サポート

現状していない。

やればできると思うが、こいつらの Default もまぁ結構キモい。特に Aurora MySQL。どうしてそうなったんだろう。

Aurora MySQL: "GREATEST({log(DBInstanceClassMemory/805306368)*45},{log(DBInstanceClassMemory/8187281408)*1000})"
RDS MySQL: {DBInstanceClassMemory/12582880}

正規表現マッチやってやれないことはないけど、log とかなんとか言ってるしマジ。まぁ結局 default の場合結果の値は static に持つのだけれども。

驚いたこと

max_connections は cluster parameter group と db parameter group 両方で設定できる

max connections は実は cluster parameter group と db parameter group 両方で設定できるのだが

あとに設定したほうが有効になるということ。知らんわ。

今回作った Exporter は DB Instance の Parameter Group を describe しているので、cluster parameter group にだけ設定しているパターンだと正しい値が取れないです。

Default はインスタンスクラスによって決まるが、それを静的な値で上書きできる

なんか全部 max はこれで決まるかと思ったけど、fixed value を入れることもできる。

そうしている場合はそちらが値に入ってるので、素直にそれを使うようになっている。

感想

Database Instance を for でぶんまわしたあとインスタンスごとに db parameter group を describe するので、loop の頻度によっては結構すぐに rate limit に達してしまう。DB Instance、いま動かしている環境だと 90 なんだけど、1分おきでたかだか3周とかで rate limit に達してたので、270 / 3min でアウトは厳しすぎない?あと rate limit 各サービスによって違うので結局調べても正しい値にたどり着けなかった。

コード的には parameter group value が default だと LEAST({DBInstanceClassMemory/9531392},5000) こういう式が、それ以外だと static に fixed value もとりうるというところがだいぶキモかった。計算式はわかったんだけど default は素直に計算された値を parameter group の value にいれといて、、、と思った。そうすれば今回書いたような map を持つ必要はなかった。

おわりに

これで aws.rds.database_connections の anormary のアラートで、接続数が少ない DB で false positive が起きてたのをアラート消せる。めでたしめでたし。

次回

AWS Config の結果を export するやつの予定。

docs.aws.amazon.com

なんかいろいろ考えてたけど忘れた。このへんか。