PostgreSQL on EC2 をサポートした CloudWatch Database Insights を試してみた

PostgreSQL on EC2 をサポートした CloudWatch Database Insights を試してみた

CloudWatch Database Insights は、pg_stat_statements と監視ロールを用意して CloudWatch agent の設定に database_insights を1節足すだけで、EC2 上の自己管理 PostgreSQL を対象にできます。DB 負荷・待機イベント・上位 SQL がコンソールに出て、CloudWatch には OTel のログとメトリクスが届きました。
2026.09.03

はじめに

2026年9月1日、CloudWatch Database Insights が自己管理 PostgreSQL に対応しました。自前で運用している PostgreSQL が、RDS や Aurora と同じ Database Insights のダッシュボードに載ります。

https://aws.amazon.com/about-aws/whats-new/2026/08/database-insights-self-managed-postgresql/

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Database-Insights-Self-Managed.html

EC2 の t3.micro に立てた PostgreSQL 16 で実際に設定して、コンソールに何が出るか、CloudWatch に何が届くかを確認しました。agent がどのようにデータを集めて送っているのかも、展開後の実効設定から追いました。

検証内容

CloudWatch agent は PostgreSQL と同じホストで動かします。ユーザーガイドの前提条件にも、リモートのデータベースの監視はサポートされないと書かれています。接続先は localhost で、サーバーログもローカルのファイルから読みます。今回は EC2 1台に同居させました。

検証環境

環境は us-west-2 の EC2 インスタンス1台です。t3.micro(gp3 8GB)に Amazon Linux 2023 を載せました。入れたのは PostgreSQL 16.15(postgresql16-server-16.15-1.amzn2023.0.1.x86_64)です。CloudWatch agent は 1.300072.0b1766 で、S3 の配布 URL から取得した最新版です。シェルアクセスは Session Manager だけにして、セキュリティグループのインバウンドは開けていません。

インスタンスプロファイルに付けたマネージドポリシーは2つです。

  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy

AmazonSSMManagedInstanceCore は Session Manager と Run Command のために付けたポリシーです。Database Insights が要求するのは CloudWatchAgentServerPolicy だけです。

この環境は CloudFormation で作成しました。

aws cloudformation deploy \
  --region us-west-2 \
  --stack-name dbinsights-selfmanaged-pg \
  --template-file template.yaml \
  --capabilities CAPABILITY_IAM \
  --parameter-overrides InstanceType=t3.micro

PostgreSQL 側の設定

Database Insights は PostgreSQL の標準ビューを読むので、先に PostgreSQL 側を設定しておく必要があります。次の内容を postgresql.conf に入れました。

shared_preload_libraries = 'pg_stat_statements'
track_activities = on
track_activity_query_size = 4096
password_encryption = 'scram-sha-256'

pg_stat_statements.max = 10000
pg_stat_statements.track = all
pg_stat_statements.track_planning = on

logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%a.log'
log_rotation_age = 1d
log_rotation_size = 0
log_truncate_on_rotation = on
log_min_duration_statement = 500
log_line_prefix = '%m [%p] %q%u@%d '

compute_query_id = on

shared_preload_libraries は起動時にしか読まれないため、反映には reload ではなく restart が必要です。

systemctl restart postgresql

続いて拡張を有効にし、監視用のユーザーを作って接続を許可しました。pg_stat_statements は拡張なので、監視するデータベースごとに作成します。

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE ROLE cw_monitor WITH LOGIN PASSWORD '<パスワード>';
GRANT pg_monitor TO cw_monitor;
# TYPE  DATABASE  USER         ADDRESS         METHOD
host    all       cw_monitor   127.0.0.1/32    scram-sha-256
host    all       cw_monitor   ::1/128         scram-sha-256

pg_hba.conf は上から評価され、最初に一致した行が使われます。Amazon Linux 2023 の既定の設定はループバック接続を ident で受けるので、この2行は既存の行より上に入れます。こちらは reload で反映できます。

systemctl reload postgresql

pg_monitor ロールを付与すると、superuser なしで pg_stat_activity と pg_stat_statements を読めます。設定を反映したあと、監視ユーザーで localhost に接続し、2つのビューが読めることを確認しました。

監視ユーザーで接続すると、次の値が返りました。

postgres (PostgreSQL) 16.15

 activity_rows
---------------
             6
(1 row)

 statement_rows
----------------
             58
(1 row)

 shared_preload_libraries
--------------------------
 pg_stat_statements
(1 row)

agent の設定

