バージョンごとのドキュメント一覧

28.5. 動的追跡 #

<title>Dynamic Tracing</title>

<productname>PostgreSQL</productname> provides facilities to support dynamic tracing of the database server. This allows an external utility to be called at specific points in the code and thereby trace execution. PostgreSQLは、データベースサーバの動的追跡をサポートする機能を提供します。 これにより、外部ユーティリティをコードの特定のポイントで呼び出すことができ、追跡を行うことができるようになります。

A number of probes or trace points are already inserted into the source code. These probes are intended to be used by database developers and administrators. By default the probes are not compiled into <productname>PostgreSQL</productname>; the user needs to explicitly tell the configure script to make the probes available. 多くの追跡やプローブ用のポイントは、すでにソースコード内部に存在します。 これらのプローブはデータベースの開発者や管理者が使うことを意図しています。 デフォルトでは、これらのプローブはPostgreSQLにコンパイルされません。ユーザは明示的にconfigureスクリプトでプローブを有効にするように設定する必要があります。

Currently, the <ulink url="https://en.wikipedia.org/wiki/DTrace">DTrace</ulink> utility is supported, which, at the time of this writing, is available on Solaris, macOS, FreeBSD, NetBSD, and Oracle Linux. The <ulink url="https://sourceware.org/systemtap/">SystemTap</ulink> project for Linux provides a DTrace equivalent and can also be used. Supporting other dynamic tracing utilities is theoretically possible by changing the definitions for the macros in <filename>src/include/utils/probes.h</filename>. 現在、これを書いている時点ではSolaris、macOS、FreeBSD、NetBSD、Oracle Linuxで利用可能なDTraceユーティリティがサポートされています。 SystemTapプロジェクトではDTrace相当の機能をLinux向けに提供しており、それを使うこともできます。 他の動的追跡ユーティリティのサポートは、src/include/utils/probes.h内のマクロ定義を変更することで、理論上は可能です。

28.5.1. 動的追跡のためのコンパイル #

<title>Compiling for Dynamic Tracing</title>

By default, probes are not available, so you will need to explicitly tell the configure script to make the probes available in <productname>PostgreSQL</productname>. To include DTrace support specify <option>&#45;-enable-dtrace</option> to configure. See <xref linkend="configure-options-devel"/> for further information. 《マッチ度[88.161994]》デフォルトでは、プローブは有効ではありません。そのため、PostgreSQLでプローブが利用できるようにするためにconfigureスクリプトで明示的に設定しなければなりません。 DTraceサポートを含めるには、configureに--enable-dtraceを指定します。 詳細は17.3.3.6を参照してください。 《機械翻訳》デフォルトではプローブは利用できませんので、configureスクリプトに明示的にプローブをPostgreSQLで利用可能にするように指示する必要があります。 詳細は17.3.3.6を参照してください。

28.5.2. 組み込み済みのプローブ #

<title>Built-in Probes</title>

A number of standard probes are provided in the source code, as shown in <xref linkend="dtrace-probe-point-table"/>; <xref linkend="typedefs-table"/> shows the types used in the probes. More probes can certainly be added to enhance <productname>PostgreSQL</productname>'s observability. 表 28.48で示されるように、多くの標準的なプローブがソースコード内で提供されています。表 28.49はプローブで使用している型を示しています。 また、PostgreSQL内の可観測性を強化するためのプローブ追加が可能です。

表28.48 組み込み済みのDTraceプローブ

