посмертная отладка взаимоблокировок в PostgreSQL

Я хочу собрать посмертную отладочную информацию как о «победившей» транзакции, так и о «проигравшей» транзакции в тупиковой ситуации PostgreSQL.

  • Я нашел эту вики-страницу, на которой есть несколько хороших просмотров в реальном времени, которые могут дать подсказки о том, что такое в настоящее время происходит неправильно, но, если я правильно понимаю, к тому времени, когда проигрышная транзакция уже откатывается, большая часть самой полезной информации уже будет удалена из этих живых представлений.
  • Я видел такие варианты, как deadlock_timeout и log_lock_waits которые регистрируют информацию о проигрышной транзакции, но не о выигрышной транзакции. Кажется, нет никакого способа настроить вывод журнала, чтобы включить более подробную информацию, чем эта (в частности, ни одно из этих целых чисел ничего не значит, когда я отлаживаю на основе журналов постфактум): LOG: process 11367 still waiting for ShareLock on transaction 717 after 1000.108 ms DETAIL: Process holding the lock: 11366. Wait queue: 11367. CONTEXT: while updating tuple (0,2) in relation "foo" STATEMENT: UPDATE foo SET value = 3;

Есть ли лучший источник данных, который я могу использовать для сбора этой информации?


person Dan    schedule 09.04.2015    source источник
comment
Проще всего было бы просто регистрировать все о каждой транзакции и выкапывать историю конкурирующего процесса постфактум. Это вариант?   -  person Nick Barnes    schedule 09.04.2015
comment
Теперь, когда я думаю об этом, к тому времени, когда вы нажмете deadlock_timeout, все вовлеченные процессы должны были вызвать log_lock_waits. Какой информации вам не хватает?   -  person Nick Barnes    schedule 09.04.2015


Ответы (1)


Во-первых, трассировка, вставленная в вопрос, не является трассировкой взаимоблокировки, а скорее предупреждением о блокировках ресурсов, которые недоступны в течение достаточно долгого времени (дольше, чем deadlock_timeout). Это не ошибка и не отменяет транзакцию, тогда как взаимоблокировка является фатальной для транзакции.

Я хочу собрать посмертную отладочную информацию как о «победившей» транзакции, так и о «проигравшей» транзакции в тупиковой ситуации PostgreSQL.

Они находятся в журнале сервера вместе с запросом, который завершается.

В качестве примера, вот трассировка тупика с log_line_prefix = '%t [%p] ' для случая, упомянутого в этом вопросе: тупик postgres без блокировка

2015-04-09 15:16:42 CEST [21689] ERROR:  deadlock detected
2015-04-09 15:16:42 CEST [21689] DETAIL:  Process 21689 waits for ShareLock on transaction 1866436; blocked by process 21028.
    Process 21028 waits for ShareLock on transaction 1866435; blocked by process 21689.
    Process 21689: insert into b values(1);
    Process 21028: insert into a values(1);
2015-04-09 15:16:42 CEST [21689] HINT:  See server log for query details.
2015-04-09 15:16:42 CEST [21689] STATEMENT:  insert into b values(1);

«Более слабый» — это PID 21689 как источник ошибки. «Победитель» — PID 21028 просто потому, что он другой.

Если посмотреть на это с точки зрения клиента, он получит следующее сообщение:

ERROR:  deadlock detected
DETAIL:  Process 21689 waits for ShareLock on transaction 1866436; blocked by process 21028.
Process 21028 waits for ShareLock on transaction 1866435; blocked by process 21689.
HINT:  See server log for query details.

Там нет упоминания о запросе, но это тот, который только что отправил клиент. Нет упоминания о лузере, но это тот, кто получает эту ошибку, другой не должен ничего замечать.

person Daniel Vérité    schedule 09.04.2015
comment
Спасибо, это, безусловно, отвечает на мой вопрос о взаимоблокировках. Существует ли аналогичная стратегия для связанных классов проблем (например, проблем с сериализацией, когда у вас есть уровень изоляции = ПОВТОРЯЕМОЕ ЧТЕНИЕ или СЕРИАЛИЗУЕМЫЙ)? - person Dan; 09.04.2015
comment
Ничего похожего, но вам будет интересно прочитать wiki.postgresql.org/wiki/SSI. - person Daniel Vérité; 09.04.2015