Русский
Русский
English
Статистика
Реклама

Postgresql performance

Перевод Семь практических советов по массовой загрузке данных в PostgreSQL

19.09.2020 00:21:00 | Автор: admin

Вольный перевод статьи 7 Best Practice Tips for PostgreSQL Bulk Data Loading


Иногда возникает необходимость в несколько простых шагов загрузить в БД PostgreSQL большой объём данных. Данная практика обычно называется массовым импортом, когда в качестве источника данных служит один или несколько больших файлов. Данный процесс иногда может проходить неприемлемо медленно. Существует несколько причин такой низкой производительности. Вызывать задержки могут индексы, триггеры, внешние и первичные ключи или даже запись WAL файлов.


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


Совет 1. Перевод целевой таблицы в нежурналируемый режим


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


ALTER TABLE <target table> SET UNLOGGED;<bulk data insert operations>ALTER TABLE <target table> LOGGED;

Нежурналируемый режим гарантирует, что PostgreSQL не будет отправлять операции загрузки в таблицу в журнал предзаписи (WAL). Это может значительно ускорить процесс загрузки. Однако, раз эти операции не логируются, данные не смогут быть восстановлены в случае сбоя или незапланированного падения сервиса PostgreSQL вовремя заливки. PostgreSQL автоматически странкейтит любую нежурналируемую таблицу после рестарта.


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


Мы рекомендуем следующие подходы для заливки данных в нежурналируемые таблицы:


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

Совет 2. Удаление и пересоздание индексов


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


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


DROP INDEX <index_name1>, <index_name2>  <index_name_n><bulk data insert operations>CREATE INDEX <index_name> ON <target_table>(column1, ,column n)

Непосредственно перед созданием индексов может оказаться целесообразным временно увеличить конфигурационный параметр maintenance_work_mem. Выделение дополнительной рабочей памяти может помочь создать индексы быстрее.


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


Совет 3. Удаление и пересоздание внешних ключей


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


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


ALTER TABLE <target_table>     DROP CONSTRAINT <foreign_key_constraint>;BEGIN TRANSACTION;    <bulk data insert operations>COMMIT;ALTER TABLE <target_table>     ADD CONSTRAINT <foreign key constraint>      FOREIGN KEY (<foreign_key_field>)     REFERENCES <parent_table>(<primary key field>)...;

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


Совет 4. Деактивация триггеров


Триггеры на INSERT или DELETE (если процесс загрузки также содержит удаление записей из целевой таблицы) могут стать причиной замедления в процессе массового импорта данных. Это связано с тем, что каждый триггер содержит программную логику, которую нужно проверить и операции, которые нужно выполнить сразу после каждой вставки или удаления строки.


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


ALTER TABLE <target table> DISABLE TRIGGER ALL;<bulk data insert operations>ALTER TABLE <target table> ENABLE TRIGGER ALL;

Совет 5. Используйте команду COPY


Мы рекомендуем использовать штатную команду PostgreSQL COPY для загрузки данных из одного или нескольких файлов. COPY оптимизирована для массовой загрузки данных. Это более эффективно, нежели запуск большого количества операторов INSERT и даже одного INSERT-а с множественным включением выражения VALUE


COPY <target table> [( column1>,  , <column_n>)]    FROM  '<file_name_and_path>'     WITH  (<option1>, <option2>,  , <option_n>)

Среди других преимуществ использования команды COPY:


  • поддержка импорта, как из текстовых, так и из двоичных файлов;
  • работа в транзакционном режиме;
  • возможность указать структуру исходных файлов;
  • возможность ограничить выборку загружаемых данных использованием выражения WHERE.

Совет 6. Используйте оператор INSERT с множественным выражением VALUE


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


Использование оператора INSERT с множественным включением выражения VALUE поможет избежать этих накладных расходов.


INSERT INTO <target_table> (<column1>, <column2>, , <column_n>) VALUES     (<value a>, <value b>, , <value x>),    (<value 1>, <value 2>, , <value n>),    (<value A>, <value B>, , <value Z>),    (<value i>, <value ii>, , <value L>),    ...;

На производительность INSERTа с множественным VALUES влияют существующие индексы. Мы рекомендуем удалить индексы до запуска команды и пересоздать потом.


Ещё один аспект, который следует учесть, это общий объём оперативный памяти, доступный PostgreSQL для запуска INSERTа с множественным VALUES. Когда запускается такой INSERT, большое количество входных значений должно уместиться в RAM и если доступной памяти недостаточно, процесс может упасть с ошибкой.


Мы рекомендуем выставить параметр effective_cache_size в значение 50%, а параметр shared_buffer в значение 25% от общего объёма оперативной памяти компьютера. Также, в целях безопасности, при запуске серии INSERTов с множественным VALUES, каждый оператор будет запущен с ограничением в 1000 строк.


Совет 7. Запуск ANALYZE


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


Заключение


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

Подробнее..
Категории: Postgresql , Postgresql performance

Postgresso 28

02.02.2021 04:10:20 | Автор: admin


Привет всем уже в 21-м году. Надеемся, он будет добрей к нам, чем прошлый. Жизнь продолжается. И мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL. Для разнообразия начну с конференций: этот жанр больше всего пострадал.

Конференции


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

Nordic PGDay 2021

Отменена. Рассчитывают на Хельсинки в марте 2022. Виртуального варианта не будет, но собираются сфокусироваться на PostgreSQL-треке FOSDEM 2021 в феврале. На сайте написано 2022, но имеется в виду, судя по всему FOSDEM 2021, о котором ниже.

А вот подход Highload++. Бескомпромиссный никакого онлайна:
Highload++ 2020 (2021)

Конференцию HighLoad++ не стали переносить в онлайн решили, что она для этого слишком масштабная. Но даты передвинули с 9-10 ноября 2020 г. на 20-21 мая 2021 года. Должна пройти в Москве в Крокус Экспо 3.

А вот полная противоположность:
FOSDEM 2021

