При высокой конкуренции за одну блокировку одна транзакция снова и снова не получает доступ. Как возникает ...

При высокой конкуренции за одну блокировку одна транзакция снова и снова не получает доступ. Как возникает такое голодание?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Голодание транзакции возникает, когда планировщик блокировок постоянно отдаёт ресурс другим ожидающим или новым запросам, поэтому одна транзакция не получает его неограниченно долго. Это не взаимная блокировка: циклического ожидания нет, ресурс в конечном итоге освобождается, но конкретная транзакция систематически проигрывает конкуренцию.

Исторический контекст

Блокировки появились как способ защищать изменяемые данные при параллельном выполнении транзакций. Когда несколько операций претендуют на один ресурс, СУБД должна решить, кого допустить первым, не разрушив изоляцию и не остановив всю систему.

Простая выдача блокировки тому, кто оказался готов в данный момент, может максимизировать пропускную способность, но не гарантирует справедливость. Поэтому в системах управления блокировками применяются очереди, приоритеты, тайм-ауты и другие политики планирования.

Постановка проблемы

Предположим, короткие транзакции постоянно захватывают блокировку между попытками более долгой транзакции получить её. Если планировщик не учитывает время ожидания, новые запросы могут опережать старый запрос снова и снова.

Последствия — рост времени ответа, истечение тайм-аутов, повторные попытки на уровне приложения и ухудшение предсказуемости системы. При этом взаимной блокировки может не быть: другие транзакции успешно завершаются, а проблема затрагивает одну или несколько постоянно проигрывающих транзакций.

Подробное решение

Голодание появляется из-за политики выдачи блокировок. Например, планировщик может предпочитать совместимые операции, более короткие транзакции, транзакции с высоким приоритетом или новые запросы. Если освобождённая блокировка сразу передаётся более «выгодному» кандидату, ожидающая транзакция может постоянно оставаться последней.

Основной способ предотвращения — справедливая очередь ожидания, обычно с приоритетом транзакций, которые ждут дольше. Политика FIFO уменьшает риск голодания, но может вызвать эффект конвоя: одна медленная транзакция задерживает множество быстрых операций.

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

Голодание следует отличать от взаимной блокировки. При взаимной блокировке транзакции образуют цикл ожидания, и СУБД обычно должна выбрать жертву и прервать её. При голодании цикла нет, поэтому специальный детектор взаимных блокировок проблему может не обнаружить.

Ситуация из практики

В очереди заказов одна транзакция долго обновляет записи, удерживая блокировку на строке склада. Множество коротких транзакций регулярно обращаются к той же строке; политика планировщика позволяет новым совместимым или более приоритетным операциям проходить раньше давно ожидающей транзакции.

Вариант с немедленными повторами после тайм-аута прост, но может усилить нагрузку и создать «стадный» эффект. Увеличение тайм-аута снижает число отказов, однако ухудшает время ответа. Безопаснее использовать очередность ожидания на стороне СУБД, короткие транзакции, ограниченные повторы с экспоненциальной задержкой и метрики времени ожидания.

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

Что кандидаты часто упускают

  1. Гарантирует ли FIFO отсутствие голодания?

    Не обязательно. FIFO предотвращает обход в очереди только при условии, что все ожидающие запросы действительно находятся в одной очереди и политика применяется последовательно. Совместимые блокировки, приоритеты, эскалация блокировок и внутренние очереди разных ресурсов могут изменить порядок допуска.

  2. Можно ли считать тайм-аут доказательством голодания?

    Нет. Тайм-аут означает, что ожидание превысило заданный предел, но причиной может быть обычная долгосрочная транзакция, взаимная блокировка, блокировка на другом ресурсе или чрезмерно высокий приоритет конкурирующих операций. Для диагностики нужны сведения о владельце блокировки, цепочке ожидания и длительности транзакций.

  3. Почему повышение приоритета ожидающей транзакции может навредить системе?

    Оно сокращает её ожидание, но способно задержать множество других операций и вызвать эффект конвоя. Если приоритет повышается без ограничений, одна старая транзакция получает почти монопольный доступ к ресурсу. Поэтому приоритет обычно повышают постепенно или ограничивают максимальным временем удержания блокировки.