1. はじめに
前回、New Relic の Database 360 で Oracle Autonomous Database(以下 ADB)を監視する記事を書きました1。書き終えたあとに Datadog でも同じことができるかを調べたところ、Datadog の Database Monitoring(以下 DBM)には ADB 専用のセットアップページがあり2、Agent のリリースノートにも 2023 年 8 月の 7.47.0 で ADB 対応が入ったと書かれていました3。
そこで今回は、前回と同じ Always Free の ADB に Datadog Agent を接続し、DBM の各画面で何が見えるか、Datadog に何が送られるかを実際に試してみます。接続は前回と同じく ADB 側で TLS 接続を許可した状態で行い、ウォレット(ADB の証明書一式)は使っていません。ウォレットで接続する場合は付録(8 章)にまとめました。
1.1. 結論(先出し)
- 公式の ADB 向け手順のとおり監視ユーザーを作れば、Agent から ADB に接続できた。GRANT 37 文はすべてそのまま実行でき、ADB 側で TLS 接続を許可していればウォレットは無くてもよい
- Databases・Queries・Samples・Explain Plans・Active Connections・Recommendations の画面は ADB でも表示された。出ないのはプリセットのダッシュボードだけだった。セッションの採取は ADB で使える ASH(Active Session History)に切り替えられ、1 秒刻みになる
- SQL 本文のリテラルは
?に置き換わり、実行計画の述語のリテラルも?になる。ただし SQL コメントは metadata として原文のまま届き、接続元のマシン名・OS ユーザー名・プログラムのパスも送られる
1.2. 検証ゴール
| # | 確かめること | 確認できれば OK の条件 |
|---|---|---|
| 1 | 公式の ADB 向け手順で Datadog Agent が ADB に接続できる(ウォレット無しの TLS 接続で) | Agent の Oracle チェックが成功し、Datadog の Databases 一覧に ADB が現れてクエリが並ぶ |
| 2 | DBM の各画面で ADB の何が見えて何が見えないか。一覧のホスト名が $resolved_hostname になる問題と、reported_hostname を設定した場合との違い |
負荷をかけた状態で各画面を開き、見えないものが公式ドキュメントとプランの記述で説明できる |
| 3 | Datadog に何が送られるか | SQL 本文・実行計画の述語・SQL コメント・接続元の情報がどう送られるかが、Datadog の画面で確認できる |
2. 検証環境
| 項目 | 値 |
|---|---|
| 監視対象 | Oracle Autonomous Database Serverless(Always Free、Autonomous Transaction Processing) |
| DB バージョン | Oracle AI Database 26ai(Agent からは 23.26.3.3.0 と見える) |
| 構成 | Always Free のインスタンス(ap-tokyo-1、ウォレット無しの TLS 接続を許可済み) |
| Agent | Datadog Agent 7.83.2(Oracle チェックは Agent 内蔵、Oracle クライアント不要) |
| Agent のホスト | Windows 11 上の WSL2 Ubuntu 24.04 |
| Datadog | Free プラン(サイトは ap1.datadoghq.com、Japan リージョン) |
ADB はホストにログインできないので、Agent 用のマシンが別に 1 台必要です。今回は手元の WSL を使いました。公式の DBM Setup Architecture のページでは、マネージドの DB に対しては Agent を別のホストに置いて接続する構成が案内されています2。本番なら OCI の Compute を VCN 内に置き、プライベートエンドポイントで接続する構成になりそうです(この構成は試していません)。Agent には Windows 版(MSI)もあり、同じ oracle.d/conf.yaml で ADB に接続でき、Datadog の Active Connections にもデータが届きました(サービスとして 3 分間動かして確認)。ただし Windows 版では 3.4 章の file.yaml による秘密の参照がサービスで有効にならず、API key が解決されないまま送信が 403 で拒否されました。Windows 版では API key を datadog.yaml に、パスワードを conf.yaml に直接書き、ファイルのアクセス権を絞って動かしています。file.yaml がサービスで有効にならなかった原因は切り分けていません。
今回の構成を図 1 に示します。左が監視対象の ADB、中央が Agent を動かす手元の PC、右が Datadog です。Agent が ADB に TLS で接続して V$ ビューを 10 秒ごとに読み、その結果を Datadog の ap1 サイトへ送ります。
図 1: 構成図(WSL 上の Datadog Agent が ADB へ TLS で接続し、ap1.datadoghq.com へ送る)
3. 構成・実装
3.1. 公式 ADB 手順と今回の差分
公式の ADB 向けページ2 では次の順で進めます。
- ADB に監視ユーザー
datadogを作る - V$ ビューと DBA_ ビューに SELECT 権限を付ける
- Agent をインストールする
- ウォレットの zip を展開し、
oracle.d/conf.yamlにprotocol: TCPSとwallet:を書く - Datadog の Integrations の画面で Oracle のインテグレーションをインストールする
- Agent の status と DBM の画面で確認する
公式手順と違うのは、wallet: を書かずに ADB の TLS 接続を使ったこと(3.2 章)、reported_hostname を最初から書いたこと(3.4 章)、API key と DB パスワードを設定ファイルに平文で書かず Agent の secrets 機能で参照したこと(3.4 章)の 3 つです。
3.2. 接続設定と ADB 側のネットワーク設定
ADB Serverless は作成した状態では mTLS(相互 TLS。クライアント側にも証明書が必要な方式)が必須で(前回の記事の 1 章1)、公式手順がウォレットを前提にしているのはこのためです。ウォレット無しで接続するには、ADB 側で ACL(アクセス制御リスト)に Agent ホストのグローバル IP を登録し、相互 TLS 認証の「必要」を解除します。Oracle の公式ドキュメントによれば、TLS 接続を許可する条件は ACL かプライベートエンドポイントのどちらかで、パブリックエンドポイントなら ACL が必須です4。この設定変更の手順は前回の記事の 3.2 章に書いたので、今回はその設定を変えた状態から始めています。
Agent の Oracle チェックは Go で書かれたドライバを内蔵していて5、Oracle Instant Client のインストールは不要です2。監視用のホストに Oracle のクライアントライブラリを入れずに済むのは運用上の利点で、その代わり接続の指定方法は Agent の設定項目に限られます。設定項目の一覧はリポジトリの conf.yaml.example にあり、protocol は TCP か TCPS、wallet は「TCPS で使うウォレットのディレクトリ」と説明されています5。今回検証した 7.83.2 の example には、ウォレット無しの TCPS についての記述はありません。
3.3. 監視ユーザーと権限
ユーザー作成と権限付与は公式の ADB ページのとおりで、ADMIN ユーザーで実行します。GRANT は 37 文あり、V$SESSION、V$SQLSTATS、V$SQL_PLAN_STATISTICS_ALL、V$SQL のほか、V$RSRCMGRMETRIC、V$LOCK、DBA_OBJECTS などが含まれます。
ユーザー作成と GRANT 37 文(公式の ADB ページのとおり)
-- ADMIN で実行。パスワードは英数字だけにする
CREATE USER datadog IDENTIFIED BY "<パスワード>";
grant create session to datadog ;
grant select on v$session to datadog ;
grant select on v$database to datadog ;
grant select on v$containers to datadog;
grant select on v$sqlstats to datadog ;
grant select on v$instance to datadog ;
grant select on dba_feature_usage_statistics to datadog ;
grant select on V$SQL_PLAN_STATISTICS_ALL to datadog ;
grant select on V$PROCESS to datadog ;
grant select on V$SESSION to datadog ;
grant select on V$CON_SYSMETRIC to datadog ;
grant select on CDB_TABLESPACE_USAGE_METRICS to datadog ;
grant select on CDB_TABLESPACES to datadog ;
grant select on V$SQLCOMMAND to datadog ;
grant select on V$DATAFILE to datadog ;
grant select on V$SYSMETRIC to datadog ;
grant select on V$SGAINFO to datadog ;
grant select on V$PDBS to datadog ;
grant select on CDB_SERVICES to datadog ;
grant select on V$OSSTAT to datadog ;
grant select on V$PARAMETER to datadog ;
grant select on V$SQLSTATS to datadog ;
grant select on V$CONTAINERS to datadog ;
grant select on V$SQL_PLAN_STATISTICS_ALL to datadog ;
grant select on V$SQL to datadog ;
grant select on V$PGASTAT to datadog ;
grant select on v$asm_diskgroup to datadog ;
grant select on v$rsrcmgrmetric to datadog ;
grant select on v$dataguard_config to datadog ;
grant select on v$dataguard_stats to datadog ;
grant select on v$transaction to datadog;
grant select on v$locked_object to datadog;
grant select on v$lock to datadog ;
grant select on gv$lock to datadog ;
grant select on dba_objects to datadog;
grant select on cdb_data_files to datadog;
grant select on dba_data_files to datadog;
Always Free の ADB でもこの 37 文はすべて ADMIN から付与できました。
セルフホストの Oracle 向けページには、このほかに SYS で X$KSUSE などの内部表を結合した dd_session というビューを作る手順があります6。ADB 向けページにはこの手順がなく、セッションの情報は V$SESSION などの公開ビューから取ります。5.2 章の Active Connections はその結果です。
3.4. conf.yaml と秘密の置き方
oracle.d/conf.yaml は次のとおりです。ホスト名・ポート・サービス名は OCI コンソールの「データベース接続」に表示される TLS 用の接続文字列の値をそのまま使います。
# /etc/datadog-agent/conf.d/oracle.d/conf.yaml(dd-agent:dd-agent, 640)
init_config:
instances:
- server: 'adb.ap-tokyo-1.oraclecloud.com:1522'
service_name: 'g4256714d933780_adbtest01_low.adb.oraclecloud.com'
username: 'datadog'
password: 'ENC[datadog_user_database_password]'
protocol: TCPS
# wallet: <WALLET_DIR> # 公式手順にはあるが今回は指定しない(8 章)
reported_hostname: 'adbtest01'
dbm: true
query_samples:
active_session_history: true # 5.2 章。ADB は ASH が使えるので V$ACTIVE_SESSION_HISTORY から採取する
tags:
- 'env:lab'
- 'db:adbtest01'
reported_hostname は Datadog 上で DB を表す名前です。公式のトラブルシューティングに、ADB は V$INSTANCE の HOST_NAME が null なので Agent がホスト名を決められず、reported_hostname を設定するよう書かれています6。書かないとどうなるかは 5.1 章で示します。
password の ENC[...] は Agent の secrets 機能の書き方で、公式ページの例もこの書き方です2。Agent には AWS Secrets Manager などから秘密を取る仕組みがいくつかあり、今回はファイルから読む file.yaml を使いました7。検証用の 1 台構成で外部の秘密管理サービスを持たないため、追加の部品が不要なこの方式にしています。datadog.yaml に次を書くと、api_key と password の両方をこのファイルから解決します。
# /etc/datadog-agent/datadog.yaml の該当箇所
api_key: "ENC[dd_api_key]"
site: ap1.datadoghq.com
hostname: wsl-lab-agent
secret_backend_type: file.yaml
secret_backend_config:
file_path: /etc/datadog-agent/secrets.yaml
# /etc/datadog-agent/secrets.yaml(root:dd-agent, 640)
dd_api_key: <API key>
datadog_user_database_password: <監視ユーザーのパスワード>
query_samples.active_session_history はセッションの採取方法の指定で、5.2 章で説明します。この指定を使うには公式の GRANT に加えて V$ACTIVE_SESSION_HISTORY の SELECT 権限が必要です。
hostname は Agent 自身のホスト名で、DB の名前とは別です。WSL2 では Agent がホスト名を決められずに起動しなかったため指定しました(4.2 章)。
4. 手順・実行
4.1. Datadog 側の準備
Datadog 側で必要なのは API key と、Integrations の画面での Oracle インテグレーションのインストールです。API key は Organization Settings の API Keys で作ります。DBM の画面は Infrastructure の Databases(/databases)から開き、初回はデータベースの種類と環境を選ぶウィザードが表示されます。Database で Oracle、Environment で Autonomous Database を選ぶと、公式ページと同じ GRANT の一覧と Agent の設定手順が表示されます。
図 2: DBM のセットアップウィザード。Environment に Autonomous Database がある
Oracle インテグレーションのインストールは、Integrations の画面の一覧から Oracle Database を開いて Install を押すだけです。Agent の設定とは独立した Datadog 側の操作で、公式手順ではこれで Oracle 向けのプリセットダッシュボードが使えるようになります。今回は Free プランのため、押したあともダッシュボードは表示されませんでした(5.6 章)。
4.2. Agent の導入と接続確認
導入は公式の 1 行コマンドです。サイトを環境変数で指定し、起動は設定後に行うので DD_INSTALL_ONLY を付けます。
export DD_API_KEY="<API key>"
export DD_SITE="ap1.datadoghq.com"
DD_INSTALL_ONLY=true bash -c "$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)"
3.4 章のファイルを置いて systemctl start datadog-agent で起動します。WSL2 では最初の起動が次のエラーで止まりました。
Error while getting hostname, exiting: unable to reliably determine the host name. You can define one in the agent config file or in your hosts file
datadog.yaml に hostname を書いて解消しました。WSL のホスト名が名前解決できないために起きる WSL 固有の挙動と考えられます。
起動後に接続を確認します。
sudo datadog-agent check oracle
oracle.can_connect の status が 0(OK)で、oracle.session_count などメトリクスの値が 148 件(同じメトリクスの PDB 別などの系列を含む数)出力されました。タグには hosting_type:OCI、oracle_version:23.26.3.3.0、pdb:g4256714d933780_adbtest01 が付いていて、ADB であることと PDB 名がタグに入っています。ウォレット無しの TCPS でエラーは出ませんでした。
4.3. 負荷のかけ方
各画面にデータを出すために、前回の記事で作った SCOTT スキーマの索引なしテーブル LOAD_TEST_NOIDX(50 万行、ID・NAME・SCORE の 3 列)に SELECT だけの負荷を 8 分間かけました。ADB の結果キャッシュを避けるため、すべての SQL に NO_RESULT_CACHE ヒントを付け、バインド変数の値を毎回変えています。前回の記事1 と同じ 4 種と遅い 3 重自己結合に加えて、送られる内容を見るために 2 種を足しました。
| 役割 | SQL | 1 回の所要時間(中央値) |
|---|---|---|
| 全表走査の集計 | COUNT(*), MIN(score), MAX(score) ... WHERE name LIKE :b |
1.31 秒 |
| 自己結合 | t a JOIN t b ON a.id = b.id WHERE a.score BETWEEN :lo AND :hi |
0.06 秒 |
| 並べ替えて上位 100 件 | ... WHERE score >= :s ORDER BY name, id FETCH FIRST 100 ROWS ONLY |
0.47 秒 |
| GROUP BY 集計 | MOD(id, :m), COUNT(*), AVG(score), MAX(name) ... GROUP BY MOD(id, :m) |
6.74 秒 |
| コメント付き | /* dd-comment-test: order_id=12345 customer=taro@example.com */ ... WHERE score = :s |
0.02 秒 |
| リテラル直書き |
... WHERE score = 729 OR name = 'LITERAL_TEST_729'(値は毎回変える、バインドなし) |
0.78 秒 |
| 遅い 3 重自己結合 | t a JOIN t b ON a.score = b.score JOIN t c ON b.score = c.score WHERE a.id BETWEEN :lo AND :hi |
37.98 秒 |
上の 6 種を 3 スレッドで順に繰り返し、遅い結合は別スレッドで繰り返します。8 分間で合計 875 回実行し、エラーはありませんでした。コメント付きの SQL は、コメントに個人情報に見える値を入れておき、それが Datadog に届くかを見るためのものです。リテラル直書きは、DB 側では実行のたびに別の SQL_ID になります。
5. 実行結果
5.1. Databases 一覧とホスト名
まず reported_hostname を書かずに起動したときの Databases 一覧が図 3 です。
図 3: reported_hostname 無し。Database Host 列が $resolved_hostname という文字列になる
Database Host 列に $resolved_hostname というテンプレートの文字列がそのまま出ています。詳細画面の URL も /databases/detail/instance/_resolved_hostname でした。Agent のログにも同じタイミングで、ホスト名を決められないので reported_hostname を検討するよう ERROR が出ています。
ERROR | (pkg/collector/corechecks/oracle/init.go:92 in init) | adb.ap-tokyo-1.oraclecloud.com:1522/g4256714d933780_adbtest01_low.adb.oraclecloud.com> failed to determine hostname, consider setting reported_hostname
reported_hostname: 'adbtest01' を追加して再起動すると、adbtest01 の行が新しく現れました(図 4)。ERROR も出なくなります。$resolved_hostname の行は時間範囲に入っている間は別のホストとして残るので、一覧は一時的に 2 行になります。
図 4: reported_hostname を設定後。adbtest01 の行が追加され、旧行も時間範囲内は残る
5.2. Databases 詳細と Active Connections
一覧から adbtest01 を開くと、負荷中の待機イベント別のセッション数と Top Queries が表示されます(図 5)。
図 5: Databases 詳細(負荷中)。待機イベント別のロードと Top Queries、PDB のセッション数
待機イベントは resmgr:cpu quantum と CPU が大半で、負荷の開始直後だけ db file sequential read が出ています。resmgr:cpu quantum は、リソースマネージャが CPU の割り当てを待たせている時間を表す待機イベントです8。Always Free の 1 OCPU で 4 スレッドの全表走査を実行したので、CPU が足りない分がそのまま待機として見えています。Top Queries には負荷側の SQL と Agent 自身の SQL が混ざって並びます(5.3 章)。Blocking Queries は「見つからない」、Calling Services は APM(Datadog のアプリケーション監視)と連携していないので 0 件です。
Active Connections タブは、画面の説明に「These snapshots of V$SESSION were taken every 10 seconds」とあるとおり、V$SESSION の 10 秒ごとのスナップショットです(図 6)。
図 6: Active Connections。V$SESSION の 10 秒ごとのスナップショットと、待機イベント別のロード
負荷中は最大 8 セッション、Query Duration の P95(95 パーセンタイル)は 36〜39 秒でした(遅い 3 重自己結合)。無負荷の区間は「0 connections detected for 45 consecutive snapshots」のように 1 行にまとまります。
採取方法は設定で切り替えられ、query_samples.active_session_history: true にすると Agent が自分でサンプリングする代わりに V$ACTIVE_SESSION_HISTORY を読みます。conf.yaml.example には「Oracle の有償オプションが必要で追加費用がかかることがある」と警告がありますが5、ADB では Database Actions の Performance Hub に ASH Analytics のタブがあり9、監視ユーザーからも V$ACTIVE_SESSION_HISTORY は 38,134 行、ADMIN からは DBA_HIST_ACTIVE_SESS_HISTORY も 21,029 行読めました。そこで V$ACTIVE_SESSION_HISTORY の SELECT 権限を追加して切り替え、3 分間の負荷をかけたのが図 7 です。
図 7: Active Connections(ASH 方式)。スナップショットが 1 秒刻みになり、待機イベントの種類も増える
スナップショットの時刻が 13:09:20 から 13:09:35 の間に 10 行あり、1 秒刻みで採取されています。画面の説明文は「10 秒ごと」のままですが、これは Agent が ASH の行を 10 秒ごとにまとめて取りに行く間隔で、行そのものは ASH の 1 秒間隔です。待機イベントの種類も db file scattered read、gc cr multi block request、PX Deq: Slave Session Stats のように細かく出るようになりました。負荷は 13:09:06 に終わっているので、図の表に並んでいるのは同じ ADB を監視している別の監視ユーザー(前回の記事の New Relic 用)のセッションです。
5.3. Query Metrics
Queries の画面は、Datadog が Normalized Query(正規化クエリ)と呼ぶ単位ごとの集計です。正規化クエリは、SQL 本文の値(数値や文字列のリテラル)を ? に置き換えて、値だけが違う SQL を 1 本にまとめたものです。たとえば WHERE score = 729 と WHERE score = 107 の 2 つの SQL は、どちらも WHERE score = ? という 1 本の正規化クエリとして数えられます。Total Duration の降順で並べたのが図 8 で、直近 1 時間で 383 本のクエリが載っています。SYS の再帰 SQL(sysauth$ や seg$ への問い合わせ)も含まれます。
図 8: Query Metrics(Total Duration 降順)。負荷 SQL と Agent 自身の SQL が並ぶ
上位 14 件を表にします。発行元は SQL の文面から判断しました。この画面には DB ユーザーで絞るフィルタが無いためです。
| 順位 | Normalized Query(先頭) | 発行元 | Count | Avg Duration | Total Duration |
|---|---|---|---|---|---|
| 1 | SELECT COUNT(*), SUM(c.score) FROM ... a JOIN ... ON a.score = b.score JOIN ... |
負荷(遅い結合) | 12 | 2 分 29 秒 | 29 分 48 秒 |
| 2 | SELECT MOD(id, :m) grp, COUNT(*), AVG(score), MAX(name) ... ORDER BY ? |
負荷(GROUP BY) | 133 | 7.00 秒 | 15 分 31 秒 |
| 3 | SELECT COUNT(*), MIN(score), MAX(score) ... WHERE name LIKE :b |
負荷(全表走査) | 134 | 1.44 秒 | 3 分 13 秒 |
| 4 | SELECT COUNT(*) FROM ... WHERE score = ? OR name = ? |
負荷(リテラル直書き) | 133 | 684 ミリ秒 | 1 分 31 秒 |
| 5 | SELECT id, name, score ... WHERE score >= :s ORDER BY name, id FETCH FIRST ? ROWS ONLY |
負荷(上位 100 件) | 133 | 570 ミリ秒 | 1 分 15 秒 |
| 6 | WITH total_bytes AS (SELECT SUM(bytes) FROM dba_data_files) ... |
Agent(表領域) | 9 | 6.60 秒 | 59.4 秒 |
| 7 | SELECT S.SID, S.SERIAL#, SE.EVENT, SE.WAIT_CLASS, NVL(SE.TOTAL_WAITS, ?), ... |
Agent(セッションと待機) | 10 | 5.22 秒 | 52.2 秒 |
| 8 | SELECT s.con_id con_id, c.name pdb_name, s.force_matching_signature, plan_hash_value, ... |
Agent(クエリ集計) | 9 | 4.83 秒 | 43.5 秒 |
| 9 | SELECT s.con_id con_id, c.name pdb_name, sql_id, plan_hash_value, dbms_lob.substr(sql_fulltext, ?, ?) ... |
Agent(SQL 本文) | 9 | 3.24 秒 | 29.2 秒 |
| 10 | SELECT COUNT(*) FROM ... a JOIN ... b ON a.id = b.id WHERE a.score BETWEEN :lo AND :hi |
負荷(自己結合) | 133 | 72.3 ミリ秒 | 9.61 秒 |
| 11 | SELECT S.ACTION, S.MACHINE, S.USERNAME, S.SCHEMANAME, S.SQL_ID, ... |
Agent(アクティビティ採取) | 10 | 692 ミリ秒 | 6.92 秒 |
| 12 | SELECT S.SQL_ID, S.SQL_FULLTEXT, S.CHILD_NUMBER, RAWTOHEX(S.CHILD_ADDRESS), ... |
Agent(SQL 本文) | 1 | 2.98 秒 | 2.98 秒 |
| 13 | SELECT COUNT(*) FROM ... WHERE score = :s |
負荷(コメント付き) | 133 | 21.2 ミリ秒 | 2.82 秒 |
| 14 | SELECT child_number, timestamp, operation, options, object_name, ... |
Agent(実行計画) | 155 | 17.6 ミリ秒 | 2.72 秒 |
4 章の表はクライアント側で測った 8 分間の中央値、ここは Datadog が集計した 1 時間の平均なので値は一致しません。リテラル直書きの SQL(4 位)は DB 側では実行のたびに別の SQL_ID になりますが、ここでは値を ? に置き換えた 1 本にまとまっています。DB 側の実行回数 142 に対して Count が 133 なのは、Datadog の集計が 1 分間隔で、負荷の開始と終了の端の分が集計範囲に入っていないためと考えられます(未確認)。コメント付きの SQL(13 位)は、正規化クエリではコメントもヒントも消えています。
表の「Agent」の行は、Agent が監視のために実行している SQL です。1 OCPU の Always Free では 1 回あたり 3.2〜6.6 秒かかっていますが、公式の計測では 2 vCPU の RDS インスタンスで DB 側のオーバーヘッドは CPU 時間の約 0.2% とされており10、CPU が 1 つの構成なので 1 回あたりの時間が長く出ていると考えられます。
5.4. Query Samples と Event Attributes
クエリの行を開くと、Explain Plans・Samples・Hosts・Users などのタブが表示されます。Samples は Active Connections と同じ 10 秒ごとの採取なので、1 回 1 秒未満の SQL は採取にかかった回だけが載ります。リテラル直書きの SQL は 142 回実行して 3 件、コメント付きは 1 件でした。
図 9: リテラル直書き SQL の Samples。142 回の実行のうち 3 件が採取されている
サンプルを開くと、接続元・待機イベント・SQL 本文と、Event Attributes タブに Datadog が受け取った属性の一覧が表示されます(図 10)。
図 10: サンプルの Event Attributes。db.metadata.comments にヒントが原文で入っている(接続元の値はマスク)
コメント付き SQL のサンプルでは、db.metadata.comments に /* dd-comment-test: order_id=12345 customer=taro@example.com */ と /*+ NO_RESULT_CACHE */ の 2 つが原文のまま入っていました(図 11)。
図 11: コメント付き SQL のサンプル。テスト用に入れたメールアドレスがそのまま届いている
届いている属性を表にまとめます。値は今回のサンプルのもので、接続元に関する値はマスクしています。
| 属性 | 値 | 元になる情報 |
|---|---|---|
| db.statement | SELECT COUNT(*) FROM SCOTT.LOAD_TEST_NOIDX WHERE score = ? OR name = ? |
SQL 本文を正規化したもの |
| db.metadata.comments | ["/*+ NO_RESULT_CACHE */"] |
SQL 中のコメントとヒント(原文) |
| db.metadata.tables / commands / operation_type | SCOTT.LOAD_TEST_NOIDX / SELECT / read | SQL の解析結果 |
| db.user / oracle.os_user | SCOTT / (OS のユーザー名) | V$SESSION の USERNAME / OSUSER |
| network.client.ip / port | (接続元のマシン名)/ 53674 | V$SESSION の MACHINE / PORT |
| db.application | (python.exe のフルパス) | V$SESSION の PROGRAM |
| oracle.module / action | dbm_load / w3 | DBMS_APPLICATION_INFO で設定した値 |
| oracle.sql_id / sql_plan_hash_value / force_matching_signature | ftqugzq3wqvv1 / 1247778635 / 12170798131100133000 | V$SESSION と V$SQL |
| db.wait_event / wait_event_type | resmgr:cpu quantum / Scheduler | V$SESSION の待機情報 |
| oracle.logon_time / sql_exec_start / session_id / serial | 時刻とセッション番号 | V$SESSION |
| duration / delta_duration / wait_duration | ナノ秒 | 採取間隔から推定した値を含む |
network.client.ip という名前ですが値は IP ではなく、V$SESSION の MACHINE の値(今回は負荷をかけた PC の名前)でした。SQL の実行結果やバインド変数の値は届いていません。
5.5. Explain Plans
Explain Plans タブには、採取されたサンプルに対応する実行計画が表示されます。遅い 3 重自己結合の計画は 12 ノードで、Map View では木として描かれ、Formatted JSON では各ノードのコスト・行数・述語が JSON で出ます(図 12)。
図 12: 遅い 3 重自己結合の Explain Plan。PX COORDINATOR / PX SEND を含む 12 ノード
計画に PX COORDINATOR と PX BLOCK ITERATOR が入っていて、Always Free の 1 OCPU でもパラレル実行の計画が選ばれています。バインド変数で書いた SQL の述語は A.ID >=: LO AND A.ID <=: HI と変数名のままでした。
リテラル直書きの SQL は、Explain Plans が「No Explain Plans available in this time frame」と 0 件でした。1 回 1 秒未満で採取にかからなかったためと考えられます(未確認)。そこで 3 重自己結合をリテラル値で書き直した SQL(WHERE a.id BETWEEN 394782 AND 396282 AND a.name <> 'LITERAL_TEST_394782' という書き方、値は毎回変える)を 4 回実行し、その計画を確認しました(図 13)。
図 13: リテラル値で書いた遅い結合の Explain Plan(Formatted JSON)。述語のリテラルが ? になっている
filter_predicates は (INTERNAL_FUNCTION(A.NAME) AND A.ID >= ? AND A.ID <= ? AND INTERNAL_FUNCTION(A.NAME) <> ?) で、数値も文字列も ? に置き換わっていました。
5.6. Recommendations とダッシュボード
Recommendations は直近 1 週間で 0 件でした。索引なしの全表走査を 8 分間かけましたが、Missing Index のような推奨は出ていません。
Oracle 向けのプリセットダッシュボード「DBM Oracle Database Overview」は、Oracle インテグレーションをインストールしたあとも Dashboards の一覧に出ませんでした。Plan & Usage の Plan 画面の比較表で、「Out-of-the-box dashboards」は今回の Free プランでは対象外になっています(図 14)。
図 14: Plan 画面。Free プランでは Out-of-the-box dashboards が使えない
この比較表に Database Monitoring の行はなく、Trial Management には「No trials available at this time」と出ていました。DBM の各画面はトライアルの開始操作なしに表示されています。
6. 考察
6.1. ホスト名は最初から書く
公式のトラブルシューティングには、ADB では V$INSTANCE.HOST_NAME が null なのでホスト名が空になり、reported_hostname を設定するよう書かれています6。今回は空になるのではなく、$resolved_hostname というテンプレートの文字列がそのまま Databases 一覧に載りました。Agent 7.67.0 のリリースノートには「Set hostname for Oracle autonomous database」という修正がありますが3、7.83.2 でも $resolved_hostname の行は出ています。reported_hostname を後から足すと、時間範囲内は旧行が残って 2 行になるので、conf.yaml を書く時点で入れておくのが確実です。
6.2. Datadog に何が送られるか
監視を入れると DB の中身がどこまで外に出るのかは、DBA が先に確認する点です。5.4 章の Event Attributes と 5.5 章の Explain Plans で確認した範囲をまとめます。
| 種類 | 送られ方 |
|---|---|
| SQL 本文 | リテラルは数値も文字列も ?。バインド変数は :lo のように名前が残る。コメントとヒントは本文からは消える |
| 実行計画の述語 | リテラルは ?。バインド変数は名前が残る |
| SQL コメント |
db.metadata.comments に原文のまま入る(ヒントも同様) |
| 接続元 | マシン名(V$SESSION の MACHINE)、OS ユーザー名、プログラムのパス、module / action |
| 結果行・バインド値 | 送られない |
Data Collected のページには、バインド値はすべて匿名化される一方で SQL コメントは匿名化を通らずに送られることがあると書かれています11。その実体が db.metadata.comments で、正規化した本文からは消えても metadata には残ります。アプリケーションがトレース用のタグや利用者の情報を SQL コメントに入れる運用だと、その値がそのまま Datadog へ届きます。conf.yaml.example の obfuscator_options には collect_comments がありデフォルトは true なので5、止めたい場合はこれを false にします(この設定は試していません)。
実行計画の述語のリテラルが ? になる点は、前回の記事の 6.5 章1 で New Relic では述語にリテラルが残っていたのと違う結果でした。Agent 7.83.2 のソースを読むと、Oracle チェックは V$SQL_PLAN_STATISTICS_ALL から取った ACCESS_PREDICATES と FILTER_PREDICATES の文字列を、SQL 本文と同じ難読化の関数(ObfuscateSQLString)に通してから送っています12。Oracle チェックの難読化はデフォルトで「難読化して正規化する」モードで、リテラルは ? に置き換え、バインド変数はそのまま残す設定です。述語も SQL の断片として同じ処理を受けるので、A.ID >= 394782 が A.ID >= ? になります。A.ID >=: LO のように : と LO の間に空白が入るのは、述語の元の文字列 A.ID>=:LO で >= に続く : が演算子の一部として読まれ、LO が別の語として正規化されたためと考えられます(:HI のように : から始まる場合はバインド変数として 1 つの語のまま残っています)。
接続元のマシン名や OS ユーザー名は、今回は負荷をかけた PC の情報でした。アプリケーションのセッションが対象になれば、アプリサーバーのホスト名・OS ユーザー・実行ファイル名がそのまま送られます。
6.3. プランと課金の単位
今回使ったのは Free プランで、Trial Management にも開始できるトライアルはありませんでした(5.6 章)。
DBM の料金は監視対象の DB ホスト単位で、1 ホストあたり 200 本の正規化クエリ(5.3 章)が含まれます13。Free プランで表示されている状態がどう扱われるかは Usage の画面が翌日以降に更新されてから確認する必要があり、本記事の時点では未確認です。継続して使う場合は Plan & Usage の Usage Overview で Database Monitoring のホスト数を確認してください。
なお、Datadog には OCI の Connector Hub 経由で ADB のメトリクスを取り込む、Agent を使わないインテグレーションも別にあります14。クエリ単位の情報は DBM 側の機能なので、今回は対象にしていません。
7. まとめ
| 確かめたこと | 結果 |
|---|---|
| ウォレット無しの接続 | ADB 側で TLS 接続を許可していれば、protocol: TCPS だけで接続できた。GRANT 37 文はすべて実行できる |
| ホスト名 |
reported_hostname を書かないと一覧に $resolved_hostname の行が出る。最初から書く |
| 見えるもの | Databases・Queries・Samples・Explain Plans・Active Connections・Recommendations |
| 見えないもの | プリセットダッシュボード(Free プランの制約) |
| Datadog に送られるもの | SQL 本文と実行計画の述語のリテラルは ?。SQL コメントは原文のまま届く。接続元のマシン名・OS ユーザー・プログラムも届く |
公式手順との差は、ウォレットを書かないこと、reported_hostname を最初から書くこと、秘密を ENC[] で参照することの 3 点で、それ以外は公式のとおりに進めば ADB でも上の表に挙げた 6 つの画面が使えます。SQL コメントと接続元の情報がそのまま届く点は、アプリケーション側の SQL の書き方と合わせて先に確認しておく項目です。
前回の New Relic Database 3601 と比べると、遅い SQL の一覧・実行計画・セッション・待機イベントが見える点は同じでした。違ったのは、実行計画の述語のリテラルが Datadog では ? になること、SQL コメントが metadata として届くこと、ADB 向けの手順が Preview ではなく通常のドキュメントとして用意されていることです。DB の名前の扱いは、New Relic ではエンティティ名がホストとポートになり、Datadog では reported_hostname を書かないとテンプレートの文字列が出るという違いで、どちらも設定の追加が必要な点は同じでした。
8. 付録: ウォレットで接続する場合(ADB 側を変えないとき)
ADB のネットワーク設定を変えられない場合は、公式手順のとおりウォレットを Agent のホストに置いて接続します。ウォレットは OCI コンソールの ADB 詳細画面から「データベース接続」でダウンロードした zip を展開したもので、Agent の実行ユーザーだけが読める場所に置きます。
sudo mkdir -p /etc/datadog-agent/wallet
sudo cp Wallet_adbtest01/{cwallet.sso,tnsnames.ora} /etc/datadog-agent/wallet/
sudo chown -R dd-agent:dd-agent /etc/datadog-agent/wallet
sudo chmod 750 /etc/datadog-agent/wallet
sudo chmod 640 /etc/datadog-agent/wallet/*
conf.yaml には 3.4 章の設定に wallet: /etc/datadog-agent/wallet を 1 行追加します。この設定で datadog-agent check oracle を実行したところ、oracle.can_connect は OK で、メトリクスもウォレット無しのときと同じ 148 個が出ました。ウォレットの zip には複数のファイルが入っていますが、今回は自動ログイン用の cwallet.sso と tnsnames.ora の 2 つを置いた状態で接続できました。
今回の ADB は TLS 接続を許可した状態なので、ここで確かめたのは「ウォレットを渡しても接続できる」ことまでです。mTLS 必須のままの ADB でウォレットが無いと接続できないことは、前回の記事の 1 章に書いた前提のとおりですが、今回は実測していません。
参考
-
New Relic Database 360 で Oracle Autonomous Database を監視してみた(前回の記事。ADB 側で TLS 接続を許可する手順は 3.2 章) ↩ ↩2 ↩3 ↩4 ↩5
-
Setting Up Database Monitoring for Oracle Autonomous Database(Datadog 公式ドキュメント。ADB 向けの監視ユーザー作成・GRANT・conf.yaml の手順。Agent は外部の Oracle クライアントを必要としない旨もここにある。Agent の置き場は同ページから案内される DBM Setup Architecture に「別のホストに置く」とある) ↩ ↩2 ↩3 ↩4 ↩5
-
Datadog Agent 7.47.0 のリリースノート(「Add support for Oracle Autonomous Database (Oracle Cloud Infrastructure)」。ホスト名の修正は 7.67.0 の「Set hostname for Oracle autonomous database」) ↩ ↩2
-
Update Network Options to Allow TLS or Require Only Mutual TLS (mTLS) Authentication on Autonomous AI Database(Oracle 公式ドキュメント。TLS 接続を許可するには ACL かプライベートエンドポイントが必要) ↩
-
oracle.d/conf.yaml.example(7.83.2)(datadog-agent リポジトリの検証した版のタグ。protocol / wallet / reported_hostname / query_samples.active_session_history / obfuscator_options.collect_comments の説明とデフォルト値。oracle_client の説明に「Oracle driver for Go」とある) ↩ ↩2 ↩3 ↩4
-
Oracle DBM のトラブルシューティング(Datadog 公式ドキュメント。「No Oracle DB hostname reported」の節に ADB で HOST_NAME が null になる旨と reported_hostname の推奨がある。セルフホスト向けの dd_session ビューの手順は self-hosted のページ) ↩ ↩2 ↩3
-
Secrets Management(Datadog 公式ドキュメント。ENC[] 記法と、file.yaml など secret_backend_type の一覧) ↩
-
Descriptions of Wait Events(Oracle Database Reference。resmgr:cpu quantum などの待機イベントの説明) ↩
-
Use Database Actions to Monitor Active Session History Analytics and SQL Statements(Oracle 公式ドキュメント。ADB の Performance Hub に ASH Analytics タブがある) ↩
-
Agent Integration Overhead(Datadog 公式ドキュメント。Oracle タブに RDS db.m5.large・TPC-C での Agent のオーバーヘッドの実測値) ↩
-
Data Collected(Database Monitoring)(Datadog 公式ドキュメント。バインド値の匿名化、SQL コメントが匿名化を通らずに送られうる旨、200 本の正規化クエリの上限) ↩
-
datadog-agent 7.83.2 の Oracle チェック statements.go(
handlePredicateが述語文字列をObfuscateSQLStringに渡している。難読化のデフォルト値は同 config/config.go のGetDefaultObfuscatorOptions) ↩ -
Datadog の料金ページ(Database Monitoring の課金単位は DB ホスト、1 ホストあたり 200 本の正規化クエリ) ↩
-
OCI Autonomous AI Database インテグレーション(Datadog 公式ドキュメント。Connector Hub 経由でメトリクスだけを取り込む、Agent 不要のインテグレーション) ↩













