Логирование TLI

Логирование инвалидации блокировок транзакций (TLI) позволяет установить, у какого запроса были сломаны блокировки (жертва) и какой запрос их сломал (нарушитель).

Включение логирования

Для получения детальных логов о конфликтах блокировок установите уровень INFO (числовое значение 6) для компонента TLI.

Добавьте в конфигурацию кластера:

log_config:
  entry:
    - component: "TLI"
      level: 6  # INFO

Параметр log_config поддерживает динамическое обновление без перезапуска узлов.

После включения сервер записывает логи при каждой сломанной блокировке, а VictimQuerySpanId начинает появляться в сообщении об ошибке SDK.

Примечание

Базовый размер лога для одного TLI-события составляет 10–20 КБ. Фактический объем зависит от размера текста логируемых запросов (виновника и жертвы) и транзакций, частью которых они являются, поскольку все эти данные записываются в лог.
Если конфликты редки, нагрузка на логирование незначительна. При высокой частоте TLI суммарный объём логов может быть существенным.

Чтобы исключить таблицы с ожидаемыми конфликтами из TLI-диагностики, используйте параметр tli_config.ignored_table_regexes.

Структура логов

Когда происходит TLI, сервер записывает четыре записи — по одной от каждого компонента для каждой из сторон конфликта.

Пример сценария:

Устанавливается две сессии к СУБД: жертва и нарушитель.

Время QuerySpanId Роль Запрос
T1 1111111111111111 Жертва SELECT * FROM Orders WHERE OrderId = 42 (устанавливает блокировку)
T2 2222222222222222 Нарушитель UPDATE Orders SET Status = 'done' WHERE OrderId = 42 (ломает блокировку)
T3 3333333333333333 Жертва UPDATE Orders SET Amount = 100 WHERE OrderId = 42 (коммит — падает)

Лог нарушителя (DataShard):

Component: DataShard, TabletId: <tablet-id>,
BreakerQuerySpanId: 2222222222222222, VictimQuerySpanIds: [1111111111111111],
Message: Write transaction broke other locks

Лог нарушителя (SessionActor):

Component: SessionActor, Message: Query had broken other locks,
BreakerQuerySpanId: 2222222222222222,
BreakerQueryText: UPDATE Orders SET Status = 'done' WHERE OrderId = 42,
BreakerQueryTexts: [QuerySpanId=2222222222222222 QueryText=UPDATE Orders SET Status = 'done' WHERE OrderId = 42]

Лог жертвы (DataShard):

Component: DataShard, TabletId: <tablet-id>,
VictimQuerySpanId: 1111111111111111, CurrentQuerySpanId: 3333333333333333,
Message: Write transaction was a victim of broken locks

Лог жертвы (SessionActor):

Component: SessionActor, Message: Query was a victim of broken locks,
VictimQuerySpanId: 1111111111111111, CurrentQuerySpanId: 3333333333333333,
VictimQueryText: SELECT * FROM Orders WHERE OrderId = 42,
VictimQueryTexts: [QuerySpanId=1111111111111111 QueryText=SELECT * FROM Orders WHERE OrderId = 42 |
                   QuerySpanId=3333333333333333 QueryText=UPDATE Orders SET Amount = 100 WHERE OrderId = 42]

Поля логов

Поле Описание Где встречается
VictimQuerySpanId Идентификатор запроса, чьи блокировки были сломаны Логи жертвы
BreakerQuerySpanId Идентификатор запроса, который сломал блокировки Логи нарушителя
CurrentQuerySpanId Идентификатор запроса в момент ошибки (может отличаться от жертвы) Логи жертвы
VictimQuerySpanIds Массив идентификаторов всех запросов-жертв Логи нарушителя DataShard
VictimQueryText SQL запроса-жертвы, который установил блокировки Логи жертвы SessionActor
BreakerQueryText SQL запроса-нарушителя Логи нарушителя SessionActor
VictimQueryTexts Все запросы транзакции-жертвы Логи жертвы SessionActor
BreakerQueryTexts Все запросы транзакции-нарушителя Логи нарушителя SessionActor

Анализ логов

По VictimQuerySpanId из сообщения об ошибке SDK можно найти все связанные события:

  1. Поиск запроса-жертвы: поле VictimQuerySpanId в логах жертвы показывает, какой SELECT установил сломанные блокировки, и его текст в поле VictimQueryText.

  2. Поиска запроса-нарушитель: в логе нарушителя DataShard поле VictimQuerySpanIds содержит то же значение. Из этого лога извлекается BreakerQuerySpanId и находится лог SessionActor нарушителя — он содержит BreakerQueryText с полным текстом запроса.

  3. Получение полного контекста транзакций: VictimQueryTexts и BreakerQueryTexts содержат все запросы соответствующих транзакций в порядке выполнения.

Утилита find_tli_chain

Для автоматического анализа логов TLI в репозитории YDB есть утилита find_tli_chain.py.

Данная утилита принимает на вход параметры:

  • VictimQuerySpanId - идентификатор сломанного запроса из сообщения об ошибке SDK;
  • LogFile - имя лог-файла для анализа логов.

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

python3 find_tli_chain.py <VictimQuerySpanId> <LogFile>

Пример:

python3 find_tli_chain.py 1111111111111111 ydb.log
================================================
  TLI Chain
================================================

VictimQuerySpanId: 1111111111111111

VictimQueryText: SELECT * FROM Orders WHERE OrderId = 42

BreakerQuerySpanId: 2222222222222222

BreakerQueryText: UPDATE Orders SET Status = 'done' WHERE OrderId = 42

================================================
  VictimTx
================================================

SELECT * FROM Orders WHERE OrderId = 42

UPDATE Orders SET Amount = 100 WHERE OrderId = 42

================================================
  BreakerTx
================================================

UPDATE Orders SET Status = 'done' WHERE OrderId = 42

Утилита выводит:

  • TLI ChainVictimQuerySpanId, VictimQueryText, BreakerQuerySpanId, BreakerQueryText;
  • VictimTx — все запросы транзакции-жертвы в порядке выполнения;
  • BreakerTx — все запросы транзакции-нарушителя.

Дополнительные параметры:

Параметр Описание
--window-sec N Временное окно поиска вокруг события (по умолчанию 10 с)
--no-color Отключить цветной вывод

Примечание

Утилита корректно обрабатывает несортированные и смешанные лог-файлы: фильтрация основана на значениях временных меток, а не на позициях строк.