Никакого Брюсселя, в 2021 только онлайн. Не только бесплатно, но и регистрации даже не требуется. Среди участников этой огромной конференции немало докладчиков, известных среди российских постгресистов: Олег Бартунов, Павел Борисов, Алексей Кондратов, Анастасия Лубенникова, Никита Глухов (Postgres Professional), Николай Самохвалов (Postgres.ai), Пётр Зайцев (Percona), Андрей Бородин (Yandex), Олег Иванов (Samsung AI Center, он автор плагина AQO в Postgres Pro Enterprise).
Расписание можно попробовать изучить здесь. Поток PostgreSQL здесь.

PGConf.Online 2021

Последняя в этом списке, компенсирую большим количеством знаков: у меня просто больше информации.
Здесь комбинация оф и он: офлайн-конференция PGConf.Russia 2021 запланирована на на конец мая начало июня 2021 года. А 1-3 марта будет проведена онлайн-конференция с соответствующим названием PGConf.Online 2021.

Темы конференции:
  • Postgres на предприятии;
  • Масштабируемость;
  • Высокие нагрузки и очень большие базы данных;
  • devops;
  • Переход на Postgres.

Участие в онлайновой конференции бесплатное. Всем желающим участвовать нужно предварительно зарегистрироваться на сайте, трансляция докладов будет вестись из личных кабинетов. Если уже оплатили PGConf.Russia 2021, то регистрироваться повторно не нужно. Регистрация действительна для обоих событий PGConf.Online и ближайшего PGConf.Russia. Также можно отказаться от участия в PGConf.Russia и вернуть свои деньги. Для этого надо написать на info@pgconf.ru.

Доклады принимаются до 10 февраля в двух форматах: кратком (22 мин + вопросы) и полном (45 мин + вопросы) на русском и английском языках. Также приветствуются мастер-классы с практическими упражнениями и обучающие лекции по вопросам расширенной разработки и DBA. Мастер-классы могут длиться 90 или 180 минут.

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

Соревнования


PostgreSQL is the DBMS of the Year 2020

СУБД года! Это не рейтинг популярности, а рейтинг роста популярности. Из рейтингов на январь 2021 вычитаются рейтинги за январь 2020. А они вычисляются по методологии экспертов db-engines. По абсолютной, а не дифференциальной популярности postgreSQL по-прежнему на 4-м месте.
О соревновании x86 с ARM в облаках см. далее.

Облака


Тема ARM в облаках набирает обороты. Что не удивительно ARM наступает широким фронтом: суперкомпьютер на ARM взобрался на верхушку Top500; новые попытки Apple; процессор Whitechapel у Google; процессоры от Ampere Computing появятся в облаках Oracle; ну и, конечно, процессоры AWS Graviton2 с ядром Arm Neoverse в исполнении Amazon.

Вот две статьи: в одной Hosting Postgres on an AWS EC2 t4g Graviton2 ARM Instance рассказывается, как запустить и настроить инстансы t4g (но ещё и о выборе EC2 vs RDS); в другой PostgreSQL on ARM-based AWS EC2 Instances: Is It Any Good? исследуется производительность. Об этом чуть подробней: Жобин Аугустин (Jobin Augustine) и Сергей Кузьмичев (Sergey Kuzmichev) из Percona тестировали ARM vs. x86. ARM на инстансах m6gd.8xlarge на базе ARM-процессоров AWS Graviton2. Сам Amazon позиционирует их как обеспечивающий на 40 % лучшее соотношение цены и производительности по сравнению с показателями x86-инстансов M5 в тестах m5d.8xlarge. В обоих инстансах по 32 виртуальных процессора.

Для разминки прогнали на pgbench, ARM выиграл и на Read-Write и на Read-Only в районе 20%. При этом тестировщики не забывали отключать и включать проверку контрольных сумм мало ли что, архитектура разная. Затем перешли к основным перконовским тестам sysbench-tpcc. Размер базы подбирали так, чтобы она умещалась в память. Стали смотреть результаты на числе потоков от 16 до 128. Получилось, что на 16 примерно та же картина, как и на pgbench, а когда потоков больше, чем виртуальных процессоров, игра в ничью. Чтобы уж совсем не огорчать поклонников x86, авторы констатировали худшую производительность у ARM на тестах, оценивающих ввод-вывод. Но и то при 128 потоках. Подробности в статье и на гитхабе.

Теперь информация, связанных с апгрейдом в облаках Amazon:
Ensuring Consistent Performance After Version Upgrades with Amazon Aurora PostgreSQL Query Plan Management

Query Plan Management это расширение apg_plan_mgmt. В статье показано, как после апгрейда кластера Aurora PostgreSQL с 9.6.11 на 10.12 при помощи этого инструмента можно легко проверить, использует ли планировщик одобренный в предыдущей версии план запроса (планы могут получать статус Approved, Rejected, Unapproved, или Preferred).

Кстати, о версиях:
Amazon RDS for PostgreSQL Supports 12.5

RDS теперь поддерживает минорные версии: 12.5, 11.10, 10.15, 9.6.20 и 9.5.24.

Релизы


pgAdmin 4 v4.30

В этой версии появился (пока в статусе бета) новый инструмент: ERD диаграммы сущность-связь, то есть графическая репрезентация таблиц, столбцов и их взаимосвязей. Можно визуализировать уже существующие схемы БД, можно создавать мышью новые, а ERD сгенерит соответствующие SQL. Также появилась поддержка Kerberos.

PostgreSQL-плагин для Zabbix 5.2.4rc1

В новой версии появилась поддержка custom query для плагина PostgreSQL. Теперь можно создать файл .sql и положить его на свою машину. Далее в web-интерфейсе своего Zabbix-сервера в шаблоне для Zabbix-Agent2 находим элемент под названием pgsql.query.custom и в нем указываем макрос, который должен иметь значение имени sql файла с запросом (при этом в конфигурационном файле Zabbix-Agent2 нужно указать путь на машине к папке с sql файлом. И тогда агент сам выполняет запрос в sql файле и пришлет результат на Zabbix-сервер с остальными, дефолтными метриками. Автор плагина Дарья Вилкова, Postgres Professional.

Целая серия новых версий FDW:

sqlite_fdw 1.3.1
InfluxDB fdw 0.3
griddb_fdw 1.3

PostgresNIO 1.0

Это неблокирующий, event-driven клиент для Swift от Vapor, построенный на эппловской SwiftNIO. Этот клиент устанавливает соединение, авторизует и отправляет запрос на сервер, а результат обратно. Использует протокол PostgreSQL. Умеет создавать пул соединений. И ещё есть пакеты более высокого уровня поверх PostgresNIO postgres-kit.

PGMoon 12.0-1

pgmoon это клиентская библиотека, написанная на чистом Lua (MoonScript). pgmoon с самого начала была разработана для использования в OpenResty web-платформе на базе докрученного Nginx), чтобы можно было пользоваться API 100% неблокирующих cosockets для асинхронных запросов.