CloudWatch agent 側で足すのは1節です。/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json の内容は次のようになりました。

{
  "agent": {
    "region": "us-west-2"
  },
  "opentelemetry": {
    "collect": {
      "database_insights": {
        "postgresql": [
          {
            "endpoint": "localhost:5432",
            "instance_name": "selfmanaged-pg-1",
            "username": "cw_monitor",
            "password_file": "/opt/aws/amazon-cloudwatch-agent/etc/pgpass",
            "logs": {
              "file_path": "/var/lib/pgsql/data/log/postgresql-*.log"
            }
          }
        ]
      }
    }
  }
}

instance_name がコンソールの表示名になります。パスワードは設定ファイルではなく、password_file が指すファイルに置きます。形式は libpq の pgpass です。

指定できるのは region、endpoint、instance_name、username、password_file、logs.file_path の6項目だけです。収集するメトリクスを選ぶ項目はありません。ユーザーガイドのパラメータ表も同じ6項目です。実際に何が集まったかは後述します。

pgpass を作り、設定を読み込ませました。

umask 077
printf 'localhost:5432:*:cw_monitor:%s\n' "$MON_PASS" \
  > /opt/aws/amazon-cloudwatch-agent/etc/pgpass
chown cwagent:cwagent /opt/aws/amazon-cloudwatch-agent/etc/pgpass

/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config -m ec2 -s \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json

pgpass は cwagent ユーザーが読めるように所有者を変えました。読み込み後、agent は次の状態を返しました。

{
  "status": "running",
  "starttime": "2026-09-03T01:53:35+00:00",
  "configstatus": "configured",
  "version": "1.300072.0b1766"
}

書いた設定ファイルには、収集間隔を指定する項目がありません。間隔は config-translator が展開した実効設定に現れます。展開後の amazon-cloudwatch-agent.yaml は 51,220 バイトです。収集ごとの間隔は次のとおりです。

収集 間隔
postgresql/metrics_0 10s
query_sample_collection(pg_stat_activity) 1s
top_query_collection(pg_stat_statements) 1m
postgresql/metrics_perresource_0 1m
postgresql/events_0 10s
hostmetrics/opentelemetry 30s

セッションのサンプルは1秒ごとで、1回に読む行数の上限は 500 です。上位クエリの収集は1分ごとで、対象は上位 200 件です。実行計画は1インターバルあたり 1000 件まで取得し、1000 件・TTL 1時間のキャッシュに載ります。

ホストメトリクスの process スクレイパーは、post(gres|master).* に一致するプロセスだけを対象にします。サーバーログを追う filelog は start_at を end にして、タイムスタンプと重大度を正規表現でパースします。ユーザー名またはロール名が cw_monitor のログレコードは filter プロセッサが落とすため、監視ユーザー自身のクエリは raw-events に出ません。

CloudWatch へ届く間隔は1分ごとで、イベントのユニークなタイムスタンプの差分は pg_stat_statements 由来・pg_stat_activity 由来のいずれも 60 秒でした。負荷を流していない区間では、点の出ない時間帯がありました。

収集は agent が自分で PostgreSQL へ接続して行います。postgresqlreceiver には設定した endpoint と username がそのまま展開され、transport は tcp です。パスワードは pgpass を passfile として参照します。投げているのは標準ビューへの SELECT です。対象は pg_stat_activity、pg_stat_statements、pg_stat_database、pg_locks、pg_stat_user_indexes、pg_stat_user_functions、pg_database_size()、SHOW max_connections、SHOW server_version などです。

負荷を流していない状態で見たときは、監視ユーザーの接続が idle で8本常駐していました。

転送は agent が OTLP/HTTP でまとめて送ります。PutMetricData は使いません。

    otlphttp/metrics:
        metrics_endpoint: https://monitoring.us-west-2.amazonaws.com/v1/metrics
        compression: gzip
        encoding: proto
        sending_queue:
            enabled: true
            num_consumers: 10
            queue_size: 1000
        retry_on_failure:
            enabled: true
            initial_interval: 5s
            max_interval: 30s
            max_elapsed_time: 5m0s
            multiplier: 1.5
        timeout: 30s
    otlphttp/logs:
        logs_endpoint: https://logs.us-west-2.amazonaws.com/v1/logs
        compression: gzip
        encoding: proto

まとめる条件は batch プロセッサに書かれています。

対象 send_batch_size send_batch_max_size timeout
メトリクス 1000 1000 30s
ログ 10000 10000 30s