<title>Built-in DTrace Probes</title>
名前パラメータ説明
transaction-start(LocalTransactionId)新しいトランザクションの開始を捕捉するプローブです。arg0はトランザクションIDです。
transaction-commit(LocalTransactionId)トランザクションの正常終了を捕捉するプローブです。arg0はトランザクションIDです。
transaction-abort(LocalTransactionId)トランザクションの異常終了を捕捉するプローブです。arg0はトランザクションIDです。
query-start(const char *)問い合わせ処理の開始を捕捉するプローブです。arg0は問い合わせ文字列です。
query-done(const char *)問い合わせ処理の正常終了を捕捉するプローブです。arg0は問い合わせ文字列です。
query-parse-start(const char *)問い合わせのパース処理の開始を捕捉するプローブです。arg0は問い合わせ文字列です。
query-parse-done(const char *)問い合わせのパース処理の正常終了を捕捉するプローブです。arg0は問い合わせ文字列です。
query-rewrite-start(const char *)問い合わせの書き換え処理の開始を捕捉するプローブです。arg0は問い合わせ文字列です。
query-rewrite-done(const char *)問い合わせの書き換え処理の正常終了を捕捉するプローブです。arg0は問い合わせ文字列です。
query-plan-start()問い合わせのプランナ処理の開始を捕捉するプローブです。
query-plan-done()問い合わせのプランナ処理の正常終了を捕捉するプローブです。
query-execute-start()問い合わせの実行(エグゼキュータ)処理の開始を捕捉するプローブです。
query-execute-done()問い合わせの実行(エグゼキュータ)処理の正常終了を捕捉するプローブです。
statement-status(const char *) サーバプロセスによるpg_stat_activity.statusの状態の更新を捕捉するプローブです。 arg0は新しい状態の文字列です。
checkpoint-start(int) チェックポイントの開始を捕捉するプローブです。 arg0はチェックポイントの種類の違い(shutdown、immediate、force)を区別するためのビットフラグを持っています。
checkpoint-done(int, int, int, int, int) チェックポイントの正常終了を捕捉するプローブです。 (以下に示すプローブはチェックポイント進行に従い順番に捕捉されます。) arg0は書き込まれたバッファ数、arg1はバッファの総数、arg2、3、4はそれぞれ追加、削除、再利用されたWALファイルの数です。
clog-checkpoint-start(bool) CLOG部分のチェックポイントの開始を捕捉するプローブです。 arg0がtrueならば通常のチェックポイントであり、falseならばシャットダウン時のチェックポイントを示します。
clog-checkpoint-done(bool) CLOG部分のチェックポイントの正常終了を捕捉するプローブです。 arg0はclog-checkpoint-startと同じ意味を持ちます。
subtrans-checkpoint-start(bool) サブトランザクション部分のチェックポイントの開始を捕捉するプローブです。 arg0がtrueならば通常のチェックポイントであり、falseならばシャットダウン時のチェックポイントを示します。
subtrans-checkpoint-done(bool) サブトランザクション部分のチェックポイントの正常終了を捕捉するプローブです。 arg0はsubtrans-checkpoint-startと同じ意味を持ちます。
multixact-checkpoint-start(bool) マルチトランザクション部分のチェックポイントの開始を捕捉するプローブです。 arg0がtrueならば通常のチェックポイントであり、falseならばシャットダウン時のチェックポイントを示します。
multixact-checkpoint-done(bool) マルチトランザクション部分のチェックポイントの正常終了を捕捉するプローブです。 arg0はmultixact-checkpoint-startと同じ意味を持ちます。
buffer-checkpoint-start(int) チェックポイントのバッファ書き込み部分の開始を捕捉するプローブです。 arg0はチェックポイントの種類の違い(shutdown、immediate、force)を区別するためのビットフラグを持っています。
buffer-sync-start(int, int) チェックポイント中のダーティバッファの書き出し開始を捕捉するプローブです(どのバッファが書き出す必要があるのかを判定した後です)。 arg0はバッファの総数で、arg1は現在ダーティであり、書き出す必要のあるバッファ数です。
buffer-sync-written(int) チェックポイント中のそれぞれのバッファの書き出し後を捕捉するプローブです。 arg0はバッファのIDを示します。
buffer-sync-done(int, int, int) 全てのダーティバッファの書き出し後を捕捉するプローブです。 arg0はバッファの総数です。 arg1はチェックポイント処理により実際に書き出されたバッファ数です。 arg2は書き出されるであろうと見積もられたバッファ数(buffer-sync-startのarg1相当)です。 違いはチェックポイント中に他のプロセスがバッファを書き出したことを反映しています。
buffer-checkpoint-sync-start()カーネルへのダーティバッファの書き出し処理発行の後、そして同期書き出し要求を開始する前を捕捉するプローブです。
buffer-checkpoint-done()バッファからディスクへの同期書き出し処理の終了を捕捉するプローブです。
twophase-checkpoint-start()二相コミット部分のチェックポイントの開始を捕捉するプローブです。
twophase-checkpoint-done()二相コミット部分のチェックポイントの正常終了を捕捉するプローブです。
buffer-extend-start(ForkNumber, BlockNumber, Oid, Oid, Oid, int, unsigned int)Probe that fires when a relation extension starts. arg0 contains the fork to be extended. arg1, arg2, and arg3 contain the tablespace, database, and relation OIDs identifying the relation. arg4 is the ID of the backend which created the temporary relation for a local buffer, or InvalidBackendId (-1) for a shared buffer. arg5 is the number of blocks the caller would like to extend by.
buffer-extend-done(ForkNumber, BlockNumber, Oid, Oid, Oid, int, unsigned int, BlockNumber)Probe that fires when a relation extension is complete. arg0 contains the fork to be extended. arg1, arg2, and arg3 contain the tablespace, database, and relation OIDs identifying the relation. arg4 is the ID of the backend which created the temporary relation for a local buffer, or InvalidBackendId (-1) for a shared buffer. arg5 is the number of blocks the relation was extended by, this can be less than the number in the buffer-extend-start due to resource constraints. arg6 contains the BlockNumber of the first new block.
buffer-read-start(ForkNumber, BlockNumber, Oid, Oid, Oid, int)Probe that fires when a buffer read is started. arg0 and arg1 contain the fork and block numbers of the page. arg2, arg3, and arg4 contain the tablespace, database, and relation OIDs identifying the relation. arg5 is the ID of the backend which created the temporary relation for a local buffer, or InvalidBackendId (-1) for a shared buffer.
buffer-read-done(ForkNumber, BlockNumber, Oid, Oid, Oid, int, bool)Probe that fires when a buffer read is complete. arg0 and arg1 contain the fork and block numbers of the page. arg2, arg3, and arg4 contain the tablespace, database, and relation OIDs identifying the relation. arg5 is the ID of the backend which created the temporary relation for a local buffer, or InvalidBackendId (-1) for a shared buffer. arg6 is true if the buffer was found in the pool, false if not.
buffer-flush-start(ForkNumber, BlockNumber, Oid, Oid, Oid) 共有バッファへの書き込み要求開始を捕捉するプローブです。 arg0とarg1はそのページのフォーク番号とブロック番号です。 arg2、arg3、arg4は対象のリレーションを識別するテーブル空間、データベース、そしてテーブルのOIDです。
buffer-flush-done(ForkNumber, BlockNumber, Oid, Oid, Oid) 書き込み要求の終了を捕捉するプローブです。 (これはカーネルへデータを渡したタイミングのみを反映していることに注意してください。大抵、この時点ではまだ実際にディスクへ書き込まれていません。) 引数はbuffer-flush-startと同じです。
wal-buffer-write-dirty-start() WALバッファ領域の不足によるサーバプロセスのダーティなWALバッファの書き出しを捕捉するプローブです。 (もしこれが頻発するようでしたら、wal_buffersが小さすぎることを意味します。)
wal-buffer-write-dirty-done()ダーティなWALバッファの書き出し終了を捕捉するプローブです。
wal-insert(unsigned char, unsigned char) WALレコードの挿入を捕捉するプローブです。 arg0はレコードのリソースマネージャ(rmid)です。 arg1は情報フラグです。
wal-switch()WALセグメントのスイッチ要求を捕捉するプローブです。
smgr-md-read-start(ForkNumber, BlockNumber, Oid, Oid, Oid, int) リレーションからのブロック読み込みの開始を捕捉するプローブ。 arg0とarg1はそのページのフォーク番号とブロック番号です。 arg2、arg3、arg4は対象のリレーションを識別するテーブル空間、データベース、そしてリレーションのOIDです。 arg5は一時テーブルをローカルバッファに作成していればそのバックエンドのIDであり、InvalidBackendId(-1)であれは共有バッファを指します。
smgr-md-read-done(ForkNumber, BlockNumber, Oid, Oid, Oid, int, int, int) ブロックの読み込み終了を捕捉するプローブです。 arg0とarg1はそのページのフォーク番号とブロック番号です。 arg2、arg3、arg4は対象のリレーションを識別するテーブル空間、データベース、そしてリレーションのOIDです。 arg5は一時テーブルをローカルバッファに作成していればそのバックエンドのIDであり、InvalidBackendId(-1)であれは共有バッファを指します。 arg6は実際に読み込んだバイト数、arg7はリクエストされた読み込みバイト数です(もし、これらに差異があった場合、何らかの問題があることを示します)。
smgr-md-write-start(ForkNumber, BlockNumber, Oid, Oid, Oid, int) リレーションへのブロック書き出しの開始を捕捉するプローブです。 arg0とarg1はそのページのフォーク番号とブロック番号です。 arg2、arg3、arg4は対象のリレーションを識別するテーブル空間、データベース、そしてリレーションのOIDです。 arg5は一時テーブルをローカルバッファに作成していればそのバックエンドのIDであり、InvalidBackendId(-1)であれは共有バッファを指します。
smgr-md-write-done(ForkNumber, BlockNumber, Oid, Oid, Oid, int, int, int) ブロックの書き出し終了を捕捉するプローブです。 arg0とarg1はそのページのフォーク番号とブロック番号です。 arg2、arg3、arg4は対象のリレーションを識別するテーブル空間、データベース、そしてリレーションのOIDです。 arg5は一時テーブルをローカルバッファに作成していればそのバックエンドのIDであり、InvalidBackendId(-1)であれは共有バッファを指します。 arg6は実際に書き出したバイト数、arg7はリクエストされた書き出しバイト数です(もし、これらに差異があった場合、何らかの問題があることを示します)。
sort-start(int, bool, int, int, bool, int) ソート処理の開始を捕捉するプローブです。 arg0は対象データがヒープ、インデックス、またはdatumのどれかを示します。 arg1はtrueならば一意性を必要としていることを示します。 arg2はカラムのキー数です。 arg3は許容されている作業メモリ(work_mem)のキロバイト数です。 arg4はtrueならばソート結果に対するランダムアクセスが要求されていることを示します。 arg5は、0ならばシリアル、1ならばパラレルワーカー、2ならばパラレルリーダーであることを示します。
sort-done(bool, long) ソート処理の終了を捕捉するプローブです。 arg0はtrueならば外部ソート、falseは内部ソートを示します。 arg1は外部ソートで使用されたディスクブロック数、もしくは内部ソートで使用されたメモリーのキロバイト数を示します。
lwlock-acquire(char *, LWLockMode) LWLockの獲得を捕捉するプローブです。 arg0はLWLockのトランシェを示します。 arg1は要求されたロックモード(排他または共有)を示します。
lwlock-release(char *) LWLockの解放を捕捉するプローブです(ただし、解放された待機状態のものにはまだ通知されていないことに注意してください)。 arg0はLWLockのトランシェを示します。
lwlock-wait-start(char *, LWLockMode) LWLockが即座には獲得できず、ロックが利用可能になるまでサーバプロセスが待機を開始したことを捕捉するプローブです。 arg0はLWLockのトランシェを示します。 arg1は要求されたロックモード(排他または共有)を示します。
lwlock-wait-done(char *, LWLockMode) サーバプロセスがLWLockの待機から解放されたことを捕捉するプローブです(まだ実際にはロックを取得していません)。 arg0はLWLockのトランシェを示します。 arg1は要求されたロックモード(排他または共有)を示します。
lwlock-condacquire(char *, LWLockMode) 呼び出し元が待機しないことを指定した際の、LWLockの獲得成功を捕捉するプローブです。 arg0はLWLockのトランシェを示します。 arg1は要求されたロックモード(排他または共有)を示します。
lwlock-condacquire-fail(char *, LWLockMode) 呼び出し元が待機しないことを指定した際の、LWLockの獲得失敗を捕捉するプローブです。 arg0はLWLockのトランシェを示します。 arg1は要求されたロックモード(排他または共有)を示します。
lock-wait-start(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE) 重量ロック(lmgr lock)を即座に取得できなかったため、サーバプロセスがロックを利用できるまでロック待ち状態になった際の開始を捕捉するプローブです。 arg0からarg3はロックされたオブジェクトの識別用タグ領域です。 arg4はロックされたオブジェクトのタイプを示します。 arg5は要求されたロックの種類を示します。
lock-wait-done(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE) 重量ロック(lmgr lock)要求の待機終了を捕捉するプローブです(つまりロックを取得した)。 引数はlock-wait-startと同じです。
deadlock-found()デッドロック検知器によるデッドロックの発見を捕捉するプローブです。

