PostgreSQL 8.2.3 中文文档
后退快退章25. 监控数据库的活动快进前进

25.4. 动态跟踪

PostgreSQL 允许对数据库服务器进行动态跟踪。这样就允许在代码内特定的点上调用外部工具来跟踪执行过程。目前此功能主要目的是为了提供给数据库开发者使用,它要求使用者对代码非常熟悉。

许多跟踪点(也被称为"探头")已经插入在源代码中了,不过缺省为禁用状态,用户必须在编译前运行 configure 脚本时明确启用它们。

目前仅支持 Solaris Express 和 Solaris 10+ 系统上的 DTrace 工具。预计将来 DTrace 将会移植到 FreeBSD 和 Mac OS X 上。理论上也可以通过更改 src/include/pg_trace.h 中的 PG_TRACE 宏来支持其它跟踪工具。

25.4.1. 编译动态跟踪支持

跟踪点是默认禁止的,你必须在运行 configure 脚本时明确使用 --enable-dtrace 选项来启用 DTrace 支持。参见节14.5获取更多信息。

25.4.2. 内置跟踪点

表25-3显示的是在源代码中提供的标准跟踪点,此外,也可以根据特定的具体问题添加其它跟踪点。

表25-3. 内置跟踪点

名字参数概述
transaction__start(int transactionId)开始新事务
transaction__commit(int transactionId)事务成功完成
transaction__abort(int transactionId)事务失败
lwlock__acquire(int lockid, int mode)成功获取 LWLock
lwlock__release(int lockid, int mode)成功释放 LWLock
lwlock__startwait(int lockid, int mode)未立即获得 LWLock 并且后端开始等待该锁
lwlock__endwait(int lockid, int mode)后端已释放等待的 LWLock
lwlock__condacquire(int lockid, int mode)成功获得调用者指定不必等待的 LWLock
lwlock__condacquire__fail(int lockid, int mode)未能获得调用者指定不必等待的 LWLock
lock__startwait(int locktag_field2, int lockmode)由于不能立即获取超重锁(lmgr lock)而进入等待
lock__endwait(int locktag_field2, int lockmode)等待获取超重锁(lmgr lock)完毕(也就是成功获取)

25.4.3. 使用跟踪点

下面的例子示范了一个分析事务次数的 DTrace 脚本,可以用来代替在性能测试之前和之后的 pg_stat_database 快照。

#!/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;
}

请注意在使用 D 脚本时,跟踪点名字中的双下划线是如何被连字符取代的。执行完毕后,示范 D 脚本的输出如下:

# ./txn_count.d `pgrep -n postgres`
^C

Start                                          71
Commit                                         70
Total time (ns)                        2312105013

必须在实际使用跟踪程序前进行仔细的编写和充分的调试,否则收集到的跟踪信息可能毫无意义。大多数问题是由于外部跟踪程序错误导致的而不是底层系统。在讨论使用动态跟踪发现的信息时,应确保在其中包含你使用的跟踪脚本。

25.4.4. 定义跟踪点

开发者可以在代码中任意位置定义新的跟踪点,当然这要重新编译之后才能生效。

可以使用一个跟踪宏来插入跟踪点。可以根据将在该跟踪点上检查多少变量来选择宏。使用跟踪点的名字就可以仅在一行代码上跟踪某个事件的发生,例如:

PG_TRACE (my__new__trace__point);

通过使用与跟踪点名字后面的参数个数一样多的 PG_TRACEn 宏,使用动态跟踪工具检查一个或多个变量,就可以提供更复杂的跟踪点:

PG_TRACE3 (my__complex__event, varX, varY, varZ);

transaction__start 跟踪点的定义如下:

static void
StartTransaction(void)
{
    ...

    /*
     * 生成一个新的事务 id
     */
    s->transactionId = GetNewTransactionId(false);

    XactLockTableInsert(s->transactionId);

    PG_TRACE1(transaction__start, s->transactionId);

    ...
}    

请注意动态跟踪工具是如何获得事务 ID 的。

动态跟踪工具可能需要定义更多的跟踪点。例如,DTrace 要求在 src/backend/utils/probes.d 文件中添加新的跟踪点,如下所示:

provider postgresql {
      ...
      probe transaction__start(int);
      ...
 };

必须注意要将"探头"参数的数据类型与 PG_TRACE 宏使用的数据类型相匹配。编译时并不对此进行检查。你可以通过重新编译来检查新增的跟踪点是否可用,然后以 root 运行新的二进制文件,执行类似下述 DTrace 命令:

dtrace -l -n transaction-start

后退首页前进
查看锁上一级监控磁盘使用情况