認証は sigv4auth です。SigV4 の service 名は、メトリクスが monitoring、ログが logs です。ロググループとログストリームの作成は awscloudwatchlogsprovisioner extension が担当します。headers_setter が付ける x-aws-log-group と x-aws-log-stream ヘッダで宛先が振り分けられます。ログ側の batch は、メタデータキーとしてロググループ名とログストリーム名を持ちます。

収集そのものにかかるコストも測りました。負荷を一切流さず、pg_stat_statements をリセットしてから 300 秒放置したときの、t3.micro 1台での値です。

  • agent プロセスの CPU 時間は 7.40 秒 / 300 秒で、1 コアの 2.47% にあたります
  • agent プロセスの RSS は 140,072 KB で、ps の %MEM は 14.9% でした
  • 監視ユーザーのクエリは 980 calls / 合計 221.94 ms でした
  • そのうち1秒間隔のものは pg_stat_activity を読む1本だけで、305 calls / 55.60 ms(mean 0.182 ms)でした。10 秒間隔の19本は各 35 calls、pg_stat_statements を読む1本は 10 calls でした
  • 1回あたりの実行時間が最も長いのは pg_database_size を読むクエリで、mean 1.535 ms でした
  • サーバーログは 300 秒で 22 行増えただけでした

DB 側の負荷は小さく、常時払うのは agent 側のメモリ 140 MB と CPU 2.5% です。t3.micro で PostgreSQL と同居させる構成では、まずメモリが問題になります。SQL の実行数とクエリログの量が増えれば、収集側の負荷も増えます。

収集が始まったかどうかは agent のログで分かります。次の行が出ていました。

I! {"caller":"builders/builders.go:26","msg":"Development component. May change in the future."}
I! {"caller":"awscloudwatchlogsprovisionerextension@v0.124.1/extension.go:79","msg":"awscloudwatchlogsprovisioner started","region":"us-west-2"}
I! {"caller":"service@v0.124.0/service.go:289","msg":"Everything is ready. Begin running and processing data."}
I! {"caller":"fileconsumer/file.go:265","msg":"Started watching file","component":"fileconsumer","path":"/var/lib/pgsql/data/log/postgresql-Thu.log"}

付与したポリシーは検証環境で示した2つだけですが、ログに AccessDenied は1件も出ませんでした。同じログに出力された収集パイプラインの構成には、postgresql/metrics_0、count/dbi_dbload、signaltometrics/dbi_topsql が含まれます。

コンソールの表示

コンソールに出るデータを作るため、SSM Run Command で負荷を投入しました。30万行のテーブルに対する集計 SELECT、INSERT と UPDATE、pg_sleep を挟んだ遅いクエリ、同一行を更新し合うトランザクションを10分間流しました。

送ったコマンドは次のとおりです。commands.json には、orders テーブルを30万行で作る SQL と、上記の負荷を流すシェルスクリプトを入れました。

aws ssm send-command \
  --region us-west-2 \
  --instance-ids i-xxxxxxxxxxxxxxxxx \
  --document-name AWS-RunShellScript \
  --parameters file://commands.json