表28.49 プローブパラメータで使われる型の定義

<title>Defined Types Used in Probe Parameters</title>
定義
LocalTransactionIdunsigned int
LWLockModeint
LOCKMODEint
BlockNumberunsigned int
Oidunsigned int
ForkNumberint
boolunsigned char

28.5.3. プローブの利用 #

<title>Using Probes</title>

The example below shows a DTrace script for analyzing transaction counts in the system, as an alternative to snapshotting <structname>pg_stat_database</structname> before and after a performance test: 以下の例では、性能試験前後でpg_stat_databaseのスナップショットを取る代わりに、システムにおけるトランザクション数を解析するDTraceスクリプトを示します。

#!/usr/sbin/dtrace -qs

postgresql$1:::transaction-start
{
      @start["Start"] = count();
      self->ts  = timestamp;
}

postgresql$1:::transaction-abort
{
      @abort["Abort"] = count();
}

postgresql$1:::transaction-commit
/self->ts/
{
      @commit["Commit"] = count();
      @time["Total time (ns)"] = sum(timestamp - self->ts);
      self->ts=0;
}

When executed, the example D script gives output such as: 実行すると、例のDスクリプトは以下のような出力をします。

# ./txn_count.d `pgrep -n postgres` or ./txn_count.d <PID>
^C

