PostgreSQL Transaction ID Wraparound Emergency: Freeze Plan
Steps to save a database from going read-only when XID age reaches a critical level. Clears blockers and runs VACUUM FREEZE in the right order.
Operational Safety & Risk Notice
This runbook contains operational intervention steps; several are write-impacting (KILL, terminate, DROP, RESIZE). Verify in a staging environment first, and apply sequentially in production with verification.
1. Symptom & Signals
- M5: `age(datfrozenxid)` 1,5 milyarın üzerinde ve artıyor.
- Log: `WARNING: database "x" must be vacuumed within N transactions`.
- Son aşama: `ERROR: database is not accepting commands that assign new transaction IDs to avoid wraparound data loss`.
2. Business & Technical Impact
Sınıra yaklaşıldığında PostgreSQL **yazmaları reddeder** (veritabanı fiilen salt okunur olur). Kurtarma, veritabanı kapalıyken tek kullanıcı modunda VACUUM gerektirebilir ve uzun kesinti yaratır.
3. Diagnosis & Root-Cause Analysis
SELECT datname, age(datfrozenxid) AS xid_age FROM pg_database ORDER BY 2 DESC;
-- Sorunlu veritabanına bağlanıp:
SELECT c.oid::regclass AS table_name, age(c.relfrozenxid) AS xid_age,
pg_size_pretty(pg_total_relation_size(c.oid)) AS size
FROM pg_class c WHERE c.relkind IN ('r','m','t')
ORDER BY age(c.relfrozenxid) DESC LIMIT 15;-- Uzun transaction'lar
SELECT pid, usename, state, now()-xact_start AS age, backend_xmin
FROM pg_stat_activity WHERE backend_xmin IS NOT NULL ORDER BY age(backend_xmin) DESC LIMIT 5;
-- Unutulmuş prepared transaction'lar
SELECT gid, prepared, owner, database FROM pg_prepared_xacts ORDER BY prepared;
-- Replikasyon slotları (S13)
SELECT slot_name, active, xmin, catalog_xmin FROM pg_replication_slots;
-- Standby'lardan gelen feedback
SELECT pid, application_name, backend_xmin FROM pg_stat_replication;4. Remediation & Action Plan
- Uzun/idle transaction: `pg_terminate_backend(pid)`.
- Unutulmuş prepared transaction: `COMMIT PREPARED 'gid';` veya `ROLLBACK PREPARED 'gid';` (sahibine danışın).
- Terk edilmiş replikasyon slotu: `SELECT pg_drop_replication_slot('slot_adi');`.
VACUUM (FREEZE, VERBOSE) kucuk_eski_tablo;
-- PG 12+, acil durumda indeks temizliğini atlayıp hızlandırmak için:
VACUUM (FREEZE, INDEX_CLEANUP OFF, VERBOSE) buyuk_tablo;ALTER SYSTEM SET vacuum_cost_delay = 0;
SELECT pg_reload_conf();postgres --single -D /var/lib/postgresql/data <veritabani_adi>
backend> VACUUM FREEZE;Bu mod kesinti gerektirir; yedeğiniz olduğundan emin olun.
5. **Kalıcı çözüm:** Büyük ve hızlı değişen tablolar için tablo bazında `autovacuum_freeze_max_age` ve `autovacuum_vacuum_cost_limit` ayarlayın. PG 14+ `vacuum_failsafe_age` ile failsafe modu devreye girer. M5 için %50'de uyarı kurun.
5. Verification & Health Checks
- `age(datfrozenxid)` 500 milyonun altına indi (veya düşme eğiliminde ve engelleyici yok).
- Yazmalar normal, log'da wraparound uyarısı yok.
- Autovacuum'un en büyük tablolarda yeniden çalıştığı `pg_stat_user_tables.last_autovacuum` ile görülüyor.
6. Rollback & Contingency Plan
- `VACUUM FREEZE` geri alınmaz ama zararsızdır (yalnızca kaynak tüketir).
- `vacuum_cost_delay` ayarını işiniz bitince eski değerine çevirin: `ALTER SYSTEM RESET vacuum_cost_delay;`.
- Prepared transaction ve slot silme geri alınamaz.