Ещё статьи


Расширение кластера PostgreSQL размером 5,7 ТБ и переход с версии 9.6 на 12.4

Статья в блоге Альфа-Банка, автор оригинала Томми Ли (Tommy Li, Coffee Meets Bagel приложение для романтических знакомств с системой курирования).

Базы работали на 6 серверах Postgres на инстансах i3.8xlarge в амазоновском облаке: одна главная нода, три реплики для раздачи веб-трафика только для чтения, балансируемые с помощью HAProxy, один сервер для асинхронных воркеров и один сервер для ETL (Extract, Transform, Load) и Business Intelligence. Для поддержания реплик в актуальном состоянии использовалась потоковая репликация.

Надо было одновременно проапгрейдить Postgres и перейти с i3.8xlarge на i3.16xlarge при минимальной суммарной остановке 4 ч. (а вышло полчаса). Для миграции использовали pglogical. Также в статье из этого опыта извлекли уроки. Эта статья вызвала справедливые и несправедливые замечания в комментариях. Так что примечателен не только сам случай, но и реакция на него, да и тот факт, что перевод статьи появился не где-нибудь, а на хабр-блоге Альфа-Банка (до этого там о базах данных ничего, кажется, не было).

PostgreSQL Scaling Advice For 2021

Каарел Моппел (Kaarel Moppel, Cybertec), чьи статьи регулярно попадают в наши обзоры, дерзнул дать советы тем, кто озабочен будущим масштабированием своих систем. Каарел признаётся, что воодушевился роликом Distributed MySQL Architectures Past, Present, Future Петра Зайцева, основателя и гендира Percona, и приложил (так как, по его, Каарела, словам, MySQL и Postgres суть сводные братья) некоторые выводы Петра к родной PostgreSQL и добавил собственные.

Итого: что даёт обычный Postgres?
  • один инстанс PostgreSQL легко выполняет сотни тысяч транзакций в секунду;
  • одна нода обычно выполняет десятки тысяч пишущих транзакций в секунду;
  • один инстанс Postgres легко справляется с десятками ТБ данных;
  • один инстанс на одной ноде даёт буквально пуленепробиваемую надёжность при должной заботе о согласованности данных;
  • в причинах сбоев легко разобраться, поэтому данные можно восстановить.


О чём не стоит забывать, когда озаботился масштабированием?
  • не бойтесь заводить свои собственные (а не поддерживаемые в облаке) базы данных;
  • старайтесь избегать архитектуры данных, у которой в основе одна большая таблица;
  • убедитесь, что вы выбрали подходящий ключ разбиения при шардинге вашей таблицы/базы.


Агрегаты в БД

Кирилл Боровиков aka Kilor (компания Тензор) на этот раз обратился к агрегатам. Это мини-серия из двух статей: Агрегаты в БД зачем, как, а стоит ли? и продолжение Агрегаты в БД эффективная обработка потока фактов. В первой движение мысли от count(*) к подсчетам с парсингом EXPLAIN, к сбору агрегатов в отдельную таблицу, к хранению временных агрегатов в памяти процесса и даже к хранению их вообще в другой СУБД.

Во второй статье агрегация обретает бизнес-очертания: пересчет остатков и ведение сводных продаж по товарам при их постоянных отгрузках, или агрегация сальдо и оборотов по бухгалтерским счетам, при массовых изменениях проводок. Цель: агрегаты по продажам в разрезе товар/день/кол-во. Разных товаров очень много и отгрузок много. Решение: конкурентная обработка очередей, чтение из курсора читайте подробности.

Образование


Чёрная Малютка

Вышла новая версия знаменитой книжки-малышки
Postgres: первое знакомство.



Книжечка проапгрейдилась до версии PostgreSQL 13. В бумажном виде она, как и раньше, будет раздаваться на конференциях, которые проходят с участием Postgres Professional. PDF можно скачать.

DEV2: Разработка серверной части приложений PostgreSQL 12. Расширенный курс.

Напоминаем о появившемся курсе. Задача его не просто познакомить с базовыми функциями PostgreSQL, но и научить пользоваться его расширяемостью: дополнять серверные механизмы собственным кодом.

Митапы и подкасты


Постгрес-вторник с Петром Зайцевым

Петра Зайцева, основателя Percona, Николай Самохвалов и Илья Космодемьянский зазывали на свои Вторники целый год. Свершилось. Был разговор о компании (из которого выяснилось, что сейчас в компании около 300 сотрудников, из них человек 50 постгресистов); о причинах дрейфа компании от MySQL и MongoDB в сторону PostgreSQL (не по любви, и не из-за технологических причин, а просто в это сторону двигались клиенты и потенциальные клиенты); о разной атмосфере в комьюнити MySQL, MongoBD и PostgreSQL (второе самое монополистическое, а третье самое открытое). Но гвоздь программы перконовская утилита мониторинга pg_stat_monitor.

Монитор опирается на расширении pg_stat_statements, но добавляет некоторую функциональность. Можно, например, посмотреть тексты запросов, отбирающих много ресурсов, сравнить прожорливость одного и того же запроса с разными планами; монитор знает название приложения, отправившего запрос. В этом контексте возник и разговор о новом расширении PWR (pgpro_pwr), вошедшем в Postgres Pro Standard и Enterprise 13. Это, кажется, обсудят на следующем Вторнике (мы же обещали статью о нём и обещание скоро сдержим).
Подробнее..

Кеш бывает разным

02.02.2021 12:18:59 | Автор: admin

