Что происходит в контрольной точке PostgreSQL?

22

Вот часть моего журнала контрольных точек:

2014-03-26 11:51:29.341 CDT,,,18682,,532854fc.48fa,4985,,2014-03-18 09:15:24 CDT,,0,LOG,00000,"checkpoint complete: wrote 15047 buffers (1.4%); 0 transaction log file(s) added, 0 removed, 30 recycled; write=68.980 s, sync=1.542 s, total=70.548 s; sync files=925, longest=0.216 s, average=0.001 s",,,,,,,,,""
2014-03-26 11:56:05.430 CDT,,,18682,,532854fc.48fa,4987,,2014-03-18 09:15:24 CDT,,0,LOG,00000,"checkpoint complete: wrote 16774 buffers (1.6%); 0 transaction log file(s) added, 0 removed, 31 recycled; write=72.542 s, sync=17.164 s, total=89.733 s; sync files=885, longest=3.812 s, average=0.019 s",,,,,,,,,""
2014-03-26 12:01:21.650 CDT,,,18682,,532854fc.48fa,4989,,2014-03-18 09:15:24 CDT,,0,LOG,00000,"checkpoint complete: wrote 14436 buffers (1.4%); 0 transaction log file(s) added, 0 removed, 33 recycled; write=122.350 s, sync=5.212 s, total=127.676 s; sync files=924, longest=3.740 s, average=0.005 s",,,,,,,,,""
2014-03-26 12:06:25.028 CDT,,,18682,,532854fc.48fa,4991,,2014-03-18 09:15:24 CDT,,0,LOG,00000,"checkpoint complete: wrote 13277 buffers (1.3%); 0 transaction log file(s) added, 0 removed, 29 recycled; write=126.217 s, sync=5.733 s, total=131.991 s; sync files=894, longest=1.859 s, average=0.006 s",,,,,,,,,""
2014-03-26 12:10:41.958 CDT,,,18682,,532854fc.48fa,4993,,2014-03-18 09:15:24 CDT,,0,LOG,00000,"checkpoint complete: wrote 20765 buffers (2.0%); 0 transaction log file(s) added, 0 removed, 28 recycled; write=88.015 s, sync=10.818 s, total=98.872 s; sync files=881, longest=2.690 s, average=0.012 s",,,,,,,,,""

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

Вопрос: Может ли контрольно-пропускной пункт вызвать это? Что происходит на этапе синхронизации контрольной точки?

Конрад Гарус
источник

Ответы:

32

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

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

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

Этот сброс происходит в два этапа:

  • Буферизованные write()грязные shared_buffersтаблицы; а также
  • fsync() затронутых файлов, чтобы убедиться, что изменения действительно попали на диск

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

Это давняя проблема, но она усугубляется, когда мы видим системы с все большим объемом ОЗУ, поэтому они могут буферизовать больше данных и быстрее записывать их. Существует дискуссия между сообществами Linux и PostgreSQL о том, как справиться с этим в данный момент, как обсуждалось в этой статье LWN.net . (LWN.net не сможет продолжать писать такую ​​замечательную работу, если люди не подпишутся. Я подписчик и делюсь этой ссылкой, потому что она полезна и информативна. Пожалуйста, рассмотрите возможность подписки, если вы хотите увидеть больше этого Такие вещи.)

Главное, что вы можете сделать, чтобы уменьшить влияние контрольных точек в данный момент, - это распределить активность контрольных точек, увеличив checkpoint_completion_targetтаким образом, чтобы к моменту прибытия последней контрольной точки было записано больше данных. Однако это имеет свою стоимость - если вы обновите страницу (скажем) десять раз, она может быть записана на диск несколько раз до контрольной точки с высокой целью завершения, даже если она была строго записана только один раз для безопасности при сбое. Более высокая цель завершения обеспечивает более плавные схемы ввода-вывода, но увеличивает общую нагрузку ввода-вывода.

Другая вещь, которую вы можете сделать, чтобы помочь, это сказать вашей операционной системе немедленно начинать запись данных, когда она получает буферизованные записи. Это похоже на настройку ядра checkpoint_completion_targetи имеет аналогичный компромисс. Смотрите документацию Vm Линукс , в частности dirty_background_bytes, dirty_background_ratio, dirty_expire_centisecs.

Крейг Рингер
источник
Запись распространяется в течение длительного времени, и я не думаю, что это вызывает проблемы. А как насчет синхронизации, это случайно операция типа "остановка мира"?
Конрад Гарус
@KonradGarus Синхронизация не должна быть операцией остановки мира, но это часто так или иначе. Прочитайте статью, на которую я ссылался выше, это очень своевременное и полезное краткое изложение проблем, хотя и с довольно технической точки зрения. Краткая версия: «fsync () в Linux имеет тенденцию полностью снижать производительность любого ввода-вывода, параллельного с fsync ()». Вы можете уменьшить это с помощью параметров настройки, перечисленных выше, чтобы уменьшить количество, которое должно быть удалено с помощью fsync.
Крейг Рингер
1

Сброс грязных буферов файловой системы ОС, вызванных превышением dirty_bytesили dirty_ratio является операцией блокировки переднего плана!

В ядре параметров настройки dirty_bytes, dirty_background_bytes, dirty_ratio, dirty_background_ratioи dirty_centisecsконтроль смыв грязных файловой системы ОС буферов на диск. dirty_bytesэто порог в байтах, dirty_ratioэто порог как отношение общего объема памяти. dirty_background_bytesи dirty_background_ratioявляются аналогичными пороговыми значениями, но сброс происходит в фоновом режиме и не блокирует другие операции чтения / записи, пока не завершится. dirty_centisecsсколько секунд может пройти до начала сброса.

Недавно значения по умолчанию для этих настраиваемых параметров были уменьшены в Linux, поскольку объем памяти для современных машин значительно увеличился. Даже соотношения 5 и 10% для dirty_background_ratioи dirty_ratioна машине 256GB может залить систему ввода / вывода.

Настроить dirty_background_bytesили dirty_background_ratioначать сбрасывать грязные буферы в фоновом режиме сложно. К счастью, вы можете настроить эти параметры без необходимости останавливать PostgreSQL или хост, передавая новые значения в соответствующие файлы:

$ sudo echo [int value of bytes] > /proc/sys/vm/dirty_background_bytes

например, чтобы установить количество байтов, для которых выполняется очистка фона. Если вы используете RAID-карту с резервным питанием от батареи, конденсатора или флэш-памяти (вы не хотите хранить свои данные в случае сбоя, не так ли?), Начните с настройки dirty_background_bytesна 1/2 размера буфера кэша записи и dirty_bytes3/4 этого размера. Контролируйте свой профиль ввода / вывода с помощью iostats, и если вы все еще видите проблемы с задержкой, это означает, что загрузка записи в базу данных все еще превышает загрузку кеша буферов файлов. Уменьшайте значения до тех пор, пока не улучшится задержка, или рассмотрите возможность обновления подсистемы ввода-вывода. Платы FusionIO и твердотельные накопители - это две возможности для максимальной пропускной способности ввода-вывода.

Удачи!

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