← Back to list

PostgreSQL WAL’dan Kafka’ya: CDC ile Gerçek Zamanlı Veri Pipeline’ı Nasıl Kurulur?

Geleneksel veri sistemlerinde veriler çoğu zaman belirli aralıklarla taşınır. Örneğin gece 01:00’de çalışan bir ETL job’ı, gün içinde…

Enesagu · 2026-04-30 16:04 · 10 claps · 9.3 min read
#data-engineering #real-time-data-processing #apache-kafka #cdc #change-data-capture
Open on Medium ↗
Wiki topics: 🔧 · Data Engineering

PostgreSQL WAL’dan Kafka’ya: CDC ile Gerçek Zamanlı Veri Pipeline’ı Nasıl Kurulur?

CDC Süreç

CDC Süreç

Geleneksel veri sistemlerinde veriler çoğu zaman belirli aralıklarla taşınır. Örneğin gece 01:00’de çalışan bir ETL job’ı, gün içinde oluşan verileri alır, dönüştürür ve Data Warehouse tarafına yazar. Bu yaklaşım birçok senaryo için yeterli olsa da, günümüzde bazı sistemler veriye saatler sonra değil, saniyeler içinde tepki vermek zorundadır.

Örneğin:

- Bir ödeme işlemi başarısız olduğunda anlık alarm üretmek
- Bir kullanıcının kritik bir aksiyonunu gerçek zamanlı analiz etmek
- Operasyonel sistemde değişen bir veriyi dashboard’a hızlıca yansıtmak
- Data Warehouse tarafını sürekli güncel tutmak
- AI veya karar destek sistemlerine taze veri sağlamak

Bu noktada karşımıza CDC, yani Change Data Capture çıkar.

CDC, veritabanındaki değişiklikleri yakalayarak bu değişiklikleri başka sistemlere aktarma yaklaşımıdır. Bu yazıda PostgreSQL tarafında oluşan değişikliklerin WAL üzerinden nasıl yakalanabileceğini, Kafka’ya nasıl aktarılabileceğini ve buradan gerçek zamanlı veri pipeline’ı kurulabileceğini anlatacağım.

CDC Nedir?

CDC, açılımıyla Change Data Capture, bir veritabanında oluşan değişiklikleri yakalama yöntemidir.

Bu değişiklikler genellikle şunlardır:

INSERT
UPDATE
DELETE

Yani bir tabloya yeni kayıt eklendiğinde, mevcut kayıt güncellendiğinde veya kayıt silindiğinde bu olaylar yakalanır ve başka sistemlere event olarak gönderilir.

Basit düşünürsek:

PostgreSQL’de bir kayıt değişir
        ↓
CDC bu değişikliği yakalar
        ↓
Kafka’ya event olarak gönderir
        ↓
Consumer bu eventi işler
        ↓
Data Warehouse, dashboard veya alarm sistemi güncellenir

Bu yaklaşım sayesinde sürekli tüm tabloyu okumaya gerek kalmaz. Sadece değişen veriler işlenir.

Bu da özellikle büyük veri sistemlerinde çok önemlidir.

Neden Direkt Batch ETL Değil?

Klasik batch ETL sisteminde genellikle şöyle bir yapı vardır:

Her gece:
PostgreSQL → ETL Job → Data Warehouse

Bu yapının bazı dezavantajları vardır:

- Veri geç güncellenir
- Büyük tablolar tekrar tekrar okunur
- Sistem kaynakları gereksiz kullanılır
- Gerçek zamanlı alarm üretmek zordur
- Değişiklik geçmişini takip etmek karmaşıklaşır

Örneğin 100 milyon satırlık bir tablonun sadece 10.000 satırı değiştiyse, tüm tabloyu tekrar okumak verimsizdir.

CDC yaklaşımı ise şöyle çalışır:

Sadece değişen kayıtları yakala
Sadece gerekli eventleri işle
Sadece yeni/güncel veriyi aktar

Bu nedenle CDC, özellikle incremental data pipeline tasarımlarında çok güçlüdür.

PostgreSQL WAL Nedir?

PostgreSQL’de her veri değişikliği doğrudan tabloya yazılmadan önce WAL adı verilen bir log yapısına kaydedilir.

WAL, Write-Ahead Log anlamına gelir.

Basitçe söylemek gerekirse PostgreSQL şunu yapar:

Önce değişikliği log’a yaz
Sonra veritabanı dosyalarına uygula