PostgreSQL хранит данные на каких-то носителях. И между PostgreSQL и, например, магнитной поверхностью диска находится несколько кешей: кеш самого винчестера, кеш RAID-контроллера или винчестерной полки, кеш файловой системы на уровне операционной системы и кеш самого PostgreSQL. Если первыми перечисленными кешами мы практический не можем управлять, то последними, находящимися в ОЗУ сервера, управлять можем: например, выделяя больше ОЗУ под кеш PostgreSQL в ущерб кешу ОС, или наоборот. В официальной документации можно прочитать ничем не подтвержденные рекомендации, типа выделять под PostgreSQL четверть ОЗУ. Это вызывает сомнения. PostgreSQL в виде Postgres95 впервые появился в 1995 году и, кто знает, быть может и эти рекомендации относятся к тому же году. Поэтому появилась идея эксперимента с целью разобраться, как лучше распределять ОЗУ.


Сразу оговорюсь, что речь пойдет про выделенный под БД сервер, на котором помимо самого PostgreSQL и обслуживающей его инфраструктуры ничего нет. Если рассмотреть эту задачу умозрительно, то интуитивно понятно, что своя рубашка ближе к телу, то есть со своим собственным кешем PostgreSQL должен работать оптимальнее. Например, в своем кеше PostgreSQL хранит информацию постранично, а размер страницы в PostgreSQL по умолчанию 8 Кб. В кеше ОС информация хранится тоже постранично, но размер страницы в памяти ОС и, обычно, файловой системы равен 4 Кб, то есть возможна фрагментация страницы PostgreSQL. Но на практике такие различия, связанные с тем, что в собственном кеше данные хранятся в более оптимальном виде, малозаметны. Другое отличие кешей заключается в том, как выбирается для удаления страница, чтобы записать новую. Кеш ОС работает просто: он удаляет ту страницу, к которой дольше всего не обращались. А кеш PostgreSQL пытается вести себя умнее, ведь данные бывают разными более или менее полезными. Например, индексы или данные за последний месяц, к которым обращаются чаще, более полезны, чем данные, скажем, годичной давности, к которым обращаются редко. Поэтому PostgreSQL выставляет данным своеобразную оценку полезности и в первую очередь высвобождает наименее полезную информацию. А если PostgreSQL видит, что намечается последовательное чтение большой таблицы, которое может вымыть остальные данные из кеша, то он принимает меры, чтобы этого не случилось. Вот такую оптимизацию, связанную с интеллектуальным анализом полезности кеша, и должен был продемонстрировать эксперимент. Также с его помощью решался вопрос о том, насколько влияют на производительность PostgreSQL HugePages.


Довольно сложно найти документацию, описывающую алгоритмы работа кеша PostgreSQL. Для желающих изучить этот вопрос более углубленно, привожу ссылку: Inside the PostgreSQL Shared Buffer Cache


Описание эксперимента


Идея проста. Создаю одну таблицу, размер которой больше ОЗУ сервера, и индекс к этой таблице, который занимает где-то 10% от размера таблицы. Мне показалось, что такая пропорция реалистична. Cначала прогреваю таблицу, потом индекс, чтобы они по максимуму находились в кеше. Измеряю время индексированного поиска. Запускаю неиндексированный поиск, который выполняет последовательное чтение всей таблицы, измеряю длительность его работы. А после этого повторяю эксперимент по индексированному поиску. Предполагаю, что в случае работы кеша PostgreSQL разница между поисками по индексу до и после поиска последовательным чтением таблицы будет минимальна, а в случае кеша ОС заметна. Эксперимент буду повторять с различными пропорциями кешей ОС и PostgreSQL, а также с использованием HugePages и без них.


Описание стенда


Стенд сделал из того, что было: ноут MSI, операционка сообщает о 8 ядрах процессора, 16 Гб ОЗУ (HugePages 2 Мб на 14 Гб), 0 swap. К тому же Linux ругался о том, что процессор перегревается и приходится сбрасывать частоту, что наверняка сказалось на повторяемости эксперимента. Софт: CentOS 8 и PostgreSQL 13.0.


Подробно опишу эксперимент, чтобы любой желающий мог его повторить в своих условиях. Прогревание выполняется с помощью функции pg_prewarm(), но поскольку в результате эксперимента выяснилось, что pg_prewarm хоть и заполняет кеш, но прогревает недостаточно, после неё дополнительно прогреваю с помощью pgbench. Потом через тот же pgbench замеряю длительность индексированного поиска, поиска через последовательное чтение и снова индексированного. Результаты складываю в CSV-файлы, которые потом импортирую в Exсel, там обрабатываю и строю графики. Видимо, из-за фрагментирования памяти иногда невозможно создавать HugePages большого размера. Поэтому цикл тестирования выглядит так: перезагружаю машину, из rc.local вызываю тестирующий скрипт, он прогоняет тесты с включенными HugePages от максимального размера кеша PostgreSQL к минимальному, потом скрипт повторяет то же самое с выключенными HugePages, после чего перезагружает машину. Размер HugePage равен 2 Мб.


Все файлы лежат в одной директории, вот их список:


postgresql.conf
include = 'shared_buffers.conf'# при max_parallel_workers_per_gather>6 ошибка выполнения при размере кеша PostgreSQL 128 Кбmax_parallel_workers_per_gather=6

Этот файл инклюдится в postgresql.conf базы данных с помощью директивы include. Он нужен для проведения эксперимента с разными настройками PostgreSQL.


shared_buffers.conf
shared_buffers=128kB

Скриптом, который выполняет тестирование, в этот файл записывается размер кеша PostgreSQL.


