PostgreSQL VACUUM ve Autovacuum: Derinlemesine Ayarlar ve Üretim İzleme Stratejileri
PostgreSQL'in çoklu sürüm eşzamanlılık kontrolü (MVCC) mimarisi, okuma işlemlerini yazma işlemlerinden izole ederek yüksek eşzamanlılık sağlar. Ancak bu mimarinin bir bedeli vardır: her UPDATE veya DELETE işlemi, diske yeni bir veri sürümü yazar ve eski sürümü "ölü tuple" olarak bırakır. Bu ölü tuplar, diski gereksiz yere doldurur, indekslerin şişmesine neden olur ve sorgu performansını olumsuz etkiler. İşte bu noktada VACUUM devreye girer.
VACUUM'un Temel İşlevi ve Autovacuum'un Rolü
VACUUM, bu ölü tupları temizleyerek disk alanını geri kazanır ve veritabanı performansını optimize eder. Ayrıca, indekslerin güncel kalmasını sağlar ve en önemlisi, Transaction ID (XID) wraparound sorununu önler. XID, PostgreSQL'deki her işlem için atanan 32 bitlik bir sayıdır. Bu sayı bir döngüde kullanıldığından, eğer VACUUM yeterince sık çalışmazsa, XID'ler tükenir ve veritabanı kapanır (salt okunur moda geçer) ve bu ciddi bir kesintiye neden olur.
Manuel VACUUM çalıştırmak pratik değildir. Bu nedenle PostgreSQL, Autovacuum adlı arka plan servisini sunar. Autovacuum, tablo aktivitesini izler ve belirli eşiklere ulaşıldığında otomatik olarak VACUUM ve ANALYZE işlemlerini tetikler. ANALYZE, sorgu planlayıcısının en verimli sorgu planlarını oluşturabilmesi için tablo istatistiklerini günceller.
Autovacuum Tetikleme Mekanizmaları ve Ayarları
Autovacuum'un ne zaman çalışacağını belirleyen ana parametreler şunlardır:
autovacuum_vacuum_scale_factor: Bir tablonun toplam satır sayısının yüzdesi olarak ölü tuple eşiğini belirler.autovacuum_vacuum_threshold: Ölü tuple sayısının mutlak eşiğini belirler.autovacuum_analyze_scale_factor: Bir tablonun toplam satır sayısının yüzdesi olarak güncellenmiş/eklenen satır eşiğini belirler.autovacuum_analyze_threshold: Güncellenmiş/eklenen satır sayısının mutlak eşiğini belirler.
Bir tablo için autovacuum, (autovacuum_vacuum_scale_factor * table_rows) + autovacuum_vacuum_threshold formülüyle hesaplanan ölü tuple sayısına ulaştığında tetiklenir. Benzer şekilde ANALYZE için de aynı mantık geçerlidir.
Varsayılan değerler genellikle çoğu iş yükü için yeterli olsa da, yüksek yazma yüküne sahip tablolar veya çok büyük tablolar için bu değerleri tablo bazında özelleştirmek gerekebilir. Örneğin, küçük ama çok sık güncellenen bir tablo için scale_factor'ı düşürmek, veya çok büyük tablolar için threshold'u artırmak mantıklı olabilir.
ALTER TABLE your_table SET (autovacuum_vacuum_scale_factor = 0.05); -- %5 yerine %10 default
ALTER TABLE your_table SET (autovacuum_vacuum_threshold = 1000); -- Mutlak eşik
ALTER TABLE your_table SET (autovacuum_analyze_scale_factor = 0.02);
ALTER TABLE your_table SET (autovacuum_analyze_threshold = 500);Bu ayarlar, postgresql.conf dosyasında global olarak veya tablo bazında ALTER TABLE komutuyla yapılabilir.
Kaynak Kontrolü ve Autovacuum İş Yükü Yönetimi
Autovacuum'un sistem üzerindeki etkisini sınırlamak için kaynak kontrol parametreleri mevcuttur:
autovacuum_vacuum_cost_delay: Autovacuum, belirli bir I/O maliyetine ulaştığında ne kadar milisaniye bekleyeceğini belirler. Varsayılan 2ms'dir. Çok aktif sistemlerde bu değeri düşürmek (0 yapmak bile) VACUUM'un daha hızlı bitmesini sağlayabilir, ancak disk I/O'sunu artırır.autovacuum_vacuum_cost_limit: Bir autovacuum işlemi başlamadan önce veya her beklemeden sonra ne kadar maliyete izin verildiğini belirler. Varsayılan -1 (yanivacuum_cost_limitglobal değerini kullan) olup, genellikle 200'dür.
Bu parametreler, autovacuum'un sürekli disk I/O'su yapmasını engeller ve diğer veritabanı operasyonlarına engel olmamasını sağlar. Ancak, çok düşük cost_delay veya çok yüksek cost_limit değerleri, autovacuum'un bir anda çok fazla kaynak tüketmesine neden olabilir. Üretim ortamlarında bu değerleri dikkatlice ayarlamak kritik öneme sahiptir.
autovacuum_max_workers parametresi, aynı anda çalışabilecek maksimum autovacuum worker sayısını belirler. Daha fazla worker, daha fazla tabloyu eş zamanlı olarak işleyebilir, ancak daha fazla CPU ve I/O kaynağı tüketir.
XID Wraparound ve Proaktif İzleme
XID wraparound, VACUUM'un en kritik görevlerinden biridir. PostgreSQL, her bir 32-bit XID'yi "freeze" etmek zorundadır, yani bir transaction'ın "çok eski" olduğunu işaretleyerek XID döngüsünü tamamlar. Eğer bir tablo çok uzun süre VACUUM edilmezse, XID'ler tükenmeye başlar ve kritik eşiğe yaklaşıldığında PostgreSQL, XID wraparound'ı önlemek için agresif VACUUM işlemleri başlatır ve hatta veritabanını salt okunur moda alabilir.
Bu durumu izlemek için pg_database tablosundaki datfrozenxid sütununu kullanabiliriz:
SELECT datname, age(datfrozenxid) FROM pg_database;age(datfrozenxid), veritabanının en eski "frozen" XID'sinin mevcut XID'ye göre ne kadar eski olduğunu gösterir. Bu değer 2 milyardan (2^31) küçük olmalıdır. Genellikle autovacuum_freeze_max_age (varsayılan 200 milyon) eşiğine yaklaşıldığında proaktif önlemler alınmalıdır.
Üretim Ortamında Autovacuum İzleme
Autovacuum'un nasıl çalıştığını anlamak ve sorunları gidermek için çeşitli araçlar mevcuttur:
pg_stat_all_tables: Bu sistem görünümü, her tablonun ne zaman en son VACUUM veya ANALYZE edildiği, kaç ölü tuple olduğu, kaç kez VACUUM/ANALYZE tetiklendiği gibi kritik istatistikleri sunar. Özelliklen_dead_tuplesvelast_autovacuum/last_autoanalyzesütunları çok bilgilendiricidir.
SELECT
relname,
n_dead_tuples,
n_live_tuples,
last_autovacuum,
last_autoanalyze,
autovacuum_count,
autoanalyze_count
FROM
pg_stat_all_tables
WHERE
n_dead_tuples > 0
ORDER BY
n_dead_tuples DESC;pg_stat_activity: Çalışan autovacuum işlemlerini bu görünümden takip edebilirsiniz. Bir autovacuum işleminin hangi tablo üzerinde çalıştığını, ne kadar süredir aktif olduğunu ve hangi durum (state) olduğunu görebilirsiniz.
SELECT
pid,
datname,
usename,
client_addr,
application_name,
backend_start,
state,
query_start,
state_change,
wait_event_type,
wait_event,
query
FROM
pg_stat_activity
WHERE
backend_type = 'autovacuum worker';pg_locks: Autovacuum, tabloları kilitler (genellikle ACCESS EXCLUSIVE kilit değil, ACCESS SHARE veya SHARE UPDATE EXCLUSIVE). Uzun süreli çalışan bir VACUUM, diğer işlemlerin bloklanmasına neden olabilir.
Gerçek Senaryo: Yüksek Yazma Yükü Altında Autovacuum Ayarlarının Optimizasyonu
Bir e-ticaret platformunda, siparişlerin anlık olarak kaydedildiği orders tablosu ve envanterin güncellendiği products tablosu, yoğun INSERT ve UPDATE trafiği altındaydı. Geceleri yapılan büyük veri yüklemeleri (batch inserts/updates) sonrasında, sabahları sorgu performansında belirgin düşüşler yaşanıyordu. pg_stat_all_tables kontrol edildiğinde, orders ve products tablolarında n_dead_tuples değerlerinin hızla yükseldiği ve last_autovacuum zamanlarının çok geride kaldığı görüldü.
Sorun, global autovacuum_vacuum_scale_factor (varsayılan 0.1, yani %10) ve autovacuum_vacuum_threshold (varsayılan 50) değerlerinin, bu yüksek hacimli tablolar için yetersiz kalmasıydı. Autovacuum, tetikleme eşiğine geç ulaşıyor ve biriken ölü tupları temizlemede gecikiyordu. Ayrıca, autovacuum_vacuum_cost_delay'in varsayılan 2ms olması, VACUUM'un çok yavaş ilerlemesine neden oluyordu.
Çözüm olarak, bu iki tablo için özel ayarlar yapıldı:
ALTER TABLE orders SET (autovacuum_vacuum_scale_factor = 0.01); -- %1'e düşürüldü
ALTER TABLE orders SET (autovacuum_vacuum_threshold = 100); -- Mutlak eşik artırıldı
ALTER TABLE orders SET (autovacuum_vacuum_cost_delay = 0); -- Gecikme kaldırıldı
ALTER TABLE products SET (autovacuum_vacuum_scale_factor = 0.02); -- %2'ye düşürüldü
ALTER TABLE products SET (autovacuum_vacuum_threshold = 200); -- Mutlak eşik artırıldı
ALTER TABLE products SET (autovacuum_vacuum_cost_delay = 0); -- Gecikme kaldırıldıcost_delay'in 0'a ayarlanması, bu tablolardaki VACUUM işlemlerinin mümkün olan en hızlı şekilde tamamlanmasını sağladı. Bu değişiklikler uygulandıktan sonra, tabloların şişmesi azaldı, sorgu performansında gözle görülür bir iyileşme oldu ve ölü tuple birikimi kontrol altına alındı. Bu, autovacuum'un genel sistem performansına olumsuz etki etmeden belirli tablolar için agresif hale getirilebileceğini gösteren tipik bir üretim senaryosudur.
Gerçek Senaryo: Uzun Süreli İşlemlerin Autovacuum'u Engellemesi
Başka bir üretim ortamında, gün sonu raporlama için çalışan uzun süreli bir SQL sorgusu (örneğin, SELECT ... FOR UPDATE veya büyük bir ETL işlemi), belirli tablolar üzerinde ACCESS SHARE veya daha kısıtlayıcı kilitler tutuyordu. Bu uzun süreli işlem, Autovacuum'un ilgili tablolarda VACUUM işlemi başlatmasını engelliyordu. Autovacuum, VACUUM yapabilmek için tablo üzerinde SHARE UPDATE EXCLUSIVE kilidi almaya çalışır. Eğer bu kilit uzun süre tutulan başka bir kilitle çakışırsa, Autovacuum beklemeye başlar ve ölü tuplar birikir.
Bu durumu pg_stat_activity ve pg_locks görünümlerinden tespit etmek mümkündür:
-- Hangi işlemler Autovacuum'u bekletiyor?
SELECT
pa.pid,
pa.query,
pa.state,
pa.query_start,
pl.relation::regclass,
pl.mode,
pl.granted,
blocking_pid
FROM
pg_stat_activity pa
JOIN
pg_locks pl ON pa.pid = pl.pid
JOIN
(
SELECT
blocking_locks.pid AS blocking_pid,
blocking_locks.relation::regclass,
blocking_locks.mode AS blocking_mode
FROM
pg_locks AS blocking_locks
JOIN
pg_stat_activity AS blocking_activity ON blocking_locks.pid = blocking_activity.pid
WHERE
NOT blocking_locks.granted
AND blocking_activity.backend_type = 'autovacuum worker'
) AS blocked_autovacuum ON pl.relation = blocked_autovacuum.relation::oid
WHERE
pl.granted
AND pl.pid != blocked_autovacuum.blocking_pid;Yukarıdaki sorgu, bir autovacuum worker'ın beklediği bir kilit ve bu kilidi tutan diğer işlemleri gösterir. Bu senaryoda, uzun süreli raporlama sorgusunun optimize edilmesi, daha kısa süreli işlemler halinde parçalanması veya raporlama işleminin yoğun olmayan saatlere kaydırılması gibi operasyonel müdahalelerle sorun giderilmiştir. Alternatif olarak, kritik tablolar için autovacuum_vacuum_cost_delay = 0 ve autovacuum_vacuum_cost_limit'in artırılması gibi daha agresif autovacuum ayarları düşünülebilir, ancak bu da kilit bekleme süresini artırabilir.
Sonuç ve Optimize Yaklaşımlar
PostgreSQL'de Autovacuum, performansı korumak ve XID wraparound gibi felaketleri önlemek için vazgeçilmez bir bileşendir. Global autovacuum ayarları çoğu durum için iyi bir başlangıç noktası olsa da, yüksek performanslı üretim ortamlarında tablo bazında ince ayarlar yapmak ve Autovacuum'un çalışma durumunu sürekli izlemek kritik öneme sahiptir. pg_stat_all_tables ve pg_stat_activity gibi sistem görünümlerini kullanarak proaktif izleme ve duruma özel ayarlamalar, PostgreSQL veritabanlarınızın sağlığını ve performansını güvence altına almanın anahtarıdır.