Bunun temel amacı veri güvenliğidir. Eğer sistem çökerse PostgreSQL WAL kayıtlarını kullanarak veriyi kurtarabilir.

Fakat WAL sadece recovery için değil, CDC için de çok değerlidir. Çünkü veritabanında olan değişiklikler burada sıralı şekilde tutulur.

Örneğin bir kullanıcı tablosunda güncelleme olduğunda WAL tarafında kabaca şu mantıkta bir kayıt oluşur:

{
  "operation": "UPDATE",
  "table": "users",
  "before": {
    "id": 12,
    "status": "pending"
  },
  "after": {
    "id": 12,
    "status": "active"
  },
  "timestamp": "2026-04-30T12:00:00"
}

Tabii PostgreSQL WAL doğrudan bu kadar okunabilir JSON formatında tutulmaz. Bunun için logical decoding, replication slot veya Debezium gibi araçlar kullanılır.

Logical Decoding ve Replication Slot Mantığı

PostgreSQL’de CDC yapabilmek için genellikle logical replication özelliği kullanılır.

Bunun için PostgreSQL tarafında bazı ayarlar gerekir:

wal_level = logical
max_replication_slots = 10
max_wal_senders = 10

Buradaki en önemli ayar:

wal_level = logical

Çünkü bu ayar PostgreSQL’in WAL kayıtlarını mantıksal değişiklikler olarak dışarıya sunmasını sağlar.

Bir diğer önemli kavram ise replication slottur.

Replication slot, PostgreSQL’e şunu söyler:

“Bu değişiklikleri bir consumer okuyacak.
Okunana kadar WAL kayıtlarını silme.”

Yani Kafka’ya veri aktaracak sistem bir süre çalışmasa bile PostgreSQL gerekli WAL kayıtlarını tutabilir. Böylece sistem yeniden ayağa kalktığında kaldığı yerden devam edebilir.

Ancak burada dikkat edilmesi gereken önemli bir nokta vardır:

Replication slot tüketilmezse WAL dosyaları birikmeye başlar. Bu da disk dolmasına sebep olabilir.

Bu yüzden production ortamda CDC kullanırken replication slot monitoring çok önemlidir.

Genel Mimari

PostgreSQL WAL’dan Kafka’ya akan bir CDC mimarisi genel olarak şu şekilde düşünülebilir:

Bu yapıda PostgreSQL kaynak sistemdir. Kafka ise değişiklik eventlerini taşıyan merkezi omurga gibi çalışır.

Debezium Bu Yapıda Ne İşe Yarar?

CDC pipeline kurarken en yaygın araçlardan biri Debeziumdur.

Debezium, veritabanlarındaki değişiklikleri yakalayıp Kafka’ya event olarak gönderen bir CDC platformudur.

PostgreSQL için Debezium şunu yapar:

PostgreSQL WAL kayıtlarını okur
Değişiklikleri anlamlı eventlere çevirir
Kafka topic’lerine yazar

Örneğin PostgreSQL’de şöyle bir tablo olsun:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT,
    amount NUMERIC,
    status TEXT,
    created_at TIMESTAMP DEFAULT now()
);

Bu tabloya yeni bir sipariş ekleyelim:

INSERT INTO orders (customer_id, amount, status)
VALUES (101, 750.00, 'created');

Debezium bu değişikliği Kafka’ya event olarak gönderebilir.

Kafka’daki event mantıksal olarak şuna benzer:

{
  "before": null,
  "after": {
    "id": 1,
    "customer_id": 101,
    "amount": 750.00,
    "status": "created",
    "created_at": "2026-04-30T12:00:00"
  },
  "op": "c",
  "source": {
    "db": "app_db",
    "table": "orders"
  },
  "ts_ms": 1777550400000
}

Burada:

op = c  → create
op = u  → update
op = d  → delete

Yani Debezium, veritabanındaki değişikliği event formatına dönüştürür.

Kafka Topic Tasarımı

CDC ile gelen verileri Kafka’da saklarken topic tasarımı önemlidir.

Basit bir yaklaşım şu olabilir:

dbserver.public.orders
dbserver.public.users
dbserver.public.payments

Yani her tablo için ayrı topic oluşturulur.

Bu yapı sayesinde farklı consumer’lar sadece ilgilendikleri tabloyu dinleyebilir.

Örneğin:

- Order analytics consumer → orders topic’ini dinler
- Payment alert consumer → payments topic’ini dinler
- User profile sync consumer → users topic’ini dinler

Bu da sistemin daha modüler ve ölçeklenebilir olmasını sağlar.

Kafka Neden Kullanılır?

Burada şu soru gelebilir:

PostgreSQL’den değişiklikleri yakaladıktan sonra neden doğrudan Data Warehouse’a yazmıyoruz? Neden araya Kafka koyuyoruz?

Çünkü Kafka bu mimaride sadece bir mesaj kuyruğu değildir. Aynı zamanda sistemler arasında dayanıklı, ölçeklenebilir ve tekrar okunabilir bir event log sağlar.

Kafka’nın avantajları:

- Veriyi producer ve consumer arasında gevşek bağlar
- Birden fazla consumer aynı eventi farklı amaçlarla işleyebilir
- Consumer çökerse kaldığı yerden devam edebilir
- Topic partition’ları ile paralel işleme yapılabilir
- Event geçmişi belirli süre Kafka’da tutulabilir
- Gerçek zamanlı sistemler için güçlü bir omurga sağlar

Örneğin aynı orders eventi üç farklı sistem tarafından kullanılabilir:

Örneğin aynı orders eventi üç farklı sistem tarafından kullanılabilir:

Yani Kafka sayesinde tek bir değişiklik birden fazla sisteme güvenli şekilde dağıtılabilir.

Consumer Tarafı Nasıl Çalışır?

Kafka’ya gelen CDC eventleri consumer’lar tarafından okunur.

Basit bir Python consumer mantığı şöyle olabilir:

from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    "app_db.public.orders",
    bootstrap_servers=["localhost:9092"],
    group_id="orders-analytics-consumer",
    auto_offset_reset="earliest",
    enable_auto_commit=False,
    value_deserializer=lambda x: json.loads(x.decode("utf-8"))
)

for message in consumer:
    event = message.value

    operation = event.get("op")
    after = event.get("after")
    before = event.get("before")

    if operation == "c":
        print("New order:", after)

    elif operation == "u":
        print("Updated order:", after)

    elif operation == "d":
        print("Deleted order:", before)

    # İşleme başarılıysa offset commit edilir
    consumer.commit()

Buradaki kritik nokta şudur:

enable_auto_commit=False

Çünkü event başarıyla işlenmeden offset commit edilirse, consumer çöktüğünde veri kaybı yaşanabilir.

Daha güvenli yaklaşım:

1. Eventi oku
2. İşle
3. Hedef sisteme yaz
4. Başarılıysa offset commit et

Idempotency Neden Önemlidir?

Gerçek zamanlı veri pipeline’larında en kritik konulardan biri idempotencydir.

Idempotency basitçe şu anlama gelir:

Aynı event birden fazla kez işlense bile sonuç değişmemeli.

Kafka consumer sistemlerinde bazı durumlarda aynı event tekrar işlenebilir.

Örneğin:

Consumer eventi okudu
Data Warehouse’a yazdı
Ama offset commit etmeden çöktü
Sistem yeniden başladı
Aynı event tekrar okundu

Eğer idempotency yoksa aynı kayıt iki kere yazılabilir.

Bu yüzden hedef sistemde genellikle şu yöntemler kullanılır:

- event_id kullanmak
- primary key veya unique constraint kullanmak
- upsert yapmak
- processed_events tablosu tutmak
- Kafka offset bilgisini takip etmek

Örneğin PostgreSQL hedef tablosuna yazarken şöyle bir mantık kurulabilir:

INSERT INTO fact_orders (order_id, customer_id, amount, status, updated_at)
VALUES (1, 101, 750.00, 'created', now())
ON CONFLICT (order_id)
DO UPDATE SET
    amount = EXCLUDED.amount,
    status = EXCLUDED.status,
    updated_at = now();

Bu sayede aynı sipariş eventi tekrar gelse bile veri iki kere oluşmaz. Mevcut kayıt güncellenir.

Bu yaklaşım CDC pipeline’larında çok önemlidir.

At-Least-Once, At-Most-Once ve Exactly-Once

Kafka tabanlı sistemlerde teslimat garantileri de önemlidir.

Üç temel kavram vardır:

At-most-once:
Event en fazla bir kez işlenir.
Veri kaybı olabilir, duplicate olmaz.

At-least-once:
Event en az bir kez işlenir.
Veri kaybı olmaz, duplicate olabilir.

Exactly-once:
Event tam olarak bir kez işlenir.
Uygulaması daha karmaşıktır.

Pratikte birçok sistem at-least-once mantığıyla çalışır.

Yani sistem şunu garanti eder:

Veri kaybolmasın. Gerekirse tekrar işlenebilir. Duplicate oluşursa idempotency ile çözülür.

Bu nedenle iyi tasarlanmış bir CDC pipeline’da sadece Kafka ayarları değil, hedef sisteme yazma stratejisi de önemlidir.

CDC Pipeline’da Hedef Sistemler

Kafka’ya gelen CDC eventleri farklı sistemlere yazılabilir.

Örneğin:

Data Warehouse:
Analitik raporlar için kullanılır.

Data Lake:
Ham veya yarı işlenmiş event verisi saklanır.

Elasticsearch:
Arama, log analizi veya hızlı dashboard için kullanılır.

Real-time Dashboard:
Anlık metrik ve operasyon takibi sağlar.

Alert System:
Kritik eventlerde alarm üretir.

AI / RAG Pipeline:
Güncel veriler embedding veya bilgi tabanı süreçlerine aktarılır.

Örneğin bir sipariş sistemi için şöyle bir yapı olabilir:

orders topic
    ↓
DWH consumer → fact_orders tablosu
    ↓
Dashboard consumer → anlık satış ekranı
    ↓
Alert consumer → yüksek tutarlı sipariş alarmı

Bu yapı sistemin esnekliğini artırır.

Spark Bu Mimaride Nerede Kullanılır?

Bu noktada şu soru gelebilir:

Kafka varsa Spark’a gerek var mı?

Cevap: Her zaman değil.

Basit event işleme, alarm üretimi veya küçük transformation işlemleri için Python consumer yeterli olabilir.

Ancak şu durumlarda Spark daha anlamlı hale gelir:

- Çok büyük hacimli veri işlenecekse
- Window aggregation yapılacaksa
- Saatlik/günlük büyük hesaplamalar varsa
- Data Lake üzerindeki Parquet dosyaları işlenecekse
- Büyük join operasyonları yapılacaksa
- ML feature üretimi yapılacaksa

Örneğin:

Kafka + Python Consumer:
Anlık alarm üretimi

Kafka + Spark Structured Streaming:
Büyük hacimli stream aggregation

Airflow + Spark:
Günlük batch ETL ve Data Warehouse yükleme

Yani Kafka ve Spark birbirinin alternatifi olmak zorunda değildir. Doğru mimaride birbirini tamamlarlar.

Monitoring ve Hata Yönetimi

CDC pipeline kurarken sadece veri akışını düşünmek yeterli değildir. Sistemin izlenebilir olması gerekir.

Takip edilmesi gereken bazı metrikler:

- Kafka consumer lag
- Replication slot lag
- WAL dosyalarının büyümesi
- Consumer hata oranı
- Failed event sayısı
- Dead-letter queue eventleri
- Hedef sisteme yazma gecikmesi
- Airflow job başarı/başarısızlık durumu

Özellikle Kafka consumer lag çok önemlidir.

Consumer lag şunu gösterir:

Kafka’da üretilen event sayısı ile consumer’ın işlediği event sayısı arasındaki fark.

Eğer lag sürekli artıyorsa consumer yetişemiyor demektir.

Bu durumda şunlar yapılabilir:

- Consumer sayısı artırılabilir
- Topic partition sayısı artırılabilir
- İşleme kodu optimize edilebilir
- Hedef veritabanı yazma performansı iyileştirilebilir
- Batch insert veya bulk write kullanılabilir

Dead Letter Queue Mantığı

Gerçek sistemlerde bazı eventler işlenemeyebilir.

Örneğin:

- JSON formatı bozuk olabilir
- Beklenen alan eksik olabilir
- Hedef veritabanı geçici olarak kapalı olabilir
- Veri tipi uyuşmazlığı olabilir

Bu tür eventleri tamamen kaybetmek yerine ayrı bir Kafka topic’ine göndermek mantıklıdır.

Buna Dead Letter Queue, yani DLQ denir.

Örnek yapı:

orders topic
    ↓
orders consumer
    ↓
başarılıysa → DWH
başarısızsa → orders_dlq topic

Böylece hatalı eventler daha sonra incelenebilir ve tekrar işlenebilir.

Bu, production sistemlerde çok önemli bir pratiktir.

Basit Uçtan Uca Akış

Tüm sistemi sadeleştirirsek uçtan uca akış şöyle olur:

1. PostgreSQL’de veri değişir
2. WAL kaydı oluşur
3. Debezium veya CDC connector WAL’ı okur
4. Değişiklik Kafka topic’ine event olarak yazılır
5. Kafka consumer eventi okur
6. Event doğrulanır ve dönüştürülür
7. Hedef sisteme upsert edilir
8. Başarılı olursa offset commit edilir
9. Hata varsa DLQ’ya gönderilir
10. Monitoring sistemi lag ve hataları takip eder

Bu yapı klasik batch ETL’e göre daha canlı, daha ölçeklenebilir ve daha event-driven bir mimari sunar.

Örnek Mini Mimari

PostgreSQL
  └── WAL
       └── Debezium
             └── Kafka Topic: app_db.public.orders
                    ├── Consumer 1: DWH Sync
                    ├── Consumer 2: Real-time Dashboard
                    ├── Consumer 3: Alert System
                    └── Consumer 4: Data Lake Writer

Bu mimaride tek bir veritabanı değişikliği birden fazla sisteme dağıtılabilir.

Bu, event-driven architecture’ın temel gücüdür.

Bu Yaklaşımın Avantajları

CDC + Kafka mimarisinin başlıca avantajları şunlardır:

- Full table scan ihtiyacını azaltır
- Incremental veri işleme sağlar
- Düşük gecikmeli veri akışı oluşturur
- Birden fazla consumer aynı veriyi kullanabilir
- Data Warehouse daha güncel kalır
- Gerçek zamanlı dashboard ve alarm sistemleri kurulabilir
- Sistemler birbirinden gevşek bağlı hale gelir
- Büyük veri mimarisine geçiş için güçlü bir temel oluşturur

Özellikle operasyonel sistemlerde bu yaklaşım çok değerlidir. Çünkü veri sadece saklanan bir şey olmaktan çıkar, sistemin tepki verebildiği bir event akışına dönüşür.

Dikkat Edilmesi Gereken Noktalar

Bu mimari güçlüdür ama dikkatli tasarlanmalıdır.

Önemli riskler:

- Replication slot tüketilmezse WAL dosyaları diski doldurabilir
- Kafka consumer lag artabilir
- Duplicate eventler oluşabilir
- Schema değişiklikleri consumer’ları bozabilir
- Hedef sisteme yazma performansı darboğaz olabilir
- Exactly-once beklentisi gerçekçi yönetilmelidir

Bu yüzden production ortamda şu konular mutlaka düşünülmelidir:

- Schema evolution
- Idempotent write
- DLQ tasarımı
- Monitoring
- Retry stratejisi
- Offset yönetimi
- Partition strategy
- Backpressure yönetimi

Sonuç

PostgreSQL WAL’dan Kafka’ya CDC pipeline kurmak, modern data engineering mimarilerinde güçlü bir yaklaşımdır.

Bu yapı sayesinde veritabanındaki değişiklikler gerçek zamanlı olarak yakalanabilir, Kafka üzerinden farklı sistemlere dağıtılabilir ve Data Warehouse, dashboard, alarm sistemi veya AI pipeline gibi hedeflere aktarılabilir.

Özetle:

PostgreSQL WAL → CDC Connector → Kafka → Consumer → DWH / Dashboard / Alert / AI

Bu mimari klasik batch ETL’in yerine tamamen geçmek zorunda değildir. Aksine çoğu sistemde batch ve streaming birlikte çalışır.

Batch pipeline geçmiş veriyi işler.

Streaming pipeline ise yeni gelen olaylara hızlı tepki verir.

İyi bir Data Engineer için önemli olan sadece araçları bilmek değildir. Hangi verinin ne zaman, nasıl ve hangi garantiyle taşınacağını tasarlayabilmektir.

CDC + Kafka mimarisi de tam olarak bu noktada güçlü bir çözüm sunar.


메타데이터
post_id
7d97f0e93de4
slug
postgresql-waldan-kafka-ya-cdc-ile-gerçek-zamanlı-veri-pipeline-ı-nasıl-kurulur-7d97f0e93de4
url
https://medium.com/@enesagu/postgresql-waldan-kafka-ya-cdc-ile-ger%C3%A7ek-zamanl%C4%B1-veri-pipeline-%C4%B1-nas%C4%B1l-kurulur-7d97f0e93de4
canonical_url
https://medium.com/@enesagu/postgresql-waldan-kafka-ya-cdc-ile-ger%C3%A7ek-zamanl%C4%B1-veri-pipeline-%C4%B1-nas%C4%B1l-kurulur-7d97f0e93de4
author_url
https://medium.com/@enesagu
status
ok
fetched_at
2026-07-13 06:23:13