init.sql
-- Размер таблицы, которую нужно создать. Подбирается методом проб и ошибок так, чтобы таблица имела размер, равный ОЗУ.\set table_size  75000000-- Создаю таблицу с именем random, там лежат случайные данные. :)drop table if exists random;create table random(random real, data float[]);insert into random select random,array_fill(random,ARRAY[20]) from (select random() as random, generate_series(1,:table_size)) as subselect;-- И индекс к ней.create index on random(random);-- Дальнейшие операции требуют роль суперпользователя, мой пользователь имеет эту роль, поэтому переключиться несложно.set role postgres;-- Модуль для функции pg_prewarmcreate extension if not exists pg_prewarm;-- Модуль, в котором можно наблюдать структуру кеша PostgreSQLcreate extension if not exists pg_buffercache;-- View на базе предыдущего модуля для наблюдением за кешем. Для эксперимента не используется, и во время эксперимента лучше не использовать, т.к. pg_buffercache вел себя нестабильно и иногда рушил процесс PostgreSQL.create or replace view cache as SELECT n.nspname AS schema,    c.relname,    pg_size_pretty(count(*) * 8192) AS buffered,    count(*) * 8 AS buffered_KiB,    round(100.0 * count(*)::numeric / ((( SELECT pg_settings.setting           FROM pg_settings          WHERE pg_settings.name = 'shared_buffers'::text))::integer)::numeric, 1) AS buffer_percent,    round(100.0 * count(*)::numeric * 8192::numeric / pg_table_size(c.oid::regclass)::numeric, 1) AS percent_of_relation   FROM pg_class c     JOIN pg_buffercache b ON b.relfilenode = c.relfilenode     JOIN pg_database d ON b.reldatabase = d.oid AND d.datname = current_database()     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace  GROUP BY c.oid, n.nspname, c.relname  ORDER BY (round(100.0 * count(*)::numeric / ((( SELECT pg_settings.setting           FROM pg_settings          WHERE pg_settings.name = 'shared_buffers'::text))::integer)::numeric, 1)) DESC LIMIT 5;-- View, в котором можно посмотреть размер таблицы на диске, использовался для подгона размера таблицы под ОЗУ.create or replace view disk as SELECT n.nspname AS schema,    c.relname,    pg_size_pretty(pg_relation_size(c.oid::regclass)) AS size,    pg_relation_size(c.oid::regclass)/1024 AS size_KiB   FROM pg_class c     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace  ORDER BY (pg_relation_size(c.oid::regclass)) DESC LIMIT 5;vacuum full freeze analyze;

SQL-скрипт, который создает окружение в БД, выполняется перед экспериментом. Запускается с помощью psql база -f init.sql.


test_idx.sql
select random from random where random=(select random()::real);

test_seq.sql
select count(data) from random;

Здесь находятся SQL-запросы, которые выполняет pgbench во время тестирования.


config.sh
# database connection parametersexport PGDATABASE='pgcache'# Добавляю путь к бинарникам PostgreSQL, это было нужно на CentOS и, возможно, других редхатоподобных дистрибутивах.PATH=$PATH:/usr/pgsql-13/bin# Через пробел указаны значения для конфигурационной переменной PostgreSQL shared_buffers, т.е. собственно размеры кеша на которых будет производится тестирование. Порядок по уменьшению величин важен. Дело в том, что HugePages уменьшить можно всегда, а вот увеличить  не всегда, видимо, из-за фрагментации памяти. Поэтому тестирование ведется при уменьшении размера кеша.readonly shared_buffers='14GB 13GB 12GB 11GB 10GB 9GB 8GB 7GB 6GB 5GB 4GB 3GB 2GB 1GB 512MB 256MB 128MB 64MB 32MB 16MB 8MB 4MB 2MB 1MB 512kB 256kB 128kB';

get_huge_pages
#!/bin/bash. config.shreadonly postgresql_service='postgresql-13' postgresql_pid='/var/lib/pgsql/13/data/postmaster.pid'readonly huge_pages_sh='huge_pages.sh' shared_buffers_conf='shared_buffers.conf'sudo systemctl start "$postgresql_service"echo 'declare -r -A huge_pages_size=( \' >"$huge_pages_sh"for s_b in $shared_buffersdo   echo "shared_buffers=$s_b" >"$shared_buffers_conf"   sleep 5   sudo systemctl restart "$postgresql_service"   pid=$(sudo head -1 "$postgresql_pid")   echo -n '   [' >>"$huge_pages_sh"   psql --expanded --quiet --tuples-only -c "show shared_buffers" | awk '/^shared_buffers \|/{printf "%s", $3}' >>"$huge_pages_sh"   echo -n ']=' >>"$huge_pages_sh"   sudo awk '/^VmPeak:/ {printf "%i", $2/2048+1}' /proc/"$pid"/status >>"$huge_pages_sh"   echo ' \' >>"$huge_pages_sh"doneecho ')' >>"$huge_pages_sh"sudo systemctl stop "$postgresql_service"

Вспомогательный скрипт. Он берет из config.sh значения для shared_buffers, запускает с этими настройками PostgreSQL, замеряет, сколько нужно HugePages для его работы в данной конфигурации, и записывает результат работы в файл huge_pages.sh.


huge_pages.sh
declare -r -A huge_pages_size=( \   [14GB]=7416 \   [13GB]=6893 \   [12GB]=6370 \   [11GB]=5847 \   [10GB]=5323 \   [9GB]=4800 \   [8GB]=4277 \   [7GB]=3750 \   [6GB]=3226 \   [5GB]=2703 \   [4GB]=2180 \   [3GB]=1655 \   [2GB]=1131 \   [1GB]=607 \   [512MB]=345 \   [256MB]=209 \   [128MB]=142 \   [64MB]=108 \   [32MB]=91 \   [16MB]=82 \   [8MB]=78 \   [4MB]=76 \   [2MB]=75 \   [1MB]=74 \   [512kB]=74 \   [256kB]=74 \   [128kB]=74 \)

Здесь лежат результаты работы get_huge_pages, они используются в скрипте test.


dataHP.csv и dataNHP.csv
Результаты работы скрипта test, используются потом в Excel.


output.log
Вывод из скрипта test полезен, если там содержатся ошибки, а если их нет он пустой.


Пример запуска тестирующего скрипта. Отредактировал файл, который уже был в CentOS:


/etc/rc.local
#!/bin/bash# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES## It is highly advisable to create own systemd services or udev rules# to run scripts during boot instead of using this file.## In contrast to previous versions due to parallel execution during boot# this script will NOT be run after all other services.## Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure# that this script will be executed during boot.sudo -u myuser /home/myuser/experiment/pgcache/test &>/home/myuser/experiment/pgcache/output.log &touch /var/lock/subsys/local

Собственно, тестирующий скрипт:


