<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Снёс 95% легаси миграций pglogical: репликация PostgreSQL без downtime убила три cron-джоба]]></title><description><![CDATA[<p dir="auto">Представь: база на PostgreSQL с кучей легаси-миграций, которые висят как мертвый груз. Команда решила мигрировать на новую версию без простоя - pglogical в помощь. Репликация логическая, данные текут незаметно, а кастомные cron-джобы для синхронизации просто сдохли.</p>
<p dir="auto">Зачем это знать? Потому что 95% ручных скриптов на миграции - это типичная <strong>архитектурная грабля</strong>. pglogical берёт на себя репликацию таблиц, и старые костыли уходят в /dev/null. Проблемы с DDL, WAL и лагами решаются нативно, без лишнего кода.</p>
<h2>Что под капотом у pglogical и почему он рвёт легаси</h2>
<p dir="auto">pglogical - это расширение для логической репликации в PostgreSQL. Не физические байты WAL копирует, а SQL-команды: INSERT, UPDATE, DELETE. Мастер шлёт изменения на реплику по подписке, без привязки к диску или архитектуре. Идеально для миграции между версиями - от 9.4 до свежей 18-й.</p>
<p dir="auto">Под капотом: декодирование WAL в логические изменения. Нужен wal_level = logical, плюс настройка слотов репликации. Легаси-миграции обычно ковыряют дампы или триггеры - медленно, с downtime. pglogical стримит в реал-тайм, но DDL не всегда реплицируется - вот где новички тонут. Пример: добавляешь колонку на мастере, реплика не видит, cron пытается подправить - и привет, рассинхрон.</p>
<ul>
<li><strong>Слот репликации</strong>: <code>SELECT * FROM pg_replication_slots;</code> - проверяй, не раздулся ли. Если лаг &gt; 1GB, мастер задохнётся.</li>
<li><strong>Подписки</strong>: <code>pglogical.replication_set_add_all_tables</code> - реплицируй выборочно, не всё сразу.</li>
<li><em>Нюанс</em>: pglogical не любит TOASTed поля - сжимай их заранее, иначе трафик взлетит.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Параметр</th>
<th>Легаси cron</th>
<th>pglogical</th>
</tr>
</thead>
<tbody>
<tr>
<td>Downtime</td>
<td>4-8 часов</td>
<td>&lt;5 мин</td>
</tr>
<tr>
<td>Load на мастер</td>
<td>Высокий (full scan)</td>
<td>Низкий (WAL stream)</td>
</tr>
<tr>
<td>DDL support</td>
<td>Ручной скрипт</td>
<td>Ограничен, sync вручную</td>
</tr>
<tr>
<td>Масштаб</td>
<td>До 100GB</td>
<td>Терабайты OK</td>
</tr>
</tbody>
</table>
<h2>Три cron-джоба, которые pglogical угробил - разбор полётов</h2>
<p dir="auto">Первый джоб синхронил изменения по триггерам. Каждый UPDATE на мастере фейрил на реплике, cron ковырял diff по primary key. pglogical взял репликацию на себя - джоб в корзину. Но <em>внимание</em>: если таблица без PK, репликация сломается - pkless tables не поддерживаются.</p>
<p dir="auto">Второй - бэкап/восстановление по расписанию. Легаси-скрипт дампил delta, заливал на slave. С pglogical дельта стримится continuously, cron просто проверял лаг: <code>pg_wal_lsn_diff(sent_lsn, replay_lsn)</code>. Если &gt;0 - алерт, но сам джоб мёртв. Пример из продакшена: 500GB база мигрировали за ночь, лаг не превысил 10MB.</p>
<p dir="auto">Третий - ротация логов и vacuum. Cron чистил orphaned записи, подгонял под реплику. pglogical с origin-фильтрами и subtxn handling это покрывает нативно. Остался только мониторинг: <code>SELECT * FROM pg_stat_replication</code>. Минус: full_page_writes off временно, ionice/renice для приоритетов.</p>
<ol>
<li>Триггерный sync: убирай все триггеры перед подпиской - <code>ALTER TABLE DROP TRIGGER</code>.</li>
<li>Delta дампы: замени на <code>pglogical.show_subscription_status</code>.</li>
<li>Vacuum cron: полагайся на autovacuum реплики, мониторь pg_stat_user_tables.</li>
</ol>
<h2>Грабли миграции: от WAL до переключения трафика</h2>
<p dir="auto">Настройка pglogical начинается с <code>CREATE EXTENSION pglogical</code>. На мастере - node creation, на реплике - subscription. Ключ: реплицируй schema сначала вручную, DDL не всегда прокатывает. Пример: ALTER TABLE на мастере - реплика в стагнации, ручной sync через <code>pglogical.sync()</code>.</p>
<p dir="auto">Лаги? Увеличивай wal_keep_segments, отключай fsync temporarily. Переключение: stop writes на мастере, sync реплику, flip DNS/app config. Время - минуты, если стек простой. Сложный стек (proxy, connection pool) - тестируй blue-green заранее.</p>
<ul>
<li><strong>wal_level=logical</strong>: обязательный, иначе слоты не стартуют.</li>
<li><strong>max_replication_slots=10</strong>: не жадничай, слоты жрут RAM.</li>
<li><em>Грабль</em>: pglogical &lt; PG12 имеет баги с subtransactions - апгрейдь до 3.x.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Шаг миграции</th>
<th>Время</th>
<th>Риски</th>
</tr>
</thead>
<tbody>
<tr>
<td>Setup nodes</td>
<td>5 мин</td>
<td>Extension conflict</td>
</tr>
<tr>
<td>Initial sync</td>
<td>1-4 ч</td>
<td>Network lag</td>
</tr>
<tr>
<td>App switch</td>
<td>2 мин</td>
<td>Cache invalidation</td>
</tr>
<tr>
<td>Cleanup</td>
<td>10 мин</td>
<td>Slot leaks</td>
</tr>
</tbody>
</table>
<h2>Репликация убила джобы - что на выходе</h2>
<p dir="auto">Итог: 95% легаси-миграций в /dev/null, три cron-а мертвы, база мигрирована zero-downtime. Осталось чистить слоты репликации и мониторить byte_lag - больше ничего не мешает.</p>
<p dir="auto">Под капотом pglogical раскрывает нативную мощь PostgreSQL. Дальше думай о multi-master или шardinгe - но это уже без костылей.</p>
]]></description><link>https://forum.exlends.com/topic/2182/snyos-95-legasi-migracij-pglogical-replikaciya-postgresql-bez-downtime-ubila-tri-cron-dzhoba</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 14:03:11 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/2182.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 24 Apr 2026 10:46:09 GMT</pubDate><ttl>60</ttl></channel></rss>