Start                                          71
Commit                                         70
Total time (ns)                        2312105013

注記

SystemTap uses a different notation for trace scripts than DTrace does, even though the underlying trace points are compatible. One point worth noting is that at this writing, SystemTap scripts must reference probe names using double underscores in place of hyphens. This is expected to be fixed in future SystemTap releases. 基本となる追跡ポイントの互換性はありますが、SystemTapはDTraceと異なる追跡スクリプトの表記を用います。 表記に関して特に注意すべき点として、SystemTapでは参照する追跡ポイント名のハイフンの代わりに二重のアンダースコアを用いる必要があります。 これは将来的なSystemTapのリリースで修正されることを期待しています。

You should remember that DTrace scripts need to be carefully written and debugged, otherwise the trace information collected might be meaningless. In most cases where problems are found it is the instrumentation that is at fault, not the underlying system. When discussing information found using dynamic tracing, be sure to enclose the script used to allow that too to be checked and discussed. DTraceスクリプトの作成には注意が必要であり、デバッグが必要であることは忘れないでください。さもないと、収集される追跡情報の意味がなくなるかもしれません。 ほとんどの場合、見つかる問題はシステムではなく使用方法の間違いです。 動的追跡を使用して見つかった情報に関して議論を行う際には、スクリプトの検査や議論もできるようにスクリプトも含めるようにしてください。