test
#!/bin/bashset -eCu -o pipefailpostgresql_service="postgresql-13"# перехожу в директорию, где лежит этот скриптcd "$( dirname "${BASH_SOURCE[0]}" )" || exit $?# настроечные опции. config.sh# ассоциативный массив, связывающий размер кеша PostgreSQL и количество нужных ему hugepages. huge_pages.sh# заголовок для CSV-файловreadonly header='huge_pages(2MiB),pg_cache,pg_cache(KiB),idx1(ms),seq(ms),idx2(ms),heap_blks_read,heap_blks_hit,idx_blks_read,idx_blks_hit,finish'date --iso-8601=seconds# цикл по включенным и отключенным hugepagesfor hp in 'HP' 'NHP'do# Цикл по всем "ступенькам" размера кеша, по которым надо пройтись    for s_b in $shared_buffers   do      data_csv="data${hp}.csv"      if [ ! -s "$data_csv" ]      then         echo "$header" >|"$data_csv"      fi      echo "shared_buffers=$s_b" >|'shared_buffers.conf'      if [ "$hp" = 'HP' ]      then         set_huge_pages=${huge_pages_size["$s_b"]}      else         set_huge_pages=0      fi      huge_pages=$(awk '/^HugePages_Total:/ {print $2}' /proc/meminfo)      if [ $huge_pages -ne $set_huge_pages ]      then         sudo sysctl --quiet --write vm.nr_hugepages="$set_huge_pages"         while [ $(awk '/^HugePages_Total:/ {print $2}' /proc/meminfo) -gt $set_huge_pages ]         do            sleep 1         done      fi      huge_pages=$(awk '/^HugePages_Total:/ {print $2}' /proc/meminfo)      if [ $set_huge_pages -ne $huge_pages ]      then         echo -n 'hugepage_error,' >>"$data_csv"         echo "$(date --iso-8601=seconds)" >>"$data_csv"         continue      fi      echo -n "$huge_pages," >>"$data_csv"      sudo systemctl start "$postgresql_service"      psql --expanded --quiet --tuples-only -c "show shared_buffers" | awk '/^shared_buffers \|/ {printf "%s,", $3}' >>"$data_csv"      psql --expanded --quiet --tuples-only -c "select setting::int*8 as shared_buffers from pg_settings where name='shared_buffers'" | awk '/^shared_buffers \|/ {printf "%s,", $3}' >>"$data_csv"      # prewarm to the cache      psql --quiet -c "select pg_prewarm('random')" -c "select pg_prewarm('random_random_idx')" >/dev/null      # more prewarm      pgbench --no-vacuum --time 100 --file test_idx.sql >/dev/null      # reset stats      psql --quiet -c "select pg_stat_reset_single_table_counters('random'::regclass),pg_stat_reset_single_table_counters('random_random_idx'::regclass)" >/dev/null      # first test index search      pgbench --no-vacuum --transaction 100 --report-latencies --file test_idx.sql | awk '/select random from random where random=\(select random\(\)::real\);$/ {printf "%s,", $1 >>"'"$data_csv"'";}'      # test sequence scan      pgbench --no-vacuum --transaction 1 --report-latencies --file test_seq.sql | awk '/select count\(data\) from random;$/ {printf "%s,", $1 >>"'"$data_csv"'"}'      # second test index search      pgbench --no-vacuum --transaction 100 --report-latencies --file test_idx.sql | awk '/select random from random where random=\(select random\(\)::real\);$/ {printf "%s,", $1 >>"'"$data_csv"'";}'      # get stats      sleep 10      psql --quiet --tuples-only --field-separator=' ' --no-align -c "select heap_blks_read,heap_blks_hit,idx_blks_read,idx_blks_hit from pg_statio_user_tables where relname='random'"| head -1 | awk '{printf "%s,", $1 >>"'"$data_csv"'";printf "%s,", $2 >>"'"$data_csv"'";printf "%s,", $3 >>"'"$data_csv"'";printf "%s,", $4 >>"'"$data_csv"'";}'      sudo systemctl stop "$postgresql_service"      echo "$(date --iso-8601=seconds)" >>"$data_csv"   donedonesudo systemctl reboot

Результаты


Здесь и далее по оси X отложены значения кеша PostgreSQL, ОЗУ около 16 Гб, вся неиспользуемая память используется, разумеется, как файловый кеш ОС. По оси Y отложено время выполнения запроса в миллисекундах. Синим цветом без использования HugePages, оранжевым с HugePages. Вид графика коробочки с усиками, подробно про них можно прочитать в документации Excel; удобны тем, что показывают не только усредненные значения, но и разброс, и распределение данных. В каждой итерации было 27 тестов с HugePages и 27 без, итераций было 251, всего было 13554 тестов.


idx1


С увеличением кеша PostgreSQL график раздваивается. Без HugePages скорость выполнения запроса а это простой поиск с использованием индекса падает. С увеличением кеша PostgreSQL только с использованием HugePages PostgreSQL кеш начинает незначительно выигрывать у кеша файловой системы. Когда я тестировал два года назад на CentOS 7 и PostgreSQL 10, кеш файловой системы работал примерно с такой же скоростью, что и кеш PostgreSQL без HugePages, а добавление HugePages давало значимый выигрыш над кешем файловой системы. Из чего я могу сделать вывод, что за последние годы Linux научился гораздо эффективнее использовать свой файловый кеш.


seq


Последовательное чтение таблицы. Тут заметно ускорение запроса, если кеш PostgreSQL больше кеша файловой системы. Что интересно (и для меня непонятно), на большей части графика использование HugePages замедляет выполнение запроса, и только при очень больших значениях кеша PostgreSQL выигрыш становится заметен. Не знаю, с чем это связано, наверное, разработчикам PostgreSQL есть еще над чем подумать.


idx2


Повторный поиск по индексу. Здесь и демонстрируется тот эффект, который я описывал в самом начале. Если использовать кеш файловой системы (задан небольшой размер кеша PostgreSQL), то при последовательном чтении таблицы индекс вымывается из кеша, что демонстрирует длительный повторный поиск по индексу. Этот эффект пропадает примерно тогда, когда кеш PostgreSQL становится достаточно большим, чтобы индекс хранился в нём, а не в кеше файловой системы, и график становится похож на график, который был до последовательного чтения таблицы: примерно 0,08 мс с HugePages и 0,12 мс без HugePages.