負荷を流した区間は 2026-09-03T01:54:23Z から 02:04:26Z までです。PostgreSQL 側の pg_stat_statements で最上位だったのは SELECT count(*) FROM orders WHERE note LIKE $1 AND amount > (random()* です。calls は 1464、total_exec_time は 1049332.9 ms でした。

Database Insights のインスタンスダッシュボード

データベース負荷のグラフ、待機イベント別の凡例、上位の SQL の一覧が並びます。以下は t3.micro 1台へ1回だけ負荷を流したときの表示です。

データベースインスタンスの一覧に出た名前は selfmanaged-pg-1 で、agent 設定の instance_name がそのまま使われました。カードには「DB 負荷使用率 94.1%」と表示され、ヘッダのロールは Instance、エンジンは PostgreSQL、サイズは t3.micro でした。

データベース負荷は平均アクティブセッション(AAS)で表示されます。負荷を流した時間帯にピーク 2〜3 のバーが出ました。凡例には CPU、BtreePage、ExecuteGather、PgSleep、WALSync、transactionid と、「最大 vCPU」の破線が並びます。

上位の SQL は10件でした。wait によるロード(AAS)の値は上位から 0.52、0.38、0.31、0.28、0.24、0.14 でした。残り4件は 0.01 未満でした。10件のうち3件は SQL テキストが取れず、Query ID を添えた Unknown として表示されました。ダッシュボードを開いた直後は「上位の SQL(0)」で「データのロード中」と表示され、そのあと10件が出ました。

ビューは「フリートの状態」と「データベースインスタンス」の2つで、Cross-account cross-region mode のトグルも RDS と同じ位置にあります。

届いたテレメトリ

agent はロググループを2本作りました。

/aws/self-managed-database-insights/postgresql/raw-events
/aws/self-managed-database-insights/postgresql/server-logs

どちらもテンプレートでは作っていません。ログストリーム名は2本ともインスタンス ID と設定した instance_name を組み合わせた i-xxxxxxxxxxxxxxxxx/selfmanaged-pg-1 という形です。これらのロググループは CloudFormation の管理外なので、スタックを削除しても残ります。

raw-events には、リテラルを ? に置き換えた OTel ログが届きました。取得した 223 件のイベントのうち、169 件は pg_stat_statements 由来の統計で、54 件は pg_stat_activity 由来のセッションのサンプルでした。

1件のイベントは次の形です。

{
  "resource": {
    "attributes": {
      "service.instance.id": "ip-10-20-x-x.us-west-2.compute.internal:5432",
      "cloud.provider": "aws",
      "cloud.platform": "aws_ec2",
      "cloud.region": "us-west-2",
      "cloud.account.id": "123456789012",
      "cloud.availability_zone": "us-west-2a",
      "host.id": "i-xxxxxxxxxxxxxxxxx",
      "host.image.id": "ami-0bea529386a62a2ad",
      "host.type": "t3.micro",
      "host.name": "ip-10-20-x-x.us-west-2.compute.internal",
      "db.system.name": "postgresql",
      "db.instance.name": "selfmanaged-pg-1",
      "deployment.environment.name": "aws_ec2:default",
      "cloud.resource_id": "arn:aws:ec2:us-west-2:123456789012:instance/i-xxxxxxxxxxxxxxxxx",
      "service.name": "unknown_service"
    },
    "schemaUrl": "https://opentelemetry.io/schemas/1.6.1"
  },
  "scope": {
    "name": "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/postgresqlreceiver",
    "version": "1.300072.0b1766",
    "attributes": {
      "cloudwatch.source": "cloudwatch-agent",
      "cloudwatch.solution": "otel-database-insights"
    }
  },
  "timeUnixNano": 1788400477424151302,
  "observedTimeUnixNano": 0,
  "severityNumber": 0,
  "severityText": "",
  "attributes": {
    "db.system.name": "postgresql",
    "db.namespace": "appdb",
    "db.query.text": "BEGIN UPDATE orders SET amount = amount + ? WHERE id = ? SELECT pg_sleep ( ? ) COMMIT",
    "user.name": "postgres",
    "postgresql.state": "active",
    "postgresql.pid": 28140,
    "postgresql.application_name": "psql",
    "network.peer.address": "",
    "network.peer.port": -1,
    "postgresql.client_hostname": "",
    "postgresql.query_start": "2026-09-03 01:54:36.888193+00",
    "postgresql.wait_event": "transactionid",
    "postgresql.wait_event_type": "Lock",
    "postgresql.query_id": "686538199038618172",
    "postgresql.total_exec_time": 625.21
  },
  "traceId": "",
  "spanId": "",
  "eventName": "db.server.query_sample"
}

掲載したイベントの eventName は db.server.query_sample で、pg_stat_activity のサンプルにあたります。pg_stat_statements 由来のイベントは db.query.text、postgresql.calls、postgresql.rows、postgresql.total_exec_time、postgresql.total_plan_time、postgresql.shared_blks_hit、postgresql.shared_blks_read、postgresql.shared_blks_dirtied、postgresql.shared_blks_written、postgresql.temp_blks_read、postgresql.temp_blks_written、postgresql.queryid、postgresql.rolname を持ちます。同じクエリでも postgresql.calls は pg_stat_statements の累積値より小さくなります。

コンソールで見た待機イベントの内訳は、Logs Insights でも同じように引けます。

filter ispresent(`attributes.postgresql.state`)
| stats count(*) as samples
    by coalesce(`attributes.postgresql.wait_event_type`, "CPU") as wait_type,
       coalesce(`attributes.postgresql.wait_event`, "CPU") as wait_event
| sort samples desc
wait_type wait_event samples
CPU CPU 27
Timeout PgSleep 17
Lock transactionid 9
IO WALSync 1

Logs Insights が対象期間でスキャンした 181 件のイベントのうち、postgresql.state を持つ 54 件の集計です(先の 223 件とは取得範囲が異なります)。待機イベントの種別を持たないイベントは、CPU として数えています。

上位クエリも、同じロググループから取れます。

filter ispresent(`attributes.postgresql.total_exec_time`)
| stats max(`attributes.postgresql.total_exec_time`) as total_exec_ms,
        max(`attributes.postgresql.calls`) as calls
    by substr(`attributes.db.query.text`, 0, 60) as query
| sort total_exec_ms desc | limit 8

返ったのは8件で、上位4件を挙げます。

query(先頭60文字) total_exec_ms calls
BEGIN UPDATE orders SET amount = amount + ? WHERE id = ? SEL 3585.866 -
SELECT pg_sleep ( ? ) count ( * ) FROM orders 975.3 40
UPDATE orders SET status = ? WHERE id = ( SELECT id FROM ord 830.038 121
SELECT count ( * ) FROM orders WHERE note LIKE ? AND amount 609.541 150

ここでの calls はイベントに乗っている値の系列で、pg_stat_statements の累積値(1464)とは別の量です。最上位の1件は calls を持たないイベントでした。

メトリクス側も見ます。設定ファイルに書いたのは1節だけですが、agent は複数のパイプラインを構成しました。

        metrics/host_metrics:
            exporters:
                - forward/opentelemetry
            processors:
                - transform/host_metrics_scope
            receivers:
                - hostmetrics/opentelemetry
        metrics/opentelemetry:
            exporters:
                - otlphttp/metrics
            processors:
                - resourcedetection/opentelemetry
                - transform/identity
                - batch/opentelemetry_metrics
            receivers:
                - forward/opentelemetry

同じダンプの上流側には、postgresql/metrics_0 と postgresql/metrics_perresource_0 が並びます。count/dbi_dbload と signaltometrics/dbi_topsql もこのダンプに出ます。DB 負荷と上位クエリは agent が組み立てます。ホストメトリクスの receiver も、設定なしで agent が構成します。

メトリクスの出口は otlphttp/metrics で、OpenTelemetry メトリクスとして送られます。そのため、ListMetrics が返す従来の CloudWatch メトリクスの一覧には出ません。CWAgent ネームスペースのメトリクスは、設定後・負荷投入後に確認した時点で {"Metrics": []} でした。直近3時間にアクティブなメトリクスのネームスペース一覧にも、Database Insights 相当のものは現れませんでした。

Performance Insights API 経由の取得もできません。手元の AWS CLI 2.34.39 に同梱のサービスモデルでは、pi API の ServiceType は RDS と DOCDB の2値のみです。自己管理 PostgreSQL を指定する値がありません。

OTel メトリクスの参照経路は PromQL です。SQL テキストはメトリクス側のラベルには入らないため、クエリ文で追う場合はロググループを見ます。

収集されているメトリクス名は、https://monitoring.us-west-2.amazonaws.com/api/v1/label/__name__/values で一覧できます。SigV4 の service 名は monitoring で、必要な権限は cloudwatch:GetMetricData と cloudwatch:ListMetrics です。返ってきたメトリクス名は 69 個で、設定ファイルには1つも書いていません。

postgresql.active_sessions.by_app  postgresql.active_sessions.by_db
postgresql.active_sessions.by_host postgresql.active_sessions.by_sql
postgresql.active_sessions.by_sql_wait postgresql.active_sessions.by_user
postgresql.active_sessions.by_wait postgresql.active_sessions.count
postgresql.backends postgresql.bgwriter.buffers.allocated
postgresql.bgwriter.buffers.writes postgresql.bgwriter.checkpoint.count
postgresql.bgwriter.duration postgresql.bgwriter.maxwritten
postgresql.blocks_read postgresql.calls postgresql.commits
postgresql.connection.max postgresql.database.count postgresql.db_size
postgresql.index.scans postgresql.index.size postgresql.operations
postgresql.rollbacks postgresql.rows postgresql.shared_blks_hit
postgresql.shared_blks_read postgresql.table.count postgresql.table.size
postgresql.table.vacuum.count postgresql.total_exec_time
postgresql.total_plan_time
process.cpu.time process.cpu.utilization process.disk.io
process.memory.usage process.memory.utilization process.memory.virtual
system.cpu.frequency system.cpu.load_average.15m system.cpu.load_average.1m
system.cpu.load_average.5m system.cpu.logical.count system.cpu.physical.count
system.cpu.time system.cpu.utilization system.disk.io system.disk.io_time
system.disk.merged system.disk.operation_time system.disk.operations
system.disk.pending_operations system.disk.weighted_io_time
system.filesystem.inodes.usage system.filesystem.usage
system.filesystem.utilization system.linux.memory.available
system.linux.memory.dirty system.memory.limit system.memory.page_size
system.memory.usage system.memory.utilization system.network.connections
system.network.dropped system.network.errors system.network.io
system.network.packets system.processes.count system.processes.created

active_sessions で始まるものが、コンソールの DB 負荷とその内訳にあたります。内訳は待機・SQL・データベース・ユーザー・アプリケーション・ホスト別です。system と process で始まるものはホストメトリクスです。

DB 負荷の内訳は、メトリクス側では PromQL で引けます。

負荷投入中の1分(time=1788401100 = 2026-09-03T02:05:00Z)の内訳です。

sum by ("postgresql.wait_event_type","postgresql.wait_event") ({"postgresql.active_sessions.by_wait"})
postgresql.wait_event_type postgresql.wait_event
CPU CPU 9
Timeout PgSleep 2
Lock transactionid 2
LWLock WALWrite 1
IPC ExecuteGather 1
IPC BtreePage 1
IO WALSync 1

並んだ待機イベントの種別はコンソールの凡例と同じでした。値は整数で、コンソールに出た AAS(ピーク 2〜3)とは一致しませんでした。CPU 待ちの推移を step=60 で並べると 4 → 7 → 8 → 10 → 7 → 7 → 8 → 6 → 9 → 9 → 9 で、1分ごとに1点です。

ラベルには OTLP の構造がそのまま乗っています。インスタンス名・ホストタイプ・solution がそのまま入ります。SQL 別のメトリクスのラベルはクエリ ID です。

このクエリを実行したのは、スタックとロググループを削除したあとです。メトリクスは残っており、ListMetrics に出ないだけで参照できました。

設定を読み込ませてから最初のイベントが届くまでは数秒でした。agent の起動が 01:53:35Z、最初のイベントが 01:53:37Z で、2本のロググループは起動から 32 秒後と 79 秒後に現れました。

検証後は、スタックに加えて CloudFormation 管理外のロググループも削除しました。

aws cloudformation delete-stack --region us-west-2 --stack-name dbinsights-selfmanaged-pg
aws cloudformation wait stack-delete-complete --region us-west-2 --stack-name dbinsights-selfmanaged-pg

# ロググループは CloudFormation の管理外なので個別に削除する
aws logs delete-log-group --region us-west-2 \
  --log-group-name /aws/self-managed-database-insights/postgresql/raw-events
aws logs delete-log-group --region us-west-2 \
  --log-group-name /aws/self-managed-database-insights/postgresql/server-logs

料金

自己管理データベースの Database Insights は、取り込み量に対する課金です。agent が取り込む OpenTelemetry メトリクスと CloudWatch Logs に対して支払います。自己管理データベースは Standard モードと Advanced モードを使わないため、RDS や Aurora のような vCPU-hour 課金は発生しません。

執筆時点の料金ページでは、OTel メトリクスの取り込みは $0.50 per GB ingested です。この定額に、収集したメトリクスを15か月保持する分のストレージが含まれます。API 呼び出し・メトリクスの保存・ユニークな系列数に対する別料金はありません。

agent が収集したログは CloudWatch に保存されます。保持期間は配信先ロググループの設定に従います。

https://aws.amazon.com/cloudwatch/pricing/

まとめ

EC2 で自前運用している PostgreSQL を、CloudWatch agent の設定に1節足すだけで Database Insights のダッシュボードに載せられました。仕組みは CloudWatch agent を使う方式です。agent が DB へ接続して標準ビューを読み、OTLP で CloudWatch へ送ります。届いた内訳は、コンソールのダッシュボードだけでなく Logs Insights と PromQL からも取れました。

構成を見ると、OTel の receiver と汎用のバッチ転送の組み合わせで、エンジン固有なのは receiver 1つです。自己管理でいまサポートされるのは PostgreSQL だけですが、他エンジンへ広がる余地のある作りではあります。EC2 などで動かす DB の監視手段として注目したいところです。CloudWatch agent の活用例、OTel 連携のリファレンスの1つとしても参考になります。

これだけの仕組みをマネージドで提供しているのが、RDS と Aurora の Database Insights です。自前運用では、PostgreSQL の設定、監視ロール、agent の常時コストを自分で抱えることになります。実運用は RDS や Aurora に寄せたうえで、中身を把握する機会として EC2 上で agent を動かして触ってみることをお勧めします。

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事