Отладка livelock в Джанго / Postgresql - PullRequest
0 голосов
/ 06 января 2010

Я запускаю умеренно популярное веб-приложение на Django с Apache2, mod_python и PostgreSQL 8.3 с базой данных базы данных postgresql_psycopg2.Я иногда испытываю живую блокировку, которую можно определить, когда процесс apache2 постоянно потребляет 99% ЦП в течение нескольких минут или более.

Я выполнил команду -p pid для процесса apache2 и обнаружилчто он постоянно повторял эти системные вызовы:

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

Этот точный фрагмент постоянно повторяется в трассировке и работал более 10 минут, прежде чем я окончательно убил процесс apache2.(Примечание: я отредактировал это, чтобы заменить мой предыдущий фрагмент strace новым, который полностью отображает содержимое строки, а не обрезается.)

Моя интерпретация вышеизложенного заключается в том, что django пытается выполнить проверку существованиямоя таблица account_profile, но в какой-то более ранний момент (до того, как я начал трассировку) что-то пошло не так (ошибка синтаксического анализа SQL - нарушение ссылочной целостности или ограничение уникальности - кто знает?), и теперь Postgresql возвращает ошибку «текущая транзакция прервана».По какой-то причине вместо того, чтобы вызывать исключение и сдаваться, он просто продолжает повторять попытки.

Одна из возможностей заключается в том, что это вызывается при вызове Profile.objects.get_or_create.Это класс модели, который отображается в таблицу account_profile.Возможно, в get_or_create есть что-то, предназначенное для перехвата слишком широкого набора исключений и повторных попыток?Из журналов веб-сервера видно, что эта живая блокировка могла произойти в результате двойного щелчка по кнопке POST в форме регистрации моего сайта.

Это условие встречалось пару раз за последние несколькодней на живом сайте, и это приводит к значительному замедлению, пока я не вмешаюсь, так что почти все, кроме бесконечного тупика, будет улучшением!:)

Ответы [ 2 ]

1 голос
/ 08 января 2010

Это оказалось полностью моей ошибкой. Я нашел место, где казалось, что выражение select (1) as 'a' происходит (в django/models/base.py), и взломал его, чтобы зарегистрировать трассировку, которая четко указывала на мой код.

У меня был какой-то код, который составляет уникальный электронный ключ для каждого профиля. Эти ключи генерируются случайным образом, поэтому, поскольку существует некоторая вероятность наложения, я запускаю их в попытке / за исключением цикла while. Я предполагал, что ограничение уникальности базы данных приведет к сбою сохранения, если ключ не будет уникальным, и я смогу повторить попытку.

К сожалению, в Postgresql вы не можете просто повторить попытку после ошибки целостности. Вы должны выполнить команду COMMIT или ROLLBACK (даже если вы, очевидно, находитесь в режиме автоматической фиксации), прежде чем сможете повторить попытку. Поэтому у меня был бесконечный цикл неудачных попыток сохранения, когда я игнорировал сообщение об ошибке.

Теперь я ищу более конкретное исключение (django.db.IntegrityError) и запускаю ограниченное количество попыток, чтобы цикл не был бесконечным.

Спасибо всем за просмотр / ответ.

0 голосов
/ 06 января 2010

Ваш анализ звучит довольно хорошо. Понятно, что дело не в том, что транзакция прервана. Я предлагаю вам сообщить об этом как об ошибке в проекте django ...

...