17

我将 Postgres 用于我的一个应用程序,有时(不是很频繁地)其中一个连接进入<IDLE> in transaction状态并保持获取的锁,导致其他连接等待这些锁,最终导致我的应用程序挂起。

以下是该pg_stat_activity过程的表输出:

select * from pg_stat_activity

24081 | db     |     798 |    16384 | db     |                  | 10.112.61.218 |                 |       59034 | 2013-09-12 23:46:05.132267+00 | 2013-09-12 23:47:31.763084+00 | 2013-09-12 23:47:31.763534+00 | f       | <IDLE> in transaction

这表明PID=798处于<IDLE> in transaction状态。使用上述输出中的client_port( )可以找到 Web 服务器上的客户端进程,如下所示。59034

sudo netstat -apl | grep 59034

tcp        0      0 ip-10-112-61-218.:59034 db-server:postgresql    ESTABLISHED 23843/pgbouncer

我知道我的应用程序代码中有问题(我杀死了一个正在运行的应用程序 cron 并释放了锁)导致连接挂起,但我无法跟踪它。

这不是很频繁,我也找不到任何明确的复制步骤,因为这只发生在生产服务器上。

我想获得有关如何跟踪此类空闲连接的输入,例如获取上次执行的查询或某种回溯以识别导致此问题的代码部分。

4

1 回答 1

12

如果您升级到 9.2 或更高版本,该pg_stat_activity视图将向您显示最近执行的idle in transaction连接查询。

select * from pg_stat_activity  \x\g\x

...
waiting          | f
state            | idle in transaction
query            | select count(*) from pg_class ;

您还可以(甚至在 9.1 中)查看进程pg_locks持有哪些锁idle in transaction。如果它只对非常常用的对象有锁,这可能不会缩小范围,但如果它是一个特殊的锁,可以告诉你在代码中的确切位置。

如果你被 9.1 卡住了,你也许可以使用调试器来获取除查询的前 22 个字符之外的所有字符(前 22 个被<IDLE> in transaction\0消息覆盖)。例如:

(gdb) printf "%s\n", ((MyBEEntry->st_activity)+22)
于 2013-09-13T18:12:35.023 回答