Выводы


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

Подробнее..

Перевод Измеряем расходы на память у Postgres процессов

10.06.2021 18:12:02 | Автор: admin

Это вольный перевод поста одного из сильных разработчиков Postgres - Andres Freund. Кроме того что разработчик сильный, так еще и статья довольно интересная и раскрывает детали того как работает ОС Linux.

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

Как по мне, здесь есть что обсудить. Кроме того можно сделать несколько улучшений и уменьшить использование памяти.

Я думаю что эта обеспокоенность оверхэдом на память вызвана одной общей причиной, это то что самый простой способ измерения потребления памяти через утилиты типа top и ps является довольно обманчивым.

И действительно, особенно довольно сложно измерить то как увеличивается используемая память при каждом новом соединении.

В этом посте я буду говорить о Postgres работающем на Linux, т.к. именно в этом направлении у меня больше всего опыта.

И перед тем как продолжить я хочу акцентировать внимание, что при точном и аккуратном измерении, одно соединение имеет накладные расходы на уровне меньше 2MiB (см. выводы в конце поста).

первый взгляд

Если использовать стандартные утилиты операционной системы, то можно сделать вывод, что накладные расходы существенно больше (чем есть на самом деле). Особенно если не использовать большие страницы (huge pages), то использование памяти каждый процессом действительно выглядит слишком большим. Отмечу что настоятельно рекомендуется использовать большие страницы. Давайте взглянем на только что установленное соединение, в только что запущенном Postgres:

andres@awork3:~$ psqlpostgres[2003213][1]=# SELECT pg_backend_pid(); pg_backend_pid         2003213 (1 row)andres@awork3:~/src/postgresql$ ps -q 2003213 -eo pid,rss    PID   RSS2003213 16944

Около 16MiB.

Утечки памяти!?! К счастью, нет.

При этом со временем памяти используется все больше и больше. Чтобы продемонстрировать это, я воспользуюсь расширением pgprewarm, чтобы загрузить таблицу в буфер (shared buffers):

postgres[2003213][1]=# SHOW shared_buffers ; shared_buffers  16GB           (1 row)postgres[2003213][1]=# SELECT SUM(pg_prewarm(oid, 'buffer')) FROM pg_class WHERE relfilenode <> 0;  sum    383341 andres@awork3:~$ ps -q 2003213 -eo pid,rss    PID   RSS2003213 3169144

Теперь использование памяти достигло уровня 3GB. При том что, на самом деле, в этой сессии не потребовалось выделять дополнительную память. Объем используемой памяти, увеличился пропорционально объему используемого буфера:

postgres[2003213][1]=# SELECT pg_size_pretty(SUM(pg_relation_size(oid))) FROM pg_class WHERE relfilenode <> 0; pg_size_pretty  2995 MB        (1 row)

Что еще хуже, даже если эти страницы будут использовать в других сессиях, это также будет отображаться как использование большого объема памяти:

postgres[3244960][1]=# SELECT sum(abalance) FROM pgbench_accounts ; sum    0 (1 row)andres@awork3:~/src/postgresql$ ps -q 3244960 -eo pid,rss    PID   RSS3244960 2700372

Конечно, Postgres на самом деле не использует 3GB и 2.7GB памяти в данном случае. На самом деле, в случае huge_pages=off, утилита ps отображает объем разделяемой (shаred - память совместно используемая с другими процессами) памяти, включая и страницы в буфере которые используются в каждой сессии. Очевидно это приводит к значительной переоценке величины используемой памяти.

На помощь внезапно приходят большие страницы

Множество процессорных микро-архитектур обычно используют страницы размером 4KiB, но также могут использовать и страницы большего размера, например широко распространенный вариант это 2MiB.

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

Если повторить вышеописанный эксперимент с huge_pages=on, можно увидеть гораздо более приятные глазу результаты. Для начала, взглянем на "новый процесс":

andres@awork3:~$ ps -q 3245907 -eo pid,rss    PID   RSS3245907  7612

Теперь, новый процесс использует всего около 7MiB. Такое уменьшение вызвано тем что таблицы управления страницами (page table) теперь требуют меньше места, из-за того что используются большие страницы, для управления тем же объемом памяти нужно в 512 раз меньше элементов чем раньше (4KiB * 512 = 2MiB).

Теперь давайте посмотрим что произойдет при доступе к большим объемам данных в памяти:

postgres[3245843][1]=# ;SELECT SUM(pg_prewarm(oid, 'buffer')) FROM pg_class WHERE relfilenode <> 0;postgres[3245851][1]=# SELECT sum(abalance) FROM pgbench_accounts ;andres@awork3:~$ ps -q 3245907,3245974 -eo pid,rss    PID   RSS3245907 122603245974  8936

В отличие от самого первого эксперимента, эти процессы используют всего 12MiB и 9MiB соответственно, в то время как в прошлый раз использовалось 3GiB и 2.7GiB.

Разница довольно очевидна ;)

Это следствие того, как в Linux реализован учёт использования больших страниц, а не потому, что мы использовали на порядки меньше памяти: используемые большие страницы не отображаются как часть значения RSS в выводе ps и top.

Чудес не бывает

Начиная с версии ядра 4.5, появился файл /proc/$pid/status в котором отображается более подробная статистики об использование памяти процессом:

  • VmRSS общий размер используемой памяти. Значение является суммой трех других значений (VmRSS = RssAnon + RssFile + RssShmem)

  • RssAnon размер используемой анонимной памяти.

  • RssFile размер используемой памяти ассоциированной с файлами.

  • RssShmem размер используемой разделяемой памяти (включая SysV shm, сегменты в tmpfs и анонимные разделяемые сегменты)