28.5.4. 新規プローブの定義 #

<title>Defining New Probes</title>

New probes can be defined within the code wherever the developer desires, though this will require a recompilation. Below are the steps for inserting new probes: 開発者が望めばコード内に新しくプローブを定義することができます。しかし、これには再コンパイルが必要です。 下記は、新規プローブの定義の手順です。

  1. Decide on probe names and data to be made available through the probes プローブの名前とプローブの処理を通じて取得可能とするデータを決めます

  2. Add the probe definitions to <filename>src/backend/utils/probes.d</filename> src/backend/utils/probes.dにプローブの定義を追加します

  3. Include <filename>pg_trace.h</filename> if it is not already present in the module(s) containing the probe points, and insert <literal>TRACE_POSTGRESQL</literal> probe macros at the desired locations in the source code もし、プローブポイントを含むモジュールがpg_trace.hをインクルードしていなければそれをインクルードし、ソースコード中のプローブを行いたい場所にTRACE_POSTGRESQLマクロを挿入します

  4. Recompile and verify that the new probes are available 再コンパイルを行い、新規プローブが利用できるか確認します

<title>Example:</title> 例:  Here is an example of how you would add a probe to trace all new transactions by transaction ID. これはトランザクションIDを用いて新規トランザクションを追跡するプローブ追加の仕方の例です。

  1. Decide that the probe will be named <literal>transaction-start</literal> and requires a parameter of type <type>LocalTransactionId</type> プローブ名をtransaction-startとし、LocalTransactionId型のパラメータを必要とすることを決めます。

  2. Add the probe definition to <filename>src/backend/utils/probes.d</filename>: src/backend/utils/probes.dにプローブの定義を追加します:

    probe transaction__start(LocalTransactionId);
    

    Note the use of the double underline in the probe name. In a DTrace script using the probe, the double underline needs to be replaced with a hyphen, so <literal>transaction-start</literal> is the name to document for users. プローブ名に二重のアンダースコアを使用する場合は注意してください。 DTraceスクリプトでプローブを用いる場合、二重のアンダースコアをハイフンに置き換える必要があります。そのため、transaction-startがユーザ向けの文書に記載される名前となります。

  3. At compile time, <literal>transaction__start</literal> is converted to a macro called <literal>TRACE_POSTGRESQL_TRANSACTION_START</literal> (notice the underscores are single here), which is available by including <filename>pg_trace.h</filename>. Add the macro call to the appropriate location in the source code. In this case, it looks like the following: コンパイル時に、transaction__startTRACE_POSTGRESQL_TRANSACTION_STARTと呼ばれるマクロに変換されます(ここではアンダースコアはひとつになります)。このマクロは、pg_trace.hをインクルードすることにより使用可能となります。 このマクロをソースコード中の適切な箇所へ追加していきます。 この場合、以下の様になります。

    TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
    

  4. After recompiling and running the new binary, check that your newly added probe is available by executing the following DTrace command. You should see similar output: 再コンパイル後に新しいバイナリでサーバを起動し、下記の様なDTraceコマンドの実行により新たに追加したプローブが利用可能かチェックします。 下記の様な出力が確認できるはずです:

    # dtrace -ln transaction-start
       ID    PROVIDER          MODULE           FUNCTION NAME
    18705 postgresql49878     postgres     StartTransactionCommand transaction-start
    18755 postgresql49877     postgres     StartTransactionCommand transaction-start
    18805 postgresql49876     postgres     StartTransactionCommand transaction-start
    18855 postgresql49875     postgres     StartTransactionCommand transaction-start
    18986 postgresql49873     postgres     StartTransactionCommand transaction-start
    

