28.5. 动态追踪
PostgreSQL提供了功能来支持数据库服务器的动态追踪。这样就允许在代码中的特 定点上调用外部工具来追踪执行过程。
一些探针或追踪点已经被插入在源代码中。这些探针的目的是被数据库开发者和管理员使用。默认情况下,探针不被编译到PostgreSQL中;用户需要显式地告诉配置脚本使得探针可用。
目前,在写本文当时DTrace1已被支持,它在 Solaris、macOS、FreeBSD、NetBSD 和 Oracle Linux 上可用。Linux 的SystemTap2项目提供了一种可用的 DTrace 等价物。支持其他动态追踪工具在理论上可以通过改变src/include/utils/probes.h中的宏定义实现。
28.5.1. 动态追踪的编译
默认情况下,探针是不可用的,因此你将需要显式地告诉配置脚本让探针在PostgreSQL中可用。要包括 DTrace 支持,在配置时指定–enable-dtrace。更多信息请见Section 16.4
28.5.2. 内建探针
如Table 28.23所示,源代码中提供了一些标准探针。Table 28.24显式了在探针中使用的类型。当然,可以增加更多探针来增强PostgreSQL的可观测性。
Table 28.23. 内建 DTrace 探针
Table 28.24. 定义用在探针参数中的类型
28.5.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 脚本给出这样的输出:
代码语言:javascript复制# ./txn_count.d `pgrep -n postgres` or ./txn_count.d <PID>
^C
Start 71
Commit 70
Total time (ns) 2312105013
SystemTap 为追踪脚本使用一个不同于 DTrace 的标记,但是底层的探针是兼容的。值得注意的是,在这样写的时候,SystemTap 脚本必须使用双下划线代替连字符来引用探针名。在未来的 SystemTap 发行中这很可能会被修复。
你应该记住,DTrace 脚本需要细心地编写和调试,否则被收集的追踪信息可能会毫无意义。在大部分发现问题的情况中,它就是发生问题的部件,而不是底层系统。当讨论使用动态追踪发现的信息时,一定要封闭使用的脚本来允许这些以便被检查和讨论。
28.5.4. 定义新探针
开发者可以在代码中任意位置定义新的探针,当然这要重新编译之后才能生效。下面是插入新探针的步骤:
- 决定探针名称以及探针可用的数据
- 把该探针定义加入到
src/backend/utils/probes.d
- 如果pg_trace.h还不存在于包含该探针点的模块中,包括它,并且在源代码中期望的位置插入
TRACE_POSTGRESQL
探针宏 - 重新编译并验证新探针是可用的 例子:. 这里是一个如何增加一个探针来用事务 ID 追踪所有新事务的例子。
- 决定探针将被命名为
transaction-start
并且需要一个LocalTransactionId类型的参数 - 将该探针定义加入到
src/backend/utils/probes.d:probe transaction__start(LocalTransactionId);
注意探针名字中双下划线的使用。在一个使用探针的 DTrace 脚本中,双下划线需要被替换为一个连字符,因此 ,对用户而言transaction-start是文档名。 - 在编译时,
transaction__start
被转换成一个宏调用TRACE_POSTGRESQL_TRANSACTION_START
(注意这里是单下划线),可以通过包括头文件pg_trace.h获得。将宏调用加入到源代码中的合适位置。在这种情况下,看起来类似:TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
- 在重新编译和运行新的二进制文件之后,通过运行下面的 DTrace 命令来检查新增的探针是否可用。你应该看到类似下面的输出:
# dtrace -ln transaction-start
ID PROVIDER MODULE FUNCTION NAME
18705 postgresql49878 postgres StartTransactionCommand transactionstart
18755 postgresql49877 postgres StartTransactionCommand transactionstart
18805 postgresql49876 postgres StartTransactionCommand transactionstart
18855 postgresql49875 postgres StartTransactionCommand transactionstart
18986 postgresql49873 postgres StartTransactionCommand transactionstart
向C代码中添加追踪宏时,有一些事情需要注意:
- 要小心的是,为探针参数指定的数据类型要匹配宏中使用的变量的数据类型,否则会发生编译错误。
- 在大多数平台上,如果用–enable-dtrace编译了PostgreSQL,无论何时当控制经过一个追踪宏时,都会评估该宏的参数,即使没有进行追踪也会这样做。通常不需要担心你是否只在报告一些局部变量的值。但要注意将开销大的函数调用放置在这些参数中。如果你需要这样做,考虑通过检查追踪是否真的被启用来保护该宏:
if (TRACE_POSTGRESQL_TRANSACTION_START_ENABLED())
TRACE_POSTGRESQL_TRANSACTION_START(some_function(...));
每个追踪宏有一个对应的ENABLED宏。