PostgreSQL on EC2 をサポートした CloudWatch Database Insights を試してみた
はじめに
2026年9月1日、CloudWatch Database Insights が自己管理 PostgreSQL に対応しました。自前で運用している PostgreSQL が、RDS や Aurora と同じ Database Insights のダッシュボードに載ります。
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 でした。

データベース負荷のグラフ、待機イベント別の凡例、上位の 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 に保存されます。保持期間は配信先ロググループの設定に従います。
まとめ
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 を動かして触ってみることをお勧めします。