There are a few things to be careful about when adding trace macros to the C code: Cのソースコードに追跡用のマクロを追加する際、いくつかの注意点があります:

  • You should take care that the data types specified for a probe's parameters match the data types of the variables used in the macro. Otherwise, you will get compilation errors. プローブの引数に指定したデータ型がマクロで使用される変数のデータ型と一致するよう注意しなければなりません。 でなければ、コンパイル時にエラーとなるでしょう。

  • On most platforms, if <productname>PostgreSQL</productname> is built with <option>&#45;-enable-dtrace</option>, the arguments to a trace macro will be evaluated whenever control passes through the macro, <emphasis>even if no tracing is being done</emphasis>. This is usually not worth worrying about if you are just reporting the values of a few local variables. But beware of putting expensive function calls into the arguments. If you need to do that, consider protecting the macro with a check to see if the trace is actually enabled: ほとんどのプラットフォームでは、もしPostgreSQL--enable-dtrace付きでビルドされた場合、何の追跡もされなかったとしても、制御がマクロを通過する際はいつでも追跡用マクロの引数が評価されます。 ごく少数のローカルな変数を報告するような場合はそれほど心配はいりません。 ただし、高価な関数呼び出しを引数にする場合は注意してください。 もしそのようにする必要がある場合、追跡が実際に有効かどうかをチェックしてマクロを保護することを考慮してください:

    if (TRACE_POSTGRESQL_TRANSACTION_START_ENABLED())
        TRACE_POSTGRESQL_TRANSACTION_START(some_function(...));
    

    Each trace macro has a corresponding <literal>ENABLED</literal> macro. 各追跡マクロは対応するENABLEDマクロを持っています。