Bilgi Bankası
ClickHousePerformans ve kapasite 19 dk 14.06.2026

Analitik event pipeline: PostgreSQL uygulama verisini ClickHouse raporlamasına nasıl ayırırsınız?

Uygulama veritabanı her şeyi taşımaya başladığında raporlama sorguları ürünün kalbini yorar. Analitik eventleri ClickHouse’a ayırmak doğru olabilir; ama event modeli, idempotency ve batch yazma tasarlanmadan yapılan taşıma sadece sorunu başka yere götürür.

Bu yazı sana şu durumda yardımcı olur
  • pano sorguları PostgreSQL üzerinde uygulama trafiğini yavaşlatıyor
  • raporlama için ağır GROUP BY ve tarih aralığı sorguları çalışıyor
  • event tablosu büyüdükçe indeks ve vacuum maliyeti artıyor
  • ClickHouse’a veri yazılıyor ama duplicate eventler oluşuyor
  • tenant bazlı raporlarda okunan satır miktarı gereksiz yükseliyor
Yazıyı bitirince

OLTP ve OLAP ayrımını ne zaman yapmanız gerektiğini, ClickHouse event tablosunu nasıl modelleyeceğinizi ve pipeline tarafında duplicate/veri gecikmesi risklerini nasıl yöneteceğinizi göreceksiniz.

TürkDB açısından ürünleşme notu

Bu bölüm, TürkDB’nin ilgili problemi hangi ürün ilkeleri ve kontrol noktalarıyla ele alacağını anlatır. Kapsam, gerçek iş yükü ve ihtiyaçla birlikte netleşir.

TürkDB PostgreSQL ve ClickHouse’u aynı platform deneyimiyle yönetilebilir hale getirdiğinde ekip iki ayrı operasyon kültürü kurmak zorunda kalmaz. Yine de pipeline kalitesi, event sözleşmesi ve sorgu modeli sizin ürün sorularınızla belirlenir.

Önce neden ayırdığınızı yazın

PostgreSQL’den ClickHouse’a geçmek “raporlar hızlı olsun” diye tek cümleyle verilmemesi gereken bir karardır. Sorun gerçekten analitik okuma yükü mü, yoksa eksik indeks, yanlış sorgu veya eski veri yaşam döngüsü mü? Önce bunu ayırın.

Ayrım doğruysa hedef şudur: uygulamanın transaction yükü PostgreSQL’de kalır, geniş zaman aralıklı okuma ve agregasyon ClickHouse’a gider. Böylece iki motor kendi güçlü olduğu işi yapar.

  • OLTP: sipariş oluşturma, kullanıcı güncelleme, ödeme durumu gibi doğru ve güncel işlem verisi.
  • OLAP: event sayımı, funnel, cohort, pano, uzun tarih aralığı ve yüksek hacimli agregasyon.
  • Ayrım, uygulama doğruluğunu değil raporlama yükünü rahatlatmalıdır.
  • ClickHouse kaynağı değil, okuma modelini hızlandırır; event kalitesi kötü ise sonuç yine kötü olur.

Event sözleşmesini baştan sade tutun

İyi event modeli her şeyi JSON içine atmak değildir. Tenant, event adı, zaman, kullanıcı, kaynak ve idempotency anahtarı gibi alanlar açık kolon olmalıdır. Bu alanlar hem sorgu performansını hem de duplicate temizliğini belirler.

Event payloadı elbette esnek olabilir; ama panoların sürekli filtrelediği alanları payload içinde saklamak ClickHouse’un gücünü azaltır.

ClickHouse event tablosu başlangıcı

clickhouse-events.sql
CREATE TABLE analytics_events
(
  tenant_id String,
  event_id UUID,
  event_name LowCardinality(String),
  user_id String,
  occurred_at DateTime64(3),
  ingested_at DateTime64(3) DEFAULT now64(3),
  source LowCardinality(String),
  payload String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(occurred_at)
ORDER BY (tenant_id, event_name, occurred_at, event_id);

Batch insert küçük fark gibi görünür, büyük fark yaratır

ClickHouse tek tek insert edildiğinde yorulabilir. Pipeline küçük eventleri biriktirip kontrollü batchler halinde yazmalıdır. Batch boyutu çok küçükse part sayısı artar; çok büyükse gecikme ve retry maliyeti artar.

Burada amaç sadece hız değildir. Retry olduğunda aynı event tekrar yazılmasın, yazıldıysa raporda çift sayılmasın. Bunun için event_id veya doğal idempotency anahtarı tasarlanmalıdır.

Basit batch insert fikri

event-writer.ts
const rows = events.map((event) => ({
  tenant_id: event.tenantId,
  event_id: event.id,
  event_name: event.name,
  user_id: event.userId,
  occurred_at: event.occurredAt,
  source: "app",
  payload: JSON.stringify(event.payload),
}))

await clickhouse.insert({
  table: "analytics_events",
  values: rows,
  format: "JSONEachRow",
})

Pano sorgusu tablo tasarımını test eder

Event yazmak kolaydır; doğru okumak daha zordur. En sık kullanılan pano sorgularını erken yazın ve read_rows/read_bytes değerlerini ölçün. Eğer her sorgu tüm tenantları okuyorsa ORDER BY veya filtre modeliniz yanlıştır.

Tenant bazlı funnel sorgusu

pano-funnel.sql
SELECT
  event_name,
  countDistinct(user_id) AS users
FROM analytics_events
WHERE tenant_id = 'acme'
  AND occurred_at >= now() - INTERVAL 30 DAY
  AND event_name IN ('signup', 'ödeme akışı_started', 'payment_completed')
GROUP BY event_name
ORDER BY users DESC;

TürkDB ile iki motoru aynı operasyon ritmine alın

Pipeline kurulduğunda artık iki motor vardır: PostgreSQL uygulama doğruluğunu, ClickHouse analitik hızını taşır. Bunların yedek, erişim, olay ve kapasite yönetimi ayrı ayrı unutulmamalıdır.

TürkDB burada pratik bir kolaylık hedefler: iki motorun bağlantı, yedek ve olay görünürlüğünü aynı arayüzden takip etmek. Bu hedef pilotta çalışırsa özellikle küçük ekiplerde “ClickHouse başka bir ekip bilir” boşluğunu azaltabilir.

OLTP ve OLAP cluster hazırlığı

turkdb-analytics-stack.sh
turkdb cluster create --name app-postgres --engine postgresql --version 16 --region tr-ist-1
turkdb cluster create --name app-clickhouse --engine clickhouse --version 24 --region tr-ist-1

turkdb connect app-postgres --no-tunnel
turkdb connect app-clickhouse --no-tunnel
turkdb backup list app-postgres
turkdb cluster events app-clickhouse --limit 20
Bu TürkDB bloğu kavramsal ürün akışını anlatır; mevcut çalışan komut, garanti edilen özellik veya teslim tarihi vaadi olarak okunmamalıdır.
Devam etmek istersen

Sorunu motor bazında derinleştirin

Benzer belirtiler farklı motorlarda farklı nedenlere dayanır; yayınlanan tüm rehberleri ana sayfadan takip edebilirsiniz.

Tüm makaleler