PostgreSQL Replikasyon Slotları: Diski Dolduran Unutulmuş Slot, WAL Sınırı ve Temizliği Durduran xmin
Tüketicisi kaybolan bir replikasyon slotu birincilin diskini WAL ile doldurur ve autovacuum'u durdurur. Slot, wal_keep_size ve WAL arşivi arasında nasıl seçim yapılır, max_slot_wal_keep_size nasıl boyutlandırılır, pg_replication_slots ile neye alarm kurulur ve CDC ile yük devretmede hangi tuzaklar bekler.
Replikasyon slotu, PostgreSQL'in bir tüketiciye verdiği sözdür: "Sen okuyana kadar bu WAL kayıtlarını silmeyeceğim." Söz iyi niyetlidir ve replikanın ya da değişiklik yakalama (CDC) aracının kısa bir kopuştan sonra kaldığı yerden devam etmesini sağlar. Sorun, sözün tüketici ortadan kaybolsa da geçerli kalmasıdır. Kapatılan bir replika, silinen bir CDC bağlayıcısı ya da bir kerelik denemeden kalan bir slot, birincil sunucunun diskinde WAL biriktirmeye devam eder. Disk dolduğunda yazmalar durur ve kesinti çoğu zaman tamamen ilgisiz görünen bir uyarıyla başlar.
Slot ne tutar, ne zaman tutar
Her slotun bir restart_lsn değeri vardır. Sunucu bu konumdan sonraki WAL dosyalarını silemez. Tüketici bağlı ve okuyorsa bu konum ilerler, tutulan WAL küçük kalır. Tüketici bağlı değilse konum donar ve o andan itibaren üretilen bütün WAL diskte kalır. Yoğun yazılan bir veritabanında bu saatte onlarca gigabayt olabilir.
Slotlar yalnızca WAL tutmaz, temizliği de durdurabilir. İki durum öne çıkar:
- Mantıksal slotlar
catalog_xmintutar. Sistem kataloglarındaki ölü satırlar temizlenemez. Şema değişikliği ya da geçici tablo kullanımı yoğunsa katalog tabloları şişer. - Fiziksel slot ve
hot_standby_feedback = onbirleşince replika kendi en eski sorgusununxmindeğerini birincile bildirir ve bu değer slotta saklanır. Replika bağlantıyı kopardığında bile slot son bildirilen değeri tutar. Sonuç, birincildeki bütün tablolarda autovacuum'un ölü satır temizleyememesidir.
Yani unutulmuş bir slot iki ayrı yoldan zarar verir: disk dolar ve tablolar şişer. İkincisi daha sinsidir, çünkü belirtisi "sorgular yavaşladı" olarak gelir.
Slot mu, wal_keep_size mı, arşiv mi
Bir replikanın geride kaldığında yetişebilmesi için üç yol var ve aralarındaki fark, hangi riski üstlendiğinizdir.
wal_keep_size sabit miktarda WAL'ı her zaman tutar. Diski asla beklenmedik biçimde doldurmaz. Karşılığında, replika bu miktardan fazla geride kalırsa yetişemez ve yeniden kurulması gerekir.
Replikasyon slotu tam tersini seçer: tüketici ne kadar geride kalırsa kalsın veri kaybolmaz, ama disk sınırsız büyüyebilir.
WAL arşivi (archive_command ya da bir yedekleme aracı ve replikada restore_command) WAL'ı birincilin diskinden alıp nesne deposuna taşır. Replika akıştan düşerse arşivden okuyarak yetişir. Birincil disk riski ortadan kalkar, depolama maliyeti ve arşivin kendisini izleme yükü gelir.
Fiziksel replikalar için önerim şu: zaten zamanda geri dönüş için WAL arşiviniz varsa slot kullanın ama mutlaka max_slot_wal_keep_size ile sınırlayın; arşiv, sınırı aşan replikanın kurtarma yolu olur. Arşiviniz yoksa önce onu kurun. Sınırsız slotu üretim birincilinde bırakmak, bir replikanın sağlığını birincilin sağlığından önemli saymaktır ve bu neredeyse hiçbir zaman doğru öncelik değildir.
Mantıksal replikasyon ve CDC için seçeneğiniz yok: mantıksal kod çözme slot olmadan çalışmaz. Burada iş izlemeye ve sınırlamaya kalır.
Sınır koymak
PostgreSQL 13 ile gelen max_slot_wal_keep_size, bir slotun tutabileceği WAL miktarına üst sınır koyar. Varsayılanı -1, yani sınırsızdır.
# postgresql.conf
max_slot_wal_keep_size = 50GB
Sınır aşıldığında slot geçersiz kılınır ve tüketicisi artık o slottan devam edemez. Fiziksel replika arşivden yetişebiliyorsa sorun yoktur; yoksa yeniden kurulur. Mantıksal tüketicide bu, ilk anlık görüntünün yeniden alınması demektir. Bu acı verir ama birincilin durmasından iyidir. Değeri seçerken WAL dizininin bulunduğu diskin boş alanından ve tüketicinin makul en uzun kesintisinde ne kadar WAL üretildiğinden yola çıkın.
PostgreSQL 18, idle_replication_slot_timeout ayarını ekledi: belirli bir süre kullanılmayan slotlar geçersiz kılınır. Varsayılanı kapalıdır. Boyut sınırını tamamlar, çünkü az yazılan bir veritabanında terk edilmiş bir slot boyut sınırına aylarca ulaşmayabilir ama xmin tutarak temizliği bütün o süre boyunca durdurur.
İzlemek
pg_replication_slots görünümü ihtiyacınız olan her şeyi verir. Birincilde çalıştırın:
SELECT slot_name,
slot_type,
active,
wal_status,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS tutulan_wal,
pg_size_pretty(safe_wal_size) AS sinira_kalan,
xmin,
catalog_xmin
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;
wal_status sütununun değerleri reserved, extended, unreserved ve lost olabilir. unreserved, slotun bir sonraki kontrol noktasında kaybolabileceğini, lost ise artık kullanılamadığını söyler. safe_wal_size sınıra ne kadar kaldığını gösterir; max_slot_wal_keep_size sınırsızsa boş döner.
Alarm için iki kural yeter:
- Bir slot belirli bir süreden uzun
active = falsedurumdaysa uyarın. Süreyi tüketicinin bilinen bakım pencerelerinden biraz uzun tutun. PostgreSQL 17 ve sonrasındainactive_sincesütunu bunu doğrudan sorgulanabilir kılar. - Tutulan WAL, WAL diskinin boş alanının belirli bir oranını geçtiğinde uyarın. Sabit gigabayt eşiği yerine orana bakmak, disk büyütüldüğünde alarmın anlamsızlaşmasını önler.
Temizliği engelleyen slotları da ayrıca görün. xmin ya da catalog_xmin değerinin yaşını age() ile ölçebilirsiniz; bu değer sürekli büyüyorsa slot temizliği tutuyordur.
Tuzaklar
Kendiliğinden doğan kalıcı slotlar. pg_basebackup akış sırasında varsayılan olarak geçici bir slot kullanır ve iş bitince slot kaybolur. Ama -C -S ad ile kalıcı slot oluşturulursa ve sonrasında replika kurulmazsa, slot sessizce kalır. Yeni bir replika denemesinden sonra slot listesine bakmayı alışkanlık edinin.
Az trafikli veritabanında CDC. Mantıksal slot ancak tüketici onay verdikçe ilerler. İzlenen tablolarda değişiklik yoksa bazı CDC araçları onay göndermez, ama aynı sunucudaki başka veritabanları WAL üretmeye devam eder. Slot hiç değişiklik okumadığı hâlde WAL biriktirir. Çözüm, tüketicinin düzenli aralıkla küçük bir yazma yaptığı bir kalp atışı tablosudur; Debezium gibi araçların bunun için hazır ayarı vardır.
Yük devretmede kaybolan mantıksal slotlar. PostgreSQL 17 öncesinde mantıksal slotlar replikaya kopyalanmaz. Birincil düşüp replika terfi ettiğinde CDC tüketicisinin devam edeceği slot yoktur ve aradaki değişiklikler kaybolur. 17 ile birlikte slotu failover seçeneğiyle oluşturup replikada sync_replication_slots ayarını açarak slotun eşlenmesini sağlayabilirsiniz. Daha eski bir sürümdeyseniz yük devretme runbook'unuzda CDC'nin yeniden anlık görüntü alacağını varsayın.
Etkin slotu silmeye çalışmak. pg_drop_replication_slot() etkin bir slotu silmez. Önce active_pid değerindeki bağlantıyı pg_terminate_backend() ile sonlandırmak gerekir. Tüketici otomatik yeniden bağlanıyorsa araya girer ve slotu tekrar etkin hâle getirir; önce tüketiciyi durdurun.
Sınırı koyup unutmak. max_slot_wal_keep_size koyduğunuzda artık disk dolmaz, ama tüketici sessizce slotunu kaybedebilir. Bu nedenle wal_status = 'lost' durumu da bir alarm olmalıdır. Sınır, sorunu bir yerden başka bir yere taşır; görünmez yapmamalıdır.
Ne zaman slot kullanmamalı
Kısa süreli kopyalar, test replikaları ve tek seferlik veri taşıma işleri için kalıcı slot açmayın. Bu işlerin geride kalması tolere edilebilir ve yeniden başlatılabilirler; wal_keep_size ya da arşiv yeterlidir. Ekibinizde slotları izleyecek bir alarm yoksa da slotu sınırsız bırakmayın. Bir slot, ancak birisi onun durumuna bakıyorsa güvenli bir sözdür.