Управление легкими блокировками
Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.
Описание
В высоконагруженных и многопоточных системах может возникать значительная конкуренция за общие структуры данных, используемые для синхронизации доступа к объектам базы данных. Это приводит к росту времени ожидания легких блокировок (LWLock) и тяжелых блокировок (heavy locks), а в отдельных случаях — к деградации производительности и риску отказа в обслуживании.
Введение конфигурационных параметров в рамках данной функциональности обеспечивает более эффективное использование механизмов блокировок в многопроцессорных системах и под высокой нагрузкой.
Настройка этих параметров позволяет:
- снизить конкуренцию за общие ресурсы;
- предотвратить чрезмерные задержки exclusive-блокировок;
- повысить общую масштабируемость и предсказуемость производительности кластера СУБД Pangolin.
Параметры позволяют управлять легкими блокировками (LWLock) на высоконагруженных системах для повышения производительности в следующих сценариях нагрузки:
- редкие пишущие запросы и чрезмерно частые читающие запросы;
- запросы с большим числом таблиц: партиционированные таблицы, таблицы с большим числом индексов, объединение таблиц с помощью оператора
JOIN; - запросы, сопровождающиеся частым обращением к буферному кешу для чтения страниц из файловой системы, записи страниц в файловую систему, вытеснения страниц из буферного кеша.
Ограничения
-
При небольших значениях параметра
lwlock_shared_limitexclusive-блокировки будут устанавливаться гораздо быстрее, но могут возникнуть значительные издержки. При увеличении значения параметра издержки снижаются, но при этом снижается скорость. -
При больших значениях параметра
fastpath_num_locksиздержки на обработку слотов fast-path блокировок могут превышать стоимость обращения к разделяемой хеш-таблице менеджера блокировок (LWLock:LockManager), поскольку поиск fast-path блокировок выполняется за0 (N). -
Увеличение значений параметров
log2_num_lock_partitionsиfastpath_num_locksвлияет на размер структурыPGPROC, соответствующей каждому бэкенду:log2_num_lock_partitions = 4,fastpath_num_locks = 16- 4000 байт (63 кеш линии)log2_num_lock_partitions = 8,fastpath_num_locks = 16- 9760 байт (153 кеш линии)log2_num_lock_partitions = 4,fastpath_num_locks = 200- 4808 байт (76 кеш линий)log2_num_lock_partitions = 4,fastpath_num_locks = 10000- 47744 байт (746 кеш линий)log2_num_lock_partitions = 8,fastpath_num_locks = 10000- 53504 байт (836 кеш линий)
При большом размере этой структуры увеличивается вероятность вытеснения
PGPROCиз кешей L2/L3 процессора, что приведет к более частому доступу в RAM. Это может значительно снизить производительность на более распространенных сценариях нагрузки. Лучше не следовать принципу – слепо выкручивать параметры до максимальных значений, потому что чем больше, тем лучше, а ориентироваться на результаты проведенных нагрузочных тестов в соответствии с интересующими сценариями.
Настройка
Параметры управления легкими блокировками
Параметр | Значение по умолчанию | Описание |
|---|---|---|
|
| Определяет количество последовательно запрашиваемых shared-блокировок, по достижении которого включается «честный» режим |
|
| Позволяет настроить число частей, на которые будет поделена общая таблица блокировок, и, соответственно, количество легких блокировок в транше |
|
| Определяет число слотов в памяти каждого из обслуживающих процессов (бэкендов) для хранения информации о fast-path блокировках на объекты БД |
|
| Устанавливает число бакетов хеш-таблицы и, соответственно, количества легких блокировок в транше |
Далее эти конфигурационные параметры описаны более подробно с указанием примеров.
GUC-параметр lwlock_shared_limit
В СУБД Pangolin легкие блокировки (LWLock) используются для защиты общих структур данных, таких как хеш-таблицы, и поддерживают два режима — разделяемый (только для чтения, shared) и исключительный (exclusive).
При интенсивной read-only нагрузке возможна ситуация, когда многочисленные читающие процессы постоянно обходят очередь, из-за чего пишущие процессы долго не могут получить exclusive-блокировку (например, LWLock:BufferMapping), что может привести к отказу в обслуживании.
Для решения этой проблемы введен параметр lwlock_shared_limit, который ограничивает число последовательных shared-захватов, после чего включается «честный» режим очереди: запросы shared-блокировок начинают вставать в очередь, что предотвращает голодание exclusive-блокировок. Значение по умолчанию — 0 (режим отключен), оптимальное — около 16.
Диапазон значений: от 0 до 16383.
Значение по умолчанию: 0 («честный» режим отключен).
Рекомендуемое значение на высокой нагрузке: очень зависит от профиля нагрузки (в большинстве случаев можно использовать значение по умолчанию, в определенных ситуациях можно поднять до 10-20).
GUC-параметр log2_num_lock_partitions
При планировании и выполнении запросов устанавливаются тяжелые блокировки на объекты БД, участвующие в запросе, а по завершении транзакции эти блокировки снимаются. Информация о тяжелых блокировках хранится в хеш-таблице, расположенной в общей памяти сервера. Хеш-таблица менеджера блокировок поделена на 16 частей, доступ к каждой из которых защищен своей легкой блокировкой (транш LWLock:LockManager). На современных многоядерных системах с высокой степенью параллельности и большой нагрузкой 16 частей может оказаться недостаточно, если в запросе участвует более 16 объектов БД. В этом случае неизбежны коллизии: хеши, вычисленные по идентификаторам разных объектов БД, ссылаются на одну и ту же часть таблицы, что, в свою очередь, приводит к большой конкуренции за легкую блокировку, отвечающую за доступ к этой части хеш-таблицы. Поскольку захват блокировки осуществляется в исключительном режиме, коллизии хешей повышают вероятность ожидания процессов на событии LWLock:LockManager.
Для снижения влияния коллизий введен новый GUC-параметр log2_num_lock_partitions. Параметр позволяет настроить число частей, на которые будет поделена общая таблица блокировок, и, соответственно, количество легких блокировок в транше LWLock:LockManager. Значение параметра представляет степень, в которую нужно возвести число 2 (2^log2_num_lock_partitions), для получения фактического количества частей хеш-таблицы.
Увеличение количества секций относительно значения по умолчанию снижает конкуренцию при доступе к секциям структуры и может быть использовано при решении проблем с ожиданиями на LWLock:LockManager.
Диапазон значений: от 4 (16 частей) до 8 (256 частей).
Значение по умолчанию: 4 (16 частей).
Рекомендуемое значение на высокой нагрузке: 7.
GUC-параметр fastpath_num_locks
Для уменьшения нагрузки на разделяемую хеш-таблицу менеджера блокировок (LWLock:LockManager) применяется подход, называемый fast-path locking (блокировка объекта БД по быстрому пути). Fast-path-блокировка объекта БД возможна при выполнении следующих условий:
- блокировка захватывается на отношение (таблица, индекс, представление и другие);
- запрашиваются менее конфликтующие режимы тяжелой блокировки, допускающие одновременное изменение данных в таблице (не конфликтуют между собой):
AccessShareLock,RowShareLock,RowExclusiveLock; - отсутствуют транзакции, заблокировавшие таблицу в более конфликтующем режиме:
ShareLock,ShareRowExclusiveLock,ExclusiveLock,AccessExclusiveLock; - текущей транзакцией используется менее 16 слотов с информацией о блокировках отношений.
Каждая транзакция может использовать fast-path-блокировку только для 16 тяжелых блокировок отношений. Все дополнительные блокировки должны использовать разделяемую хеш-таблицу менеджера блокировок. Информация о менее конфликтующих блокировках, полученных по fast-path, хранится в разделяемой памяти, но конкуренция за этот участок возникает не так часто, как за хеш-таблицу менеджера блокировок. Обычно доступ к этой области памяти осуществляет только процесс, выполняющий запрос, поэтому можно рассматривать этот участок, как локальный для процесса. Исключением является случай, когда в одной транзакции уже взята менее конфликтующая блокировка на объект, а в другой захватывается более конфликтующая блокировка на тот же объект. Процесс с более конфликтующей блокировкой будет переносить информацию о менее конфликтующей блокировке другого процесса в общую хеш-таблицу менеджера блокировок, а для этого ему потребуется заблокировать доступ к памяти с fast-path-блокировками другого процесса. В сценариях нагрузки, когда более конфликтующие блокировки на объекты берутся достаточно редко, за счет использования fast-path-блокировок можно получить значительный прирост производительности.
Для снижения частоты использования разделяемой хеш-таблицы менеджера блокировок (LWLock:LockManager) введен новый GUC-параметр fastpath_num_locks. Параметр определяет число слотов в памяти каждого из обслуживающих процессов (бэкендов) для хранения информации о fast-path-блокировках на объекты БД.
Диапазон значений: от 16 до 10000.
Значение по умолчанию – 16. Максимальное значение – 10000.
Рекомендуемое значение на высокой нагрузке: 64 - 128.
GUC-параметр log2_num_buf_partitions
В СУБД Pangolin страницы отношений хранятся в буферном кеше. Он располагается в общей памяти сервера и доступен всем процессам. Когда менеджеру буферов требуется прочитать страницу, он сначала пытается найти ее в буферном кеше. Для быстрого поиска нужного буфера используется хеш-таблица Shared Buffer Lookup Table, хранящая номера буферов.
Для увеличения гранулярности хеш-таблица поделена на 128 частей (сегментов/бакетов), доступ к каждой из которых защищается своей отдельной легкой блокировкой.
Эти легкие блокировки объединены в транш блокировок LWLock::BufferMapping для данной хеш-таблицы. Перед обращением к хеш-таблице процесс должен захватить легкую блокировку, на которую выпал ключ хеширования: идентификатор файла отношения, тип слоя и номер страницы внутри файла этого слоя. Блокировка захватывается в двух режимах: в разделяемом режиме – для чтения и в исключительном – для изменений.
В большинстве сценариев обращения к хеш-таблице происходят очень активно, поэтому эта блокировка становится «узким местом». На современных многоядерных системах число сегментов 128 оказывается недостаточным из-за высокой конкуренции за доступ к отдельному сегменту.
Для решения описанной проблемы используйте GUC-параметр log2_num_buf_partitions для установки числа сегментов хеш-таблицы и, соответственно, количества легких блокировок в транше LWLock:BufferMapping. Увеличение значения параметра при интенсивной нагрузке позволит снизить вероятность ожидания процессов на событии LWLock:BufferMapping за счет увеличения гранулярности блокировок. Значение параметра представляет степень, в которую нужно возвести число 2, для получения фактического количества частей хеш-таблицы.
Диапазон значений: от 7 (128 частей) до 16 (65536 частей).
Значение по умолчанию: 7 (128 частей).
Рекомендуемое значение на высокой нагрузке: 10-12.
Включение функциональности
Задание параметров осуществляется в конфигурационных файлах СУБД Pangolin (postgres.conf для конфигурации standalone, postgres.yml для конфигурации cluster), или в командной строке при запуске сервера. Список GUC-параметров управления легкими блокировками:
lwlock_shared_limit;fastpath_num_locks;log2_num_lock_partitions;log2_num_buf_partitions.
После изменения параметра lwlock_shared_limit, для применения значения, достаточно выполнить процесс перечитывания параметров СУБД Pangolin (reload). Изменение fastpath_num_locks, log2_num_lock_partitions и log2_num_buf_partitions требует обязательного перезапуска сервера СУБД Pangolin (restart).
Отключение функциональности
Отключение производится путем установки параметров в значение по умолчанию:
lwlock_shared_limit = 0;log2_num_lock_partitions = 4;fastpath_num_locks = 16;log2_num_buf_partitions = 7.