Zabbix ile PostgreSQL Veritabanı İzleme

PostgreSQL izlemeye başladığımda, Zabbix’in varsayılan şablonlarının yüzeysel kaldığını fark etmek uzun sürmedi. Disk dolumu, bağlantı sayısı, sorgu süreleri… Bunların hepsini doğru yapılandırmazsanız, bir gün production veritabanınız yavaşlamaya başlar ve siz hâlâ “her şey normal görünüyor” diye monitor ekranına bakarsınız. Bu yazıda sıfırdan başlayarak PostgreSQL’i Zabbix üzerinde nasıl izleyeceğinizi, hangi metriklere gerçekten dikkat etmeniz gerektiğini ve bazı ince ama kritik noktaları aktarmaya çalışacağım.

Kurulum Öncesi Hazırlık

Zabbix’in PostgreSQL’i izleyebilmesi için birkaç farklı yol var. Zabbix Agent 2 kullanıyorsanız, içinde gömülü PostgreSQL plugin’i geliyor ve bu en temiz çözüm. Zabbix Agent (klasik) ile gidiyorsanız, pg_activity veya özel script’ler yazmanız gerekiyor. Ben her iki senaryoyu da anlatacağım ama önce ortak altyapıyı hazırlayalım.

PostgreSQL’de İzleme Kullanıcısı Oluşturma

Production ortamında asla postgres superuser’ı ile izleme yapmayın. Bunun için read-only bir monitoring kullanıcısı oluşturun:

-- PostgreSQL'e bağlanın
CREATE USER zabbix_monitor WITH PASSWORD 'guclu_bir_sifre';

-- pg_monitor rolünü atayın (PostgreSQL 10+)
GRANT pg_monitor TO zabbix_monitor;

-- Eğer eski sürüm kullanıyorsanız elle verin
GRANT SELECT ON pg_stat_database TO zabbix_monitor;
GRANT SELECT ON pg_stat_replication TO zabbix_monitor;
GRANT SELECT ON pg_stat_user_tables TO zabbix_monitor;
GRANT EXECUTE ON FUNCTION pg_ls_waldir() TO zabbix_monitor;

pg_monitor rolü PostgreSQL 10 ile geldi ve izleme için gereken neredeyse tüm view’lara okuma yetkisi veriyor. Bu rolü kullanmak, elle tek tek yetki vermekten çok daha güvenli bir yol.

pg_hba.conf Yapılandırması

Zabbix agent’ının hangi IP’den bağlanacağını pg_hba.conf dosyasına eklemeniz gerekiyor:

# /etc/postgresql/14/main/pg_hba.conf dosyasına ekleyin
# Zabbix agent aynı sunucudaysa
host    all    zabbix_monitor    127.0.0.1/32    scram-sha-256

# Zabbix agent ayrı bir sunucudaysa
host    all    zabbix_monitor    192.168.1.100/32    scram-sha-256

Değişikliği uygulamak için reload yeterli, restart gerekmez:

systemctl reload postgresql
# veya
pg_ctlcluster 14 main reload

Zabbix Agent 2 ile PostgreSQL Plugin Yapılandırması

Zabbix Agent 2, Go ile yazılmış ve plugin mimarisine sahip. PostgreSQL için ayrı bir şey yüklemenize gerek yok.

Agent 2 Yapılandırma Dosyası

# /etc/zabbix/zabbix_agent2.d/postgresql.conf

Plugins.PostgreSQL.Default.Uri=tcp://localhost:5432
Plugins.PostgreSQL.Default.User=zabbix_monitor
Plugins.PostgreSQL.Default.Password=guclu_bir_sifre
Plugins.PostgreSQL.Default.Database=postgres

# Bağlantı havuzu boyutu
Plugins.PostgreSQL.Default.KeepAlive=300
Plugins.PostgreSQL.Default.CallTimeout=30

Şifreyi konfig dosyasına düz metin yazmak istemiyorsanız, Zabbix Vault entegrasyonunu kullanabilirsiniz. Ama en basit haliyle bu yapılandırma çalışır.

Agent’ı yeniden başlatın:

systemctl restart zabbix-agent2

Bağlantıyı test etmek için:

zabbix_agent2 -t pgsql.ping[tcp://localhost:5432,zabbix_monitor,guclu_bir_sifre]
# Dönen değer: 1 (başarılı)

Zabbix Frontend’de Template Yapılandırması

Zabbix 6.0 ve sonrasında “PostgreSQL by Zabbix Agent 2” adında hazır bir template geliyor. Bu template’i host’a bağlayıp makro değerlerini girmek yeterli.

Host makroları:

  • {$PG.HOST}: localhost ya da gerçek IP
  • {$PG.PORT}: 5432
  • {$PG.USER}: zabbix_monitor
  • {$PG.PASSWORD}: şifreniz
  • {$PG.DB}: postgres

Template’i bağladıktan birkaç dakika sonra veriler akmaya başlar. Ancak burada durup “tamam, bitirdim” dememenizi öneririm. Hazır template’in bazı threshold’ları senaryonuza uymayabilir.

Kritik Metrikler ve Özel İzleme Sorguları

Hazır template iyi bir başlangıç noktası ama production ortamında bazı özel metrikleri kendiniz eklemeniz gerekiyor. İşte gerçek hayatta işe yarayan sorgular.

Bağlantı Havuzu İzleme

PostgreSQL’in bağlantı limitine yaklaşmak ciddi bir problem. Bunu erken yakalamak kritik:

-- Aktif bağlantı sayısını ve maksimum limiti karşılaştır
SELECT
    count(*) AS total_connections,
    max_conn,
    round(count(*) * 100.0 / max_conn, 2) AS usage_percent
FROM pg_stat_activity,
     (SELECT setting::int AS max_conn FROM pg_settings WHERE name = 'max_connections') mc
GROUP BY max_conn;

Bu sorguyu Zabbix’te custom UserParameter olarak ekleyebilirsiniz:

# /etc/zabbix/zabbix_agentd.d/pg_custom.conf

UserParameter=pg.connection.usage,psql -U zabbix_monitor -d postgres -t -c "SELECT round(count(*) * 100.0 / (SELECT setting::int FROM pg_settings WHERE name = 'max_connections'), 2) FROM pg_stat_activity;"

Bağlantı kullanımı %80’i geçtiğinde uyarı, %90’ı geçtiğinde kritik alarm tetiklemenizi öneririm. Bunu Zabbix trigger’ı olarak tanımlayın.

Bloklanan Sorgu Tespiti

Uzun süre bekleyen ya da bloklanan sorgular veritabanını felç edebilir. Bunu izlemek şart:

-- 5 dakikadan uzun süredir bekleyen sorgular
SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state,
    wait_event_type,
    wait_event
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'
  AND state != 'idle'
ORDER BY duration DESC;

Bu sorguyu Zabbix’e count döndürecek şekilde basitleştirin:

UserParameter=pg.long.queries,psql -U zabbix_monitor -d postgres -t -c "SELECT count(*) FROM pg_stat_activity WHERE (now() - query_start) > interval '5 minutes' AND state != 'idle';"

Trigger koşulu: last(pg.long.queries) > 0 olduğunda WARNING, last(pg.long.queries) > 5 olduğunda HIGH alarm tetikleyin.

Vacuum ve Bloat İzleme

PostgreSQL’in MVCC yapısı nedeniyle eski satır versiyonları tablolarda birikerek “bloat” oluşturur. Autovacuum’un bu bloat’ı temizleyip temizlemediğini takip etmeniz lazım. Bu metrik çoğu hazır template’de ya hiç yok ya da çok yüzeysel:

-- Tablolarda dead tuple oranı
SELECT
    schemaname,
    relname AS tablename,
    n_dead_tup,
    n_live_tup,
    round(n_dead_tup * 100.0 / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_tuple_percent,
    last_vacuum,
    last_autovacuum
FROM pg_stat_user_tables
WHERE n_live_tup + n_dead_tup > 10000
ORDER BY dead_tuple_percent DESC
LIMIT 10;

Dead tuple oranı %20’yi geçen tablolarınız varsa, autovacuum ayarlarını gözden geçirmeniz gerekiyor. Bu durumu Zabbix’te izlemek için en yüksek dead tuple yüzdesini döndüren bir item oluşturun.

Replikasyon Gecikmesi İzleme

Primary-replica kurulumunuzda replikasyon gecikmesi kritik bir metriktir. Primary tarafında çalıştırın:

-- Byte cinsinden replikasyon gecikmesi
SELECT
    application_name,
    client_addr,
    state,
    pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replication_lag_bytes
FROM pg_stat_replication;
UserParameter=pg.replication.lag,psql -U zabbix_monitor -d postgres -t -c "SELECT COALESCE(MAX(pg_wal_lsn_diff(sent_lsn, replay_lsn)), 0) FROM pg_stat_replication;"

10 MB’ı geçen replikasyon gecikmesi için WARNING, 100 MB için CRITICAL trigger tanımlayın. Bu değerleri iş gereksinimlerinize göre ayarlayın, her ortam farklı.

Zabbix Low-Level Discovery ile Dinamik Veritabanı İzleme

Sunucunuzda birden fazla veritabanı çalışıyorsa her birini tek tek eklemek yerine LLD (Low-Level Discovery) kullanın. Zabbix Agent 2’nin PostgreSQL plugin’i zaten bunu destekliyor ama elle de yapabilirsiniz.

Discovery script’i:

#!/bin/bash
# /etc/zabbix/scripts/pg_db_discovery.sh

PSQL_CMD="psql -U zabbix_monitor -d postgres -t -A -F','"

DATABASES=$($PSQL_CMD -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres';")

echo '{"data":['
FIRST=1
while IFS=',' read -r DBNAME; do
    if [ $FIRST -eq 0 ]; then
        echo ','
    fi
    echo "{"{#DBNAME}":"${DBNAME}"}"
    FIRST=0
done <<< "$DATABASES"
echo ']}'

Bu script’i çalıştırılabilir yapın ve Zabbix’e UserParameter olarak ekleyin:

chmod +x /etc/zabbix/scripts/pg_db_discovery.sh

# pg_custom.conf'a ekle
UserParameter=pg.db.discovery,/etc/zabbix/scripts/pg_db_discovery.sh

Zabbix frontend’de Discovery rule oluşturup {#DBNAME} makrosunu item prototype’larınızda kullanabilirsiniz. Her yeni veritabanı otomatik olarak izlemeye alınır.

Gerçek Dünya Senaryosu: Production Krizini Önceden Yakalamak

Geçen yıl bir e-ticaret platformunda yaşanan olayı paylaşayım. Sabah 3’te veritabanı yanıt süreleri patladı. İncelediğimizde şunları gördük:

Birinci sorun: Bir developer gece yarısı büyük bir tabloya index eklemişti. Bu işlem tabloya exclusive lock koymuş ve ardından gelen tüm sorgular beklemeye girmişti. Eğer bloklanan sorgu sayısını izlemiş olsaydık, bu durumu dakikalar içinde fark ederdik.

İkinci sorun: O tablonun dead tuple oranı %35’e çıkmıştı ama autovacuum bunu temizleyemiyordu çünkü lock nedeniyle çalışamıyordu.

O olaydan sonra şu üç metriği her PostgreSQL sunucusuna zorunlu olarak ekledik:

  • Bloklanan sorgu sayısı (eşik: 0’dan fazla olunca bile uyar)
  • Exclusive lock bekleyen bağlantı sayısı
  • Autovacuum’un son çalışma zamanı (2 saat geçmişse uyar)

Şu sorgu exclusive lock bekleyenleri verir:

SELECT count(*) 
FROM pg_stat_activity 
WHERE wait_event_type = 'Lock' 
  AND wait_event = 'relation';
UserParameter=pg.exclusive.lock.wait,psql -U zabbix_monitor -d postgres -t -c "SELECT count(*) FROM pg_stat_activity WHERE wait_event_type = 'Lock' AND wait_event = 'relation';"

Zabbix Trigger Yapılandırması

Sadece veri toplamak yetmez, doğru trigger’ları tanımlamak izlemenin yarısı. Benim tercih ettiğim trigger sıralaması:

Disaster seviyesi:

  • max_connections kapasitesinin %95’ine ulaşıldı
  • PostgreSQL process’i cevap vermiyor (pgsql.ping 0 döndü)
  • Replikasyon tamamen durdu

High seviyesi:

  • Bağlantı kullanımı %85’i geçti
  • 10 dakikadan uzun süredir bekleyen sorgu var
  • Replikasyon gecikmesi 50 MB’ı geçti
  • Dead tuple oranı %30’u geçen tablo var

Warning seviyesi:

  • Bağlantı kullanımı %70’i geçti
  • 5 dakikadan uzun süredir bekleyen sorgu var
  • Disk kullanımı (WAL dahil) %80’i geçti

Trigger expression örneği, Zabbix 6.x syntax ile:

last(/hostname/pg.connection.usage) > 85

Bağlantı kullanımı için Hysteresis kullanmanızı öneririm. Değer %85’in altına düşmeden alarmı kapatmayın:

last(/hostname/pg.connection.usage) > 85
# Recovery condition:
last(/hostname/pg.connection.usage) < 75

Performans İzleme: Cache Hit Ratio

PostgreSQL’in buffer cache kullanımı sorgu performansının göstergesi. Bu oranın %95’in altına düşmesi, RAM artırmanız ya da shared_buffers değerini gözden geçirmeniz gerektiğine işaret edebilir:

SELECT
    datname,
    blks_hit,
    blks_read,
    round(blks_hit * 100.0 / NULLIF(blks_hit + blks_read, 0), 2) AS cache_hit_ratio
FROM pg_stat_database
WHERE datname NOT IN ('template0', 'template1')
ORDER BY cache_hit_ratio ASC;
UserParameter=pg.cache.hitratio[*],psql -U zabbix_monitor -d $1 -t -c "SELECT round(blks_hit * 100.0 / NULLIF(blks_hit + blks_read, 0), 2) FROM pg_stat_database WHERE datname = '$1';"

Bu item’ı LLD ile birleştirerek her veritabanı için ayrı cache hit ratio izleyebilirsiniz.

Grafana Entegrasyonu (Bonus)

Zabbix’in kendi grafikleri temel ihtiyaçları karşılar ama PostgreSQL metriklerini görselleştirmek için Grafana + Zabbix datasource kombinasyonu çok daha iyi sonuç veriyor. Zabbix datasource plugin’ini Grafana’ya yükledikten sonra, topladığınız tüm metrikleri Grafana dashboard’larında gösterebilirsiniz.

Özellikle pg_stat_statements extension’ını etkinleştirirseniz ve sorgu bazında istatistikleri toplayabilirseniz, hangi sorguların en fazla yük oluşturduğunu gösteren dashboard’lar hazırlayabilirsiniz. Bunu aktive etmek için:

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.max = 10000
pg_stat_statements.track = all

Sonra veritabanında:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

Sonuç

PostgreSQL izleme, “kurdum çalışıyor” aşamasından geçip gerçekten operasyonel görünürlük sağlamak için zaman ve dikkat istiyor. Zabbix’in hazır template’leri iyi bir başlangıç noktası, ama production ortamında bloklanan sorgular, dead tuple birikimi, replikasyon gecikmesi ve bağlantı havuzu kullanımı gibi metrikleri özel olarak eklemeniz şart.

En önemli çıkarım şu: İzleme, olaydan sonra “ne oldu” sorusunu yanıtlamak için değil, olayı önceden haber vermek için var. Doğru threshold’ları, doğru metrikleri ve iyi yapılandırılmış trigger’ları olan bir Zabbix kurulumu, production krizlerini saatler önce size söyler.

Burada anlattığım sorguları kendi ortamınıza uyarlarken PostgreSQL sürümüne dikkat edin. PostgreSQL 10 öncesi için bazı sorgular farklı çalışabilir ya da ilgili view’lar mevcut olmayabilir. PostgreSQL 14 ve üzerinde her şey sorunsuz çalışır.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir