ClickHouse ile Yüksek Performanslı Analitik Sorguları: Mimariden Optimizasyona

 · 

ClickHouse ile Yüksek Performanslı Analitik Sorguları: Mimariden Optimizasyona

ClickHouse ile Yüksek Performanslı Analitik Sorguları: Mimariden Optimizasyona

Büyük veri setleri üzerinde analitik sorguların milisaniyeler veya saniyeler içinde tamamlanması, modern veri odaklı işletmeler için kritik bir gerekliliktir. Geleneksel ilişkisel veri tabanları bu ölçek ve hız beklentilerini karşılamakta zorlanırken, kolonsal depolama mimarisine sahip veri tabanları öne çıkmaktadır. Yandex tarafından geliştirilen ve açık kaynak olarak sunulan ClickHouse, tam da bu ihtiyaca yönelik, yüksek performanslı bir OLAP (Online Analytical Processing) veri tabanıdır.

ClickHouse'un Temel Mimari Prensipleri

ClickHouse'un performansı, temel mimari kararlarında yatmaktadır:

Kolonsal Depolama

Geleneksel satır tabanlı veri tabanlarının aksine, ClickHouse veriyi kolonlar halinde depolar. Bir sorgu yalnızca belirli kolonlara ihtiyaç duyduğunda, diskten yalnızca bu kolonların verisi okunur. Bu, I/O yükünü dramatik şekilde azaltır ve özellikle geniş tablolarda analitik sorgular için büyük bir avantaj sağlar.

-- Satır tabanlı bir sistemde her kayıt için tüm kolonlar okunur: id, name, value, timestamp
-- Kolon tabanlı bir sistemde sadece istenen kolonlar okunur: value, timestamp
SELECT SUM(value) FROM my_table WHERE timestamp > '2023-01-01';

Bu senaryoda, id ve name kolonları diskten okunmaz, bu da performansı artırır.

Vectorized Query Execution (Vektörleştirilmiş Sorgu Yürütme)

ClickHouse, sorgu yürütme motorunu vektörleştirilmiş işlemler için tasarlamıştır. Bu, verilerin tek tek satırlar yerine, bellek blokları (vektörler) halinde işlenmesi anlamına gelir. CPU önbelleğini daha etkin kullanarak, işlemci tarafından daha hızlı ve verimli bir şekilde işlenmelerini sağlar. Bu yaklaşım, modern CPU mimarilerinin SIMD (Single Instruction, Multiple Data) komut setlerinden maksimum düzeyde faydalanır.

MergeTree Ailesi Motorları

ClickHouse'un en yaygın ve güçlü tablo motoru ailesi MergeTree'dir. MergeTree motorları, veriyi disk üzerinde küçük parçalar (data parts) halinde depolar. Bu parçalar, arka planda otomatik olarak birleştirilir (merge) ve bu işlem sırasında veri sıkıştırma ve dizin oluşturma gibi optimizasyonlar uygulanır. Temel özellikleri şunlardır:

  • Primary Key: Verinin disk üzerindeki fiziksel sıralamasını belirler, arama ve filtreleme işlemlerini hızlandırır.
  • Partitioning Key: Veriyi belirli bir kritere göre (genellikle tarih) bölümlere ayırır. Bu, eski verilerin kolayca silinmesini ve sorguların sadece ilgili bölümleri taramasını sağlar.
  • Sıralama Anahtarı (ORDER BY): Verinin diske yazılırken sıralandığı anahtardır. Primary Key ile aynı veya farklı olabilir.
CREATE TABLE page_views (
    event_time DateTime,
    user_id UInt64,
    page_url String,
    duration_ms UInt32
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time)
ORDER BY (user_id, event_time)
PRIMARY KEY (user_id);

Bu örnekte, veriler ay bazında bölümlenirken, user_id ve event_time'a göre sıralanır ve user_id primary key olarak tanımlanır. Bu yapı, belirli bir kullanıcının belirli bir zaman aralığındaki hareketlerini sorgularken performansı artırır.

Verimli Sorgu Yazımı ve Optimizasyon Teknikleri

ClickHouse'un mimarisi doğal olarak hızlı olsa da, sorguları doğru yazmak ve ek optimizasyon teknikleri uygulamak kritik öneme sahiptir.

1. Partition Pruning (Bölüm Budama)

Sorgularınızda PARTITION BY anahtarını kullanarak tanımladığınız kolonları filtrelemek, ClickHouse'un sadece ilgili veri bölümlerini okumasını sağlar.

-- Yüksek performanslı sorgu: Sadece 2023 yılının Ocak ayı verileri taranır.
SELECT COUNT() FROM page_views WHERE event_time BETWEEN '2023-01-01' AND '2023-01-31';

-- Düşük performanslı sorgu: Tüm partition'lar taranabilir (eğer event_time partition key ise bu durum değişir).
SELECT COUNT() FROM page_views WHERE user_id = 123;

2. Materialized Views (Materyalleştirilmiş Görünümler)

Sıkça kullanılan ve maliyetli aggregate (toplama) sorguları için Materialized Views kullanmak, sorgu sürelerini önemli ölçüde düşürür. Veri eklenirken arka planda önceden hesaplanmış sonuçları saklarlar.

CREATE MATERIALIZED VIEW mv_daily_user_views
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id)
AS
SELECT
    toDate(event_time) AS event_date,
    user_id,
    count() AS total_views
FROM page_views
GROUP BY event_date, user_id;

-- Artık günlük kullanıcı görünümlerini doğrudan MV'den sorgulayabiliriz.
SELECT * FROM mv_daily_user_views WHERE event_date = '2023-01-15';

Bu MV, page_views tablosuna yeni veri eklendikçe otomatik olarak güncellenir ve günlük, kullanıcı bazında toplam görünüm sayısını tutar. Bu, özellikle dashboard ve raporlama senaryolarında çok değerli bir yaklaşımdır.

3. Dizinler ve Skip Indeksler

MergeTree motorları, veriye ek olarak min/max değerleri gibi hafif indeksler de tutar. Ancak, daha karmaşık filtreleme senaryoları için Skip Indeksler kullanılabilir. Örneğin, Bloom Filter dizinleri, bir kolonda belirli bir değerin olup olmadığını hızlıca kontrol etmek için faydalıdır.

CREATE TABLE logs (
    timestamp DateTime,
    level String,
    message String,
    INDEX message_bloom_filter message TYPE bloom_filter GRANULARITY 1
) ENGINE = MergeTree()
ORDER BY timestamp;

-- Bloom filter sayesinde "error" kelimesini içeren mesajlar daha hızlı bulunur.
SELECT COUNT() FROM logs WHERE hasToken(message, 'error');

4. JOIN Optimizasyonları

ClickHouse'ta JOIN işlemleri, genellikle sol taraftaki tablonun tamamının taranmasını gerektirir. Küçük bir tablo ile büyük bir tabloyu birleştirirken, küçük tabloyu sağ tarafa almak (sağ tablo RAM'e alınır) en iyi performansı verir. Ayrıca, GLOBAL IN veya GLOBAL JOIN gibi dağıtık JOIN mekanizmaları da mevcuttur.

-- İyi bir JOIN performansı için, 'users' tablosu 'events' tablosundan küçük olmalı.
SELECT e.event_name, u.username
FROM events AS e
INNER JOIN users AS u ON e.user_id = u.id;

Gerçek Dünya Senaryoları

Senaryo 1: Telekomünikasyon CDR (Call Detail Record) Analizi

Bir telekomünikasyon operatörü, günde milyarlarca çağrı detay kaydı (CDR) üretmektedir. Bu kayıtlar, faturalandırma, ağ optimizasyonu ve dolandırıcılık tespiti için anlık olarak analiz edilmelidir. Her bir CDR kaydı arayan numara, aranan numara, çağrı süresi, başlangıç zamanı, sonlandırma zamanı, hücre ID'si gibi birçok alanı içerir.

CREATE TABLE cdr_data (
    call_id UUID,
    caller_num String,
    callee_num String,
    start_time DateTime,
    end_time DateTime,
    duration_seconds UInt32,
    cell_id String,
    service_type Enum8('voice' = 1, 'sms' = 2, 'data' = 3),
    cost Decimal64(4)
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(start_time)
ORDER BY (caller_num, start_time)
PRIMARY KEY caller_num
SETTINGS index_granularity = 8192;

Bu yapı, start_time'a göre bölümlenmiş ve caller_num ile start_time'a göre sıralanmış bir tablo oluşturur. Böylece belirli bir abonenin çağrı geçmişi veya belirli bir zaman aralığındaki tüm çağrılar hızlıca sorgulanabilir.

-- Belirli bir abonenin son 24 saatteki toplam çağrı süresi
SELECT SUM(duration_seconds)
FROM cdr_data
WHERE caller_num = '5551234567' AND start_time >= now() - INTERVAL 1 DAY;

-- Belirli bir hücre ID'sinden yapılan çağrıların ortalama süresi (son 1 saat)
SELECT AVG(duration_seconds)
FROM cdr_data
WHERE cell_id = 'CELL_XYZ' AND start_time >= now() - INTERVAL 1 HOUR;

Bu sorgular, milyarlarca kayıt arasından saniyeler içinde sonuç döndürebilir, bu da operatörün ağ performansını anlık izlemesini ve anormallikleri hızla tespit etmesini sağlar.

Senaryo 2: Web Analitiği ve Kullanıcı Davranış Takibi

Büyük bir e-ticaret platformu, milyonlarca kullanıcının web sitesi üzerindeki her etkileşimini (sayfa görüntülemeleri, ürün tıklamaları, sepet eklemeleri) kaydetmektedir. Bu verilerin anlık olarak analiz edilmesi, kişiselleştirilmiş öneriler sunmak, pazarlama kampanyalarını optimize etmek ve kullanıcı deneyimini iyileştirmek için gereklidir.

CREATE TABLE website_events (
    event_time DateTime,
    user_id UUID,
    event_type String,
    page_url String,
    product_id UInt64,
    session_id UUID
) ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(event_time)
ORDER BY (user_id, event_time)
PRIMARY KEY user_id;

Günlük bazda bölümlenmiş bu tablo, belirli bir kullanıcının zaman içindeki davranışını veya belirli bir günün olaylarını hızla sorgulamak için optimize edilmiştir.

-- Son bir saat içinde en çok görüntülenen 10 ürün
SELECT product_id, COUNT() AS views
FROM website_events
WHERE event_time >= now() - INTERVAL 1 HOUR AND event_type = 'page_view'
GROUP BY product_id
ORDER BY views DESC
LIMIT 10;

-- Belirli bir kullanıcının son bir haftadaki etkileşim türlerinin dağılımı
SELECT event_type, COUNT()
FROM website_events
WHERE user_id = 'a1b2c3d4-e5f6-7890-1234-567890abcdef' AND event_time >= now() - INTERVAL 7 DAY
GROUP BY event_type;

Bu tür sorgular, platformun A/B test sonuçlarını anlık olarak izlemesine, trendleri belirlemesine ve olası sorunları (örneğin, sepet terk etme oranlarındaki ani artışlar) proaktif olarak ele almasına olanak tanır.

Operasyonel İpuçları ve En İyi Uygulamalar

  • Donanım Seçimi: ClickHouse, yüksek CPU çekirdeği sayısı, bol miktarda hızlı RAM ve NVMe SSD'lerden maksimum fayda sağlar. I/O performansı, kolonsal depolama için kritik öneme sahiptir.
  • Cluster Yapılandırması: Yüksek kullanılabilirlik ve yatay ölçeklenebilirlik için ClickHouse clusterları kullanın. Sharding ve replikasyon, büyük veri setlerini yönetmek için temeldir. ZooKeeper veya ClickHouse Keeper, cluster durumunu yönetmek için kullanılır.
  • Monitoring: Prometheus ve Grafana gibi araçlarla ClickHouse sunucularının ve sorgularının performansını sürekli izleyin. Yavaş sorguları, disk I/O'yu, CPU kullanımını ve bellek tüketimini takip etmek, optimizasyon fırsatlarını belirlemenize yardımcı olur.
  • Veri Tipi Seçimi: Doğru veri tiplerini seçmek (örneğin, UInt8 yerine String kullanmak), hem depolama alanından tasarruf sağlar hem de sorgu performansını artırır.

Sonuç

ClickHouse, doğru mimari anlayışı ve optimizasyon teknikleriyle uygulandığında, petabayt ölçeğindeki veri setleri üzerinde bile inanılmaz derecede yüksek performanslı analitik sorgular sunabilen güçlü bir OLAP veri tabanıdır. Kolonsal depolama, vektörleştirilmiş sorgu yürütme ve MergeTree motorlarının birleşimi, onu büyük veri analitiği dünyasında vazgeçilmez bir araç haline getirmektedir. Gerçek dünya senaryolarında gösterildiği gibi, telekomünikasyondan web analitiğine kadar geniş bir yelpazede, anlık kararlar almayı ve iş süreçlerini optimize etmeyi mümkün kılar.

← Blog Listesine Dön