0

我在 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 按钮而发生的。

在过去的几天里,这种情况在现场已经发生了几次,在我干预之前导致速度显着放缓,所以除了无限死锁之外,几乎任何事情都会有所改善!:)

4

2 回答 2

1

结果证明这完全是我的错。我找到了select (1) as 'a'语句似乎起源的位置(in django/models/base.py)并破解了它以记录回溯,它清楚地指向了我的代码。

我有一些代码构成了每个配置文件的唯一电子邮件“密钥”。这些键是随机生成的,所以因为有一些重叠的可能性,所以我在一个 while 循环中的 try/except 中运行它。我的假设是,如果密钥不是唯一的,数据库的唯一约束会导致保存失败,我可以再试一次。

不幸的是,在 Postgresql 中,您不能简单地在完整性错误后重试。在重试之前,您必须发出 COMMIT 或 ROLLBACK 命令(即使您显然处于自动提交模式)。所以我有一个无限循环的失败保存尝试,我忽略了错误消息。

现在我寻找一个更具体的异常 ( django.db.IntegrityError) 并运行有限次数的尝试,以使循环不是无限的。

感谢大家观看/回答。

于 2010-01-08T15:07:55.017 回答
-1

你的分析听起来不错。显然,它没有发现交易被中止的事实。我建议您将此作为 django 项目的错误报告...

于 2010-01-06T17:54:32.157 回答