andres@awork3:~$ grep -E '^(Rss|HugetlbPages)' /proc/3247901/statusRssAnon:    2476 kBRssFile:    5072 kBRssShmem:    8520 kBHugetlbPages:       0 kBpostgres[3247901][1]=# SELECT SUM(pg_prewarm(oid, 'buffer')) FROM pg_class WHERE relfilenode <> 0;andres@awork3:~$ ps -q 3247901 -eo pid,rss    PID   RSS3247901 3167164andres@awork3:~$ grep -E '^(Rss|HugetlbPages)' /proc/3247901/statusRssAnon:    3148 kBRssFile:    9212 kBRssShmem: 3154804 kBHugetlbPages:       0 kB

RssAnon отображает объем "анонимной" памяти, т.е. участки рабочей памяти которые не являются отображанием файлов на диске. RssFile это как раз отображение в памяти конкретных файлов на диске, включая даже исполняемый файл postgres. И последнее RssShmem отображает доступную разделяемую память без учета больших страниц.

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

И теперь взглянем на эту же статистику, но с huge_pages=on:

andres@awork3:~$ grep -E '^(Rss|HugetlbPages)' /proc/3248101/statusRssAnon:    2476 kBRssFile:    4664 kBRssShmem:       0 kBHugetlbPages:  778240 kBpostgres[3248101][1]=# SELECT SUM(pg_prewarm(oid, 'buffer')) FROM pg_class WHERE relfilenode <> 0;andres@awork3:~$ grep -E '^(Rss|HugetlbPages)' /proc/3248101/statusRssAnon:    3136 kBRssFile:    8756 kBRssShmem:       0 kBHugetlbPages:    3846144 kB

Увеличиваем точность

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

Первое, на самом деле учет RssFile в использовании памяти не играет роли - по факту это всего лишь исполняемый файл и используемые им разделяемые библиотеки (Postgres не использует mmap() для каких-либо файлов). Все эти файлы являются общими для всех процессов в системе и практически не дают накладных расходов для постгресовых процессов.

Второе, RssAnon также переоценивает использование памяти. Смысл тут в том что ps показывает всю память процесса целиком, при том что большая часть этой памяти в случае создания нового процесса делится между пользовательским соединением и памятью родительского процесса postgres (так же известен как postmaster). Это следует из того что Linux не копирует всю память целиком когда создает новый процесс (при выполнении операции fork()), вместо этого используется механизм Copy-on-Write для копирования в новый процесс, набора только измененных страниц.

Таким образом, пока нет хорошего способа аккуратно и точно измерить использование памяти отдельно взятого нового процесса. Но все не так плохо, начиная с версии 4.14 ядро предоставляет еще одну статистику (коммит с описанием) процесса в /proc/$pid/smaps_rollup файле. Pss показывает "принадлежащую процессу пропорциональную долю отображения" среди всех отображений этого процесса (детали можно найти в документации поиском по smaps_rollups и Pss которые сами по себе не имеют прямых ссылок). Для сегмента памяти используемого совместно между несколькими процессами, доля будет представлять собой отношение размера этого сегмента на количество процессов которые используют этот сегмент.

postgres[2004042][1]=# SELECT SUM(pg_prewarm(oid, 'buffer')) FROM pg_class WHERE relfilenode <> 0;  sum    383341 (1 row)postgres[2004042][1]=# SHOW huge_pages ; huge_pages  off        (1 row)andres@awork3:~$ grep ^Pss /proc/2004042/smaps_rollupPss:             3113967 kBPss_Anon:           2153 kBPss_File:           3128 kBPss_Shmem:       3108684 kB

Pss_Anon включает в себя анонимную память используемую процессом, Pss_File включает память используемую под разделяемые библиотеки задействование процессом, и Pss_Shmem (если не используются большие страницы) показывает использование общей памяти разделенное на все процессы которые обращались к соответствующим страницам.

Но у пропорциональных значений есть небольшой недостаток, это использование делителя который зависит от числа подключений к серверу. Здесь я использовал pgbench (scale 1000, -S -M prepared -c 1024) чтобы создать большое число подключений:

postgres[2004042][1]=# SELECT count(*) FROM pg_stat_activity ; count   1030 (1 row)postgres[2004042][1]=# SELECT pid FROM pg_stat_activity WHERE application_name = 'pgbench' ORDER BY random() LIMIT 1;   pid    3249913 (1 row)andres@awork3:~$ grep ^Pss /proc/3249913/smaps_rollupPss:                4055 kBPss_Anon:           1185 kBPss_File:              6 kBPss_Shmem:          2863 kB

И с использованием huge_pages=on:

andres@awork3:~$ grep ^Pss /proc/2007379/smaps_rollupPss:                1179 kBPss_Anon:           1173 kBPss_File:              6 kBPss_Shmem:             0 kB

Как я понимаю Андрес намекает здесь на то что из-за большого количества процессов и соответственно большого делителя, значение Pss_Shmem становится маленьким, отчего может складываться впечатление что процесс использует мало разделяемой памяти хотя по факту мог использовать ее гораздо больше (Прим. переводчика).

К сожалению Pss значения учитывают только те ресурсы, что видны приложению. Например, размер таблицы страниц не учитывается. Размер таблицы страниц можно увидеть в уже упоминавшемся `/proc/$pid/status`.

Я не уверен, но насколько я знаю, VmPTE (размер таблицы страниц) полностью приватный для каждого процесса, но остальное большинство Vm* значений, включая стек VmStk являются общими через copy-on-write.

Учитывая всё это, накладные расходы с учетом таблицы страниц и с huge_pages=off:

andres@awork3:~$ grep ^VmPTE /proc/2004042/statusVmPTE:      6480 kB

и с huge_pages=on:

VmPTE:     132 kB

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

Вывод

На основе проделанных измерений, мы можем представить что процесс выполняющий достаточно простую read-only OLTP нагрузку имеет накладные расходы около 7.6MiB с huge_pages=off и около 1.3MiB с huge_pages=on включая Pss_Anon в VmPTE.

Даже если представить что есть некий "невидимый" оверхэд, и большой объем данных в буфере и т.д., я думаю мы вернемся к моему раннему утверждению что накладные расходы на соединение меньше чем 2MiB.

Дополнение от переводчика. В версии Postgres 14 появилось новое представление pg_backend_memory_contexts которое показывает подробную утилизацию памяти текущим процессом с точки зрения самого Postgres.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru