惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
C
Check Point Blog
博客园 - Franky
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
Microsoft Security Blog
Microsoft Security Blog
V2EX - 技术
V2EX - 技术
AI
AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Jina AI
Jina AI
S
Security @ Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Hacker News: Front Page
H
Hackread – Cybersecurity News, Data Breaches, AI and More
O
OpenAI News
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
爱范儿
爱范儿
H
Heimdal Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
Google Developers Blog
G
GRAHAM CLULEY
V
V2EX
The Register - Security
The Register - Security
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
Schneier on Security
Schneier on Security
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
Help Net Security
Help Net Security
大猫的无限游戏
大猫的无限游戏
C
CERT Recently Published Vulnerability Notes
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
S
Secure Thoughts
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
NISL@THU
NISL@THU
K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
T
Threatpost
Recent Commits to openclaw:main
Recent Commits to openclaw:main
宝玉的分享
宝玉的分享
Security Latest
Security Latest
T
The Exploit Database - CXSecurity.com
博客园_首页
A
Arctic Wolf

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Конфликты потоковой репликации в PostgreSQL
OlegIct · 2026-04-25 · via Все публикации подряд на Хабре

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

В статье описываются конфликты репликации и как с ними бороться.

Что такое конфликт репликации?

Конфликт репликации возникает, когда процесс восстановления (startup) не может применить изменения из WAL, полученных с мастера, так как эти изменения препятствуют продолжению выполнения запросов, уже выполняющихся на реплике. Такие конфликты не могут препятствовать выполнению запросов на мастере, но возникают на реплике, из-за того, что мастер не знает о том, какие запросы выполняются на реплике.

Виды конфликтов:

1) Конфликты моментальных снимков

Это наиболее часто возникающий конфликт.

Могут возникать, если VACUUM (любой процесс, выполняющий вакуумирование: автоматическое или ручное) обрабатывает таблицу и вычищает мёртвые версии строк (dead tuples). Удаление строки логируется, передаётся через WAL и применяется на реплике. Запрос на реплике мог быть запущен раньше, чем VACUUM на мастере (у запроса  старый моментальный снимок), поэтому запрос может захотеть видеть версии строк, которые должны удалиться при применении WAL.

2) Конфликты блокировок

Запросы на реплике блокируют таблицы в режиме ACCESS SHARE. Поэтому любая ACCESS EXCLUSIVE блокировка на мастере (блокировка уровня ACCESS EXCLUSIVE конфликтует с ACCESS SHARE) должна быть воспроизведена на реплике, чтобы предотвратить действия с таблицей, несовместимые с запросом. PostgreSQL воспроизводит такую ​​блокировку для команд, конфликтующих с SELECT, например DROP TABLE, TRUNCATE и большинства вариаций команды ALTER TABLE. Если реплика должна воспроизвести ​​блокировку ACCESS EXCLUSIVE на таблице, с которой работает запрос, возникает конфликт блокировок.

3) Конфликты закреплений блока в буфере (BufferPin)

Один из способов уменьшить необходимость в VACUUM - это быстрая очистка блоков (HOT cleanup). Запрос на мастере, который работает с блоком, может получить эксклюзивную блокировку блока и очистить его от мёртвых версий строк. PostgreSQL удерживает блокировки блоков для очистки в течение короткого времени, поэтому конфликта с другими процессами на мастере нет. Есть и другие причины эксклюзивных блокировок блоков, но эта самая распространённая.

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

Когда на реплике нужно воспроизвести такую ​​эксклюзивную блокировку блока, а какой-нибудь запрос на реплике уже работает с блоком ("закрепил блок"), то возникает конфликт. Блоки могут быть закреплены на более долгое время, например, при последовательном сканировании внешней таблицы в соединении способом Nested Loop.

HOT cleanup может привести и к конфликтам моментальных снимков.

4) Редкие виды конфликтов

Встречаются редко и, обычно, не создают проблем:

  • Взаимоблокировка: запрос на реплике вызывает взаимоблокировку во время использования закреплённого запросом буфера, который нужно изменить при проигрывании WAL. Такой запрос немедленно прерывается.

  • Конфликты репликации табличных пространств: если на реплике  табличное пространство указано в параметре конфигурации temp_tablespaces, то запрос на реплике, при нехватке памяти, будет создавать в этом табличном пространстве файлы для хранения временных данных. Если на мастере выполнить команду DROP TABLESPACE, то возникает конфликт на реплике. Запрос, использующий временные файлы немедленно прервётся.

  • Конфликты репликации базы данных: репликация команды DROP DATABASE вызывает конфликт, если на реплике есть активные сессии с удаляемой базой данных. В этом случае, разрываются все сессии с удаляемой базой данных.

Мониторинг конфликтов репликации

В представлении pg_stat_database_conflicts содержится подробная информация обо всех конфликтах репликации, которые возникали с момента последнего сброса статистики. Просматривать это представление нужно на реплике, а не на мастере, так как именно там возникают конфликты.

В этом представлении отображаются не все конфликты репликации, а только те, которые привели к отмене запроса на реплике.

Как реплика разрешает конфликты?

Параметр max_standby_streaming_delay определяет, что происходит, когда воспроизведение WAL-файлов сталкивается с конфликтом репликации (существует аналогичный параметр max_standby_archive_delay, выполняющий ту же функцию для восстановления из архива журналов). PostgreSQL приостанавливает применение WAL до устранения конфликта или на max_standby_streaming_delay. Если запрос не завершился до истечения max_standby_streaming_delay, то PostgreSQL отменяет запрос с сообщением об ошибке типа:

ERROR: canceling statement due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.

В DETAIL указано, что запрос прерван из-за конфликта моментальных снимков.

У параметра max_standby_streaming_delay по умолчанию установлено значение 30 секунд, поэтому запросы имеют 30 секунд для завершения, прежде чем они будут отменены, с момента возникновения конфликта. Это промежуточное значение между значениями 0 (PostgreSQL отменяет запросы немедленно, как только возник конфликт) и -1 (PostgreSQL не отменяет запросы, задержка применения WAL не ограничивается).

Параметр max_standby_archive_delay, по умолчанию, 30 секунд. Применяется при восстановлении из архива журналов. Определяет не максимальнкю длительность запроса на реплике, а максимальное время, за которое должны быть применены изменения из одного WAL-файла (размер 16Мб). Если один запрос привёл к задержке в применении журнальных записей из WAL-файла, то прервутся все запросы, которые мешают применять журнальные записи из этого же файла, независимо от того, сколько времени они работали.

Чтобы понять, как настроить PostgreSQL для разрешения конфликтов, нужно знать для чего используется репликация.

Для чего используются реплики

Высокая доступность

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

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

Если реплика отстаёт в применении WAL, это не влияет на потери данных при переключении, так как передача WAL не зависит от скорости применения, WAL записываются в директорию pg_wal по мере их получения. Однако, реплике потребуется больше времени, чтобы применить полученные WAL, поэтому время на переключение увеличится.

Перенос на реплику долгих запросов

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

Еще один пример разгрузки мастера - перенос резервирования на реплику. Резервирование реплики не создает нагрузки на мастер.

Главная задача в данном случае - обеспечить бесперебойное выполнение запросов (или создания бэкапов).

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

Горизонтальное масштабирование

Реплики можно использовать для распределения нагрузки между несколькими машинами. На практике это ограничено несколькими факторами:

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

  • Приложение должно уметь направлять запросы по одному адресу (реплик), а вносить изменения по другому адресу (мастера).

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

Ещё одна сложность заключается в отсутствии подходящей настройки для параметра max_standby_streaming_delay: низкое значение приведёт к сбоям запросов на реплике, а высокое значение приведёт к тому, что запросы на реплике  будут выдавать устаревшие данные.

Как справляться с противоречивыми требованиями

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

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

Как избегать конфликтов

Запретить режим горячей реплики (hot_standby), чтобы избежать конфликтов

Конфликтов не может быть, если на реплике нет запросов. Поэтому, если установить hot_standby = off на реплике, о конфликтах можно не беспокоиться.

Хотя это просто и эффективно, это имеет смысл только, если реплика используется исключительно для обеспечения высокой доступности.

Предотвращение конфликтов блокировок

Для предотвращения конфликтов можно не использовать команды, которые требуют блокировок уровня ACCESS EXCLUSIVE. Наиболее часто используемые команды, которые требуют этой блокировки:

  • DROP TABLE

  • TRUNCATE

  • LOCK

  • DROP INDEX

  • DROP TRIGGER

  • ALTER TABLE

Однако существует один тип блокировок ACCESS EXCLUSIVE: блокировки, возникающие при VACUUM (truncate). Когда VACUUM завершил обработку таблицы и блоки в конце таблицы стали пустыми, система пытается получить на небольшое время блокировку ACCESS EXCLUSIVE. Если это удаётся, VACUUM убирает пустые блоки из таблицы и снимает блокировку. Хотя такие блокировки не влияют на работу мастера, они могут вызывать конфликты на резервном сервере.

Существует два способа избежать VACUUM (truncate):

  • Начиная с версии PostgreSQL 12, вы можете отключить эту фазу для отдельных таблиц с помощью параметра на уровне таблицы: ALTER TABLE имя SET (vacuum_truncate = off);

  • До 17 версии PostgreSQL можно установить значение параметра конфигурации old_snapshot_threshold отличное от -1. Это отключает VACUUM (truncate), что является документированным побочным эффектом параметра.

    Начиная с версии PostgreSQL 18 можно установить значение параметра конфигурации vacuum_truncate = off.

Предотвращение конфликтов моментальных снимков

Способ уменьшить подобные конфликты - предотвратить удаление на мастере версии строк, которые могут оставаться видимыми запросам на реплике. В этом помогают два параметра:

  • Установить hot_standby_feedback = on на реплике. Тогда сообщения обратной связи от резервного сервера к основному серверу будут содержать снимок xmin самой старой активной транзакции на резервном сервере, и мастер не будет удалять кортежи, которые эта транзакция все еще может видеть.
    Это устранит большинство конфликтов репликации, но длительно выполняющиеся запросы на реплике могут привести к раздуванию таблиц на основном сервере, поэтому этот параметр не включен по умолчанию. Тщательно оцените риски.

  • Установите vacuum_defer_cleanup_age на мастере в значение больше 0. В этом случае VACUUM не будет удалять версии строк, которые моложе vacuum_defer_cleanup_age транзакций. Но это менее избирательно, чем hot_standby_feedback и может привести к раздуванию таблиц.

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

Предотвращение конфликтов закреплений блоков в буферах

Нет надежного способа избежать этих конфликтов. Возможно, можно уменьшить количество HOT cleanup, но это негативно скажется на производительности мастера.

Заключение

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

Если вы не можете позволить себе иметь несколько реплик или хотите использовать реплики для горизонтального масштабирования, вам придется настроить параметр конфигурации hot_standby_feedback, чтобы свести к минимуму число отмененных запросов. Чтобы избежать чрезмерного раздувания таблиц и отставания реплик, установите на мастере параметр max_standby_streaming_delay. Также, отключите vacuum_truncate.