Мы проверяли производительность до и после увеличения количества траншей до 64 — прирост есть, но в нашем конкретном случае он был не слишком значительным.
Я бы рекомендовал попробовать сократить количество информации, которое записывается в WAL. Если есть возможность, установите wal_level в minimal и отключите full_page_writes (Опасно! Обязательно изучите риски в документации).
Нужно также проверить настройки checkpoint, чтобы он выполнялся реже, и с большим объемом данных (checkpoint_flush_after).
Если есть возможность, лучше перенести папку pg_wal на другой диск (не тот, где находится PGDATA), чтобы при массовой вставке не было конкуренции.
Также можно отключить fsync, synchronous_commit (Опасно! Обязательно прочитайте в документации о последствиях).
Если ничего не помогает и хочется попробовать увеличить количество траншей — это можно сделать очень просто, особенно на ванильной сборке PostgreSQL.
и пересоберите PostgreSQL с теми же параметрами, которые использовались в оригинале. Потом подменить бинари и можно тестировать. Я посмотрел в версии 13.8 - должно работать так же.
Соответственно, статья - странная о странном. Что вызывает недоумение - серьёзная компания, и подобный материал. Это что такое было?
Статьи должны быть разными для разной аудитории. Эта статья задумывалась как введение в профессию для начинающих специалистов, поэтому глубокий технический разбор здесь не предполагался.
Если вам интересны сложные кейсы, рекомендую посмотреть другие материалы или доклады на PgConf — где мы, нашим отделом, подробно разбираем реальные проблемы и их решения.
Немного прокомментирую по поводу WAL, т. к. это одна из последних наших задач и, как мне кажется, достаточно интересная.
Забыли?! Её не используют, по причине увеличения количества потерянных транзакций в случае сбоев.
Пожалуй, здесь действительно недостаточно контекста. Ну что вы хотите от интервью :)
Речь идёт о массовой вставке данных при миграции в PostgreSQL с другой СУБД. По факту, нам тут не очень-то и важно, потеряем ли мы какие-то транзакции или нет. Если что-то идёт не так при миграции, будь то segmentation fault или просто кто-то рубильник дёрнул, нам в 99% случаев придётся делать эту миграцию заново.
Ещё момент - в случае массовой вставки данных необходимо существенно увеличивать количество сохраняемых WAL-ов для того, чтобы увеличить интервал между чекпойнтами.
Безусловно, это первое узкое горлышко, с которым сталкиваешься, когда пытаешься залить огромную кучу данных. Мы это поправили ещё до миграции, но столкнулись уже с более нестандартными проблемами при большом количестве потоков COPY (300+).
Изначальная проблема звучит так: в процессе массовой миграции данных в pg_stat_activity наблюдалось доминирование wait_event: LWLock:WalInsert.
Увеличили wal_buffers в 10 раз — ситуация не изменилась, поэтому начинаем думать.
Приступаем к анализу!
По утилизации сервера видно, что мы ещё не исчерпали ресурсы системы, а как раз стопоримся на внутренних блокировках PostgreSQL.
Попробую коротко описать суть блокировки LWLock:WalInsert: Перед тем как отправить WAL-запись на диск, эта запись помещается в WAL-буфер в shared memory. Описать, как именно записи пишутся в буфер, лучше, чем Егор Рогов, я не смогу, поэтому — цитата из книги:https://edu.postgrespro.ru/postgresql_internals-17.pdf
Чтобы создать журнальную запись, процесс сначала резервирует место внутри страницы WAL, а затем заполняет его необходимыми данными. Резервирование строго упорядочено; процесс должен захватить спин-блокировку insert position, защищающую указатель вставки. Но заполнять уже зарезервированное место могут одновременно несколько процессов. Для этого процесс должен захватить любую из восьми легких блокировок, образующих транш WALInsert.
И вот, понимая это, первая мысль, которая приходит в голову: «Ну вот же, мы наконец достигли ситуации, когда 8-ми траншей не хватает и их нужно увеличить».
Но кардинально изменить ситуацию у нас не получалось.
Рассказывать, как мы пришли к решению, можно долго, поэтому подведу итоги: блокировки LWLock:WALInsert были вызваны недостаточной производительностью записи WAL из-за недостаточного размера буферов и частых сбросов на диск. Увеличив wal_buffers и wal_writer_flush_after до неприличных значений, мы добились ускорения на 30%. И проблема с блокировками внутри PostgreSQL больше не повторялась.
Считаем допустимым установить большие значения для этих параметров на время миграции. После миграции, конечно, нужно вернуть рекомендуемые значения.
Признаюсь, мне сложно остановиться — кажется, об этом можно написать отдельную статью. Если интересно, дайте знать — мы на низком старте!
Мы проверяли производительность до и после увеличения количества траншей до 64 — прирост есть, но в нашем конкретном случае он был не слишком значительным.
Я бы рекомендовал попробовать сократить количество информации, которое записывается в WAL. Если есть возможность, установите wal_level в minimal и отключите full_page_writes (Опасно! Обязательно изучите риски в документации).
Нужно также проверить настройки checkpoint, чтобы он выполнялся реже, и с большим объемом данных (checkpoint_flush_after).
Если есть возможность, лучше перенести папку pg_wal на другой диск (не тот, где находится PGDATA), чтобы при массовой вставке не было конкуренции.
Также можно отключить fsync, synchronous_commit (Опасно! Обязательно прочитайте в документации о последствиях).
Если ничего не помогает и хочется попробовать увеличить количество траншей — это можно сделать очень просто, особенно на ванильной сборке PostgreSQL.
Замените в исходниках https://github.com/postgres/postgres/blob/4bc493d14409857090928ea51c02a20aba8db364/src/backend/access/transam/xlog.c#L123:
на
и пересоберите PostgreSQL с теми же параметрами, которые использовались в оригинале. Потом подменить бинари и можно тестировать. Я посмотрел в версии 13.8 - должно работать так же.
Спасибо за обратную связь, учтём!
Статьи должны быть разными для разной аудитории. Эта статья задумывалась как введение в профессию для начинающих специалистов, поэтому глубокий технический разбор здесь не предполагался.
Если вам интересны сложные кейсы, рекомендую посмотреть другие материалы или доклады на PgConf — где мы, нашим отделом, подробно разбираем реальные проблемы и их решения.
Немного прокомментирую по поводу WAL, т. к. это одна из последних наших задач и, как мне кажется, достаточно интересная.
Пожалуй, здесь действительно недостаточно контекста. Ну что вы хотите от интервью :)
Речь идёт о массовой вставке данных при миграции в PostgreSQL с другой СУБД. По факту, нам тут не очень-то и важно, потеряем ли мы какие-то транзакции или нет. Если что-то идёт не так при миграции, будь то segmentation fault или просто кто-то рубильник дёрнул, нам в 99% случаев придётся делать эту миграцию заново.
Безусловно, это первое узкое горлышко, с которым сталкиваешься, когда пытаешься залить огромную кучу данных. Мы это поправили ещё до миграции, но столкнулись уже с более нестандартными проблемами при большом количестве потоков COPY (300+).
Изначальная проблема звучит так: в процессе массовой миграции данных в pg_stat_activity наблюдалось доминирование wait_event: LWLock:WalInsert.
Увеличили wal_buffers в 10 раз — ситуация не изменилась, поэтому начинаем думать.
Приступаем к анализу!
По утилизации сервера видно, что мы ещё не исчерпали ресурсы системы, а как раз стопоримся на внутренних блокировках PostgreSQL.
Попробую коротко описать суть блокировки LWLock:WalInsert: Перед тем как отправить WAL-запись на диск, эта запись помещается в WAL-буфер в shared memory.
Описать, как именно записи пишутся в буфер, лучше, чем Егор Рогов, я не смогу, поэтому — цитата из книги:https://edu.postgrespro.ru/postgresql_internals-17.pdf
И вот, понимая это, первая мысль, которая приходит в голову: «Ну вот же, мы наконец достигли ситуации, когда 8-ми траншей не хватает и их нужно увеличить».
Разработчики сделали патч, попутно улучшив алгоритм взятия этих блокировок: https://www.postgresql.org/message-id/flat/3b11fdc2-9793-403d-b3d4-67ff9a00d447%40postgrespro.ru
Мы радостно его забираем, пробуем — и ничего... На текущей нагрузке и на наших серверах выигрыш совсем не заметен.
Пока тестировали предыдущий патч, разработчик попутно обнаружил ещё одну возможность оптимизации с WALBufMappingLock: https://www.postgresql.org/message-id/flat/39b39e7a-41b4-4f34-b3f5-db735e74a723%40postgrespro.ru
Но кардинально изменить ситуацию у нас не получалось.
Рассказывать, как мы пришли к решению, можно долго, поэтому подведу итоги: блокировки LWLock:WALInsert были вызваны недостаточной производительностью записи WAL из-за недостаточного размера буферов и частых сбросов на диск. Увеличив wal_buffers и wal_writer_flush_after до неприличных значений, мы добились ускорения на 30%. И проблема с блокировками внутри PostgreSQL больше не повторялась.
Считаем допустимым установить большие значения для этих параметров на время миграции. После миграции, конечно, нужно вернуть рекомендуемые значения.
Признаюсь, мне сложно остановиться — кажется, об этом можно написать отдельную статью. Если интересно, дайте знать — мы на низком старте!