6.11.26

VLF: когда журнал транзакций превращается в коммуналку

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

Чем больше VLF, тем заметнее просадка производительности. Страдают, причём дружно, почти все участники процесса:

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

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

Хорошая новость с оговоркой

В SQL Server 2022 (16.x) и более поздних версиях появилось послабление: при автоувеличении журнала новый кусок можно не перезаписывать нулями, если его размер не превышает 64 МБ. Это та самая мгновенная инициализация файлов, которая для файлов данных работает давно, а до журнала добралась только сейчас.

Но есть нюанс, и он принципиальный: если вы настроили автоувеличение журнала на 65 МБ или больше, обнуление никуда не денется — SQL Server честно затрёт новый кусок нулями, и операция снова станет медленной. Так что «волшебная палочка» работает только в пределах 64 МБ. Для журнала эта функция не требует прав SE_MANAGE_VOLUME_NAME, которые нужны для файлов данных, но включённая мгновенная инициализация на экземпляре всё равно должна быть в наличии.

Контрольная точка — не уборщик, а диспетчер

Контрольная точка (CHECKPOINT) сама по себе в журнале ничего не удаляет и не усекает. Её задача — сбросить на диск грязные страницы данных и служебные метаданные базы, которые накопились в памяти. Пока эти страницы не зафиксированы на диске, соответствующие записи журнала остаются нужными для восстановления — а значит, и VLF, в которых они лежат, может оказаться невозможно пометить как неактивные.

Вот тут и вступает в игру MinLSN — минимальный номер последовательности в журнале, необходимый для успешного отката или восстановления. Контрольная точка записывает этот MinLSN в служебную страницу базы данных (boot page). Всё, что в журнале находится до MinLSN, после успешной контрольной точки становится ненужным для восстановления — и соответствующие VLF можно пометить как неактивные (inactive), то есть пригодные для повторного использования.

Именно поэтому shrink журнала без предварительной контрольной точки — занятие не всегда эффективное: журнал может быть полон «мёртвым грузом» с точки зрения физического места, но с точки зрения логики восстановления эти VLF всё ещё активны.

Дальше всё зависит от модели восстановления:

  • в простой модели сразу же после сброса грязных страниц контрольной точкой те VLF, что оказались до MinLSN, становятся неактивные. Это и есть то, что на бытовом уровне называют «очисткой журнала»;
  • в полной модели контрольная точка только фиксирует MinLSN и сбрасывает страницы, но это не приводит к повторному использованию VLF. Разрешение появляется лишь после резервной копии журнала — именно она сдвигает границу и позволяет помечать VLF как неактивные.

Так что в полной модели цикл получается двухступенчатым: контрольная точка подготавливает почву (сбрасывает грязные страницы), а резервная копия журнала даёт «добро» на освобождение VLF. Без резервной копии журнала в полной модели VLF так и останутся активными, сколько бы контрольных точек вы ни выполняли и DBCC SHRINKFILE не сделает той работы, которую от него ожидают. Но даже если всё сделано правильно, длинные транзакции могут помешать высвобождению LSN в конце файла и размер может сразу не измениться. Однако, повторяя этот цикл, можно постепенно уменьшить физический размер файла, а также количество VLF в нём.

Как снизить количество VLF и не довести журнал до фрагментации

  • не мельчить с автоувеличением: рост по 10% или маленькими кусками гарантированно плодит VLF;
  • задать автоувеличению фиксированный размер, например 64 МБ, чтобы попасть в новое послабление, или 1 ГБ и больше — если вы готовы платить за обнуление, но получить меньше VLF за один шаг;
  • увеличивать журнал вручную до разумного размера, а не ждать очередного мелкого роста;
  • следить за количеством VLF через DBCC LOGINFO или sys.dm_db_log_info;
  • при сильной фрагментации — аккуратно усечь файл журнала: выполнить контрольную точку, чтобы сбросить грязные страницы и зафиксировать MinLSN, а в полной модели — обязательно сделать резервную копию журнала, затем сжать файл командой DBCC SHRINKFILE и повторять этот цикл, пока количество VLF не снизится до приемлемого. Обычно хватает двух–трёх итераций, если нет длинных незавершённых транзакций, репликации или других факторов, удерживающих журнал;
  • не увлекаться уменьшением журнала без нужды — потом рост опять наделает мелких VLF.

В SQL Server 2014 и 2022 алгоритмы создания VLF улучшили, но расслабляться не стоит: доверяй, но проверяй. Мониторьте количество VLF — и журнал не превратится в бесконечную коммуналку.

Полезные ссылки:

Комментариев нет:

Отправить комментарий