我在 Django 上使用 Apache2、mod_python 和 PostgreSQL 8.3 以及 postgresql_psycopg2 数据库后端运行一个中等流行的 Web 应用程序。我偶尔会遇到活锁,当 apache2 进程在几分钟或更长时间内持续消耗 99% 的 CPU 时可识别。
我在 apache2 进程上做了一个 strace -p pid,发现它不断重复这些系统调用:
sendto(25, "Q\0\0\0SSELECT (1) AS \"a\" FROM \"account_profile\" WHERE \"account_profile\".\"id\" = 66201 \0", 84, 0, NULL, 0) = 84
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
poll([{fd=25, events=POLLIN|POLLERR, revents=POLLIN}], 1, -1) = 1
recvfrom(25, "E\0\0\0\210SERROR\0C25P02\0Mcurrent transaction is aborted, commands ignored until end of transaction block\0Fpostgres.c\0L906\0Rexec_simple_query\0\0Z\0\0\0\5E", 16384, 0, NULL, NULL) = 143
这个确切的片段在跟踪中不断重复,并且在我最终杀死 apache2 进程之前运行了 10 多分钟。(注意:我对此进行了编辑,以用一个显示完整字符串内容而不是截断的新片段替换我以前的 strace 片段。)
我对上述内容的解释是,django 正在尝试对我的表 account_profile 进行存在检查,但在更早的时候(在我开始跟踪之前)出现了问题(SQL 解析错误?引用完整性或唯一性约束违规?谁知道? ),现在 Postgresql 返回错误“当前事务已中止”。出于某种原因,它没有引发异常并放弃,而是不断重试。
一种可能性是这是在调用 Profile.objects.get_or_create 时触发的。这是映射到 account_profile 表的模型类。也许 get_or_create 中有一些东西旨在捕获过于广泛的异常并重试?从 Web 服务器日志来看,这种活锁可能是由于双击我网站注册表单中的 POST 按钮而发生的。
在过去的几天里,这种情况在现场已经发生了几次,在我干预之前导致速度显着放缓,所以除了无限死锁之外,几乎任何事情都会有所改善!:)