Logical Replication Slot WAL Bloat: Keď Subscribery Odídu Offline
Replication sloty sa lahko zabudnu a draho ignoruju. “pg_wal adresár má 500GB a rastie.” Príčina: logical replication subscriber sa odpojil pred 3 dňami a PostgreSQL drží všetky WAL súbory odvtedy čakajúc na jeho reconnect.
Prostredie: PostgreSQL 14+ s logical replikáciou, CDC pipelines (Debezium, atď.), viacerí subscriberi
Problém
Mizajúce Miesto na Disku
# Disk alert sa spustí
df -h /var/lib/postgresql
# /dev/sda1 1000G 950G 50G 95% /var/lib/postgresql
# Kde je miesto?
du -sh /var/lib/postgresql/14/main/*
# 450G pg_wal <- WAL súbory žerú disk!
# Koľko WAL súborov?
ls -la /var/lib/postgresql/14/main/pg_wal/*.gz | wc -l
# 28,521 súborov
# Skontroluj najstarší WAL súbor
ls -lt /var/lib/postgresql/14/main/pg_wal/ | tail -5
# -rw------- 1 postgres postgres 16777216 Dec 26 10:00 0000000100000ABC00000001
# To je 3 dni staré - prečo je stále tu?
Nájdenie Vinníka
-- Skontroluj replication sloty
SELECT
slot_name,
slot_type,
active,
restart_lsn,
confirmed_flush_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal,
age(now(), COALESCE(
(SELECT backend_start FROM pg_stat_activity
WHERE pid = active_pid), '2000-01-01'
)) AS last_active
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC;
-- Výstup:
-- slot_name | active | retained_wal | last_active
-- debezium_cdc_slot | f | 450 GB | 3 days 02:15:33
-- analytics_sub | t | 15 MB | 00:00:05
-- audit_log_slot | t | 8 MB | 00:00:12
-- debezium_cdc_slot je neaktívny a drží 450GB WAL!
Príčina
Ako Logical Replication Sloty Fungujú
Normálna prevádzka:
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL Primary │
│ │
│ WAL Generácia: [001][002][003][004][005][006]... │
│ │
│ Slot A (aktívny): confirmed_lsn = 005 │
│ Slot B (aktívny): confirmed_lsn = 004 │
│ │
│ Môže zmazať: [001][002][003] (pred všetkými slotmi) │
│ Musí držať: [004][005][006]... (potrebný nejakým slotom) │
└─────────────────────────────────────────────────────────────┘
Keď subscriber odíde offline:
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL Primary │
│ │
│ WAL Generácia: [001][002]...[1000][1001][1002]... │
│ │
│ Slot A (OFFLINE): confirmed_lsn = 002 (spred 3 dní!) │
│ Slot B (aktívny): confirmed_lsn = 1002 │
│ │
│ Môže zmazať: [001] (pred VŠETKÝMI slotmi vrátane offline) │
│ Musí držať: [002]...[1002] (Slot A sa možno pripojí) │
│ │
│ 1000 × 16MB = 16GB minimum (často oveľa viac) │
└─────────────────────────────────────────────────────────────┘
Prečo PostgreSQL Drží WAL
-- Logical sloty sú PERZISTENTNÉ
-- Prežijú reštarty a čakajú neobmedzene na consumera
-- Slot kontrakt:
-- "Sľubujem mať všetky zmeny od restart_lsn dostupné
-- aby subscriber mohol pokračovať odkiaľ skončil"
-- Toto je správne správanie, ale neobmedzené:
-- - Žiadny automatický cleanup neaktívnych slotov
-- - Žiadny timeout pre offline consumerov
-- - Žiadny size limit na retained WAL
Diagnostika
Monitoruj Slot Lag
-- Vytvor monitoring query
CREATE OR REPLACE VIEW replication_slot_lag AS
SELECT
slot_name,
slot_type,
active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS wal_retained,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) / 1024 / 1024 AS mb_retained,
CASE
WHEN active THEN
(SELECT now() - backend_start FROM pg_stat_activity
WHERE pid = active_pid)
ELSE
'inactive'::interval
END AS connection_age
FROM pg_replication_slots;
-- Kontroluj pravidelne
SELECT * FROM replication_slot_lag WHERE mb_retained > 1000;
Skontroluj WAL Retention Nastavenia
-- Tieto nastavenia ovplyvňujú WAL retention ale NELIMITUJú slot retention
SHOW wal_keep_size; -- Minimum WAL na držanie (nie max!)
SHOW max_slot_wal_keep_size; -- PostgreSQL 13+: Max WAL per slot!
-- max_slot_wal_keep_size je kľúčové nastavenie
-- Default: -1 (neobmedzené - nebezpečné!)
-- Nastav limit: '100GB'
Riešenie
Možnosť 1: Dropni Neaktívny Slot (Ak Consumer Je Preč)
-- NEBEZPEČENSTVO: Toto stratí všetky zmeny od kedy slot odišiel offline!
-- Rob len ak consumer je naozaj preč alebo urobí full-resync
-- Skontroluj čo dropuješ
SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn))
FROM pg_replication_slots WHERE slot_name = 'debezium_cdc_slot';
-- Dropni slot
SELECT pg_drop_replication_slot('debezium_cdc_slot');
-- WAL súbory sa vyčistia pri ďalšom checkpointe
CHECKPOINT;
Možnosť 2: Nastav max_slot_wal_keep_size (Prevencia)
-- PostgreSQL 13+: Limituj WAL retained per slot
ALTER SYSTEM SET max_slot_wal_keep_size = '100GB';
SELECT pg_reload_conf();
-- Ak slot prekročí toto, stane sa "invalid"
-- Subscriber musí urobiť full resync, ale disk je chránený
-- Skontroluj invalidované sloty
SELECT slot_name, wal_status FROM pg_replication_slots;
-- wal_status = 'lost' znamená slot je invalid (potrebuje resync)
Možnosť 3: Proaktívny Slot Management
-- Vytvor funkciu na drop stale slotov
CREATE OR REPLACE FUNCTION cleanup_stale_slots(max_age interval, max_wal_gb int)
RETURNS TABLE (slot_name text, action text) AS $$
DECLARE
slot RECORD;
BEGIN
FOR slot IN
SELECT
s.slot_name,
s.active,
pg_wal_lsn_diff(pg_current_wal_lsn(), s.restart_lsn) / 1024 / 1024 / 1024 AS gb_retained
FROM pg_replication_slots s
WHERE s.slot_type = 'logical'
AND s.active = false
AND pg_wal_lsn_diff(pg_current_wal_lsn(), s.restart_lsn) > max_wal_gb * 1024 * 1024 * 1024
LOOP
PERFORM pg_drop_replication_slot(slot.slot_name);
RETURN QUERY SELECT slot.slot_name, 'dropped'::text;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Spúšťaj periodicky (napr. cez pg_cron)
SELECT * FROM cleanup_stale_slots('1 day', 50);
Checklist
## Logical Replication Slot WAL Bloat
### Symptómy
- [ ] pg_wal adresár neobmedzene rastie
- [ ] Disk space alerty na PostgreSQL serveri
- [ ] WAL súbory staršie než očakávaná retencia
- [ ] Neaktívne sloty v pg_replication_slots
### Diagnostika
- [ ] Skontroluj pg_replication_slots pre neaktívne sloty
- [ ] Identifikuj retained WAL size per slot
- [ ] Nájdi vlastníka slotu (aplikácia/subscriber)
- [ ] Skontroluj max_slot_wal_keep_size nastavenie
### Riešenia
- [ ] Dropni skutočne opustené sloty
- [ ] Nastav max_slot_wal_keep_size pre ochranu
- [ ] Reconnectni/reštartuj offline subscribera
- [ ] Implementuj proaktívny slot cleanup
### Prevencia
- [ ] Monitoruj slot lag metriky
- [ ] Alertuj na neaktívne sloty
- [ ] Nastav max_slot_wal_keep_size
- [ ] Dokumentuj vlastníkov slotov a recovery procedúry
Záver
Lekcia: logical replication sloty sú sľuby ktoré PostgreSQL berie vážne. Zabudnutý slot bude držať WAL navždy. Nastav max_slot_wal_keep_size a monitoruj zdravie slotov aby si sa vyhol disk-full núdzovým situáciám.
Kľúčové body:
- Neaktívne sloty držia WAL neobmedzene by design
- max_slot_wal_keep_size je tvoja záchranná sieť (PostgreSQL 13+)
- Monitoruj a alertuj na slot lag predtým než disk sa naplní
- Dokumentuj vlastníctvo slotov aby si vedel čo sa dá dropnúť
Súvisiace články
- pg_waldump WAL Forensics - Analýza WAL obsahu
- PostgreSQL HOT Updates - Pochopenie PostgreSQL internals
Súvisiace články
pg_waldump WAL Forenzika: Rekonštrukcia Čo Sa Stalo s Tvojimi Dátami
Niečo zmazalo riadky z produkcie ale nikto nepriznáva že spustil DELETE. Použi pg_waldump na analýzu WAL súborov a rekonštruuj presne čo sa stalo a kedy.
PostgreSQL Replication Slot Bloat: Ako Jeden Neaktívny Slot Naplnil 500GB Disk
Disk je na 95%, WAL adresár má 400GB. Ukážem ako replication slots bránia WAL cleanup a playbook pre prevenciu a recovery.
PostgreSQL logical replication lag: veľké transakcie a reorder buffer spilly
Jedna obrovská transakcia vie pripnúť logical replication na hodiny. Runbook na rýchlu identifikáciu, bezpečné tunenie decodingu a kontrakt na bounded transakcie.
PostgreSQL Read Replica Konflikty: Prečo sa vaše dotazy rušia
Dotazy na read replikách zlyhávajú s 'canceling statement due to conflict with recovery'. Riešenie závisí od toho, ktorý z 5 typov konfliktov máte - tu je návod ako diagnostikovať a vyriešiť každý z nich.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.