ClickHouse, milyarlarca satırlık veri üzerinde saniyeler yerine milisaniyeler mertebesinde toplama sorgusu çalıştırmak için tasarlanmış, sütun tabanlı bir analitik veritabanıdır. İhtiyacı genellikle şu sahnede fark edersiniz: MySQL ya da PostgreSQL üzerinde çalışan raporlama sorgunuz aylar içinde önce yavaşlamış, sonra dakikalarca sürmeye başlamıştır. Index eklersiniz, biraz düzelir; veri iki katına çıkar, yine bozulur. Sorun index tasarımı değildir — ilişkisel veritabanları satır satır çalışacak şekilde kurgulanmıştır ve "on milyon satırın şu iki sütununu topla" sorusu onların doğasına aykırıdır.
Bu rehberde ClickHouse'un neden bu kadar hızlı olduğunu, hangi işler için doğru hangi işler için tamamen yanlış olduğunu ve sıfırdan nasıl kurulup ilk tablonun nasıl oluşturulacağını anlatacağım. Sütun tabanlı depolamanın mantığından başlayıp resmî depodan kuruluma, MergeTree tablo motoruna, ORDER BY ve PARTITION BY seçimlerine, toplu veri yüklemeye, TTL ile otomatik saklama politikasına ve materyalize görünümlerle ön toplamaya kadar gideceğiz. Sonda da yeni başlayanların en sık düştüğü tuzaklar var.
ClickHouse Ne İşe Yarar, Ne İşe Yaramaz#
ClickHouse bir OLAP (çevrimiçi analitik işleme) sistemidir. Yani "çok sayıda satırı okuyup az sayıda sonuç üret" tipi sorularda uzmanlaşmıştır: günlük ziyaretçi sayısı, kampanya bazlı ciro, sunucu log analizi, ürün bazında satış toplamı, zaman serisi ölçümleri.
Yapmadığı şey ise klasik uygulama veritabanı olmaktır. Tek satır güncellemek, benzersizlik kısıtı uygulamak, işlem (transaction) içinde birden çok tabloyu tutarlı biçimde değiştirmek — bunlar ClickHouse'un tasarım hedefleri arasında yoktur. Silme ve güncelleme işlemleri "mutasyon" olarak adlandırılır, asenkron çalışır ve maliyetlidir.
| Soru | Uygun sistem |
|---|---|
| Kullanıcı 4821'in profilini getir | İlişkisel veritabanı |
| Sipariş oluştur, stoktan düş, ödeme kaydet | İlişkisel veritabanı (işlem) |
| Son 90 günün günlük cirosunu kanala göre grupla | ClickHouse |
| 2 milyar log satırında hata oranını hesapla | ClickHouse |
| "kabin fanı" için alakalı ürünleri sırala | Arama motoru |
Doğru mimari genellikle ikisini birlikte kullanmaktır: işlem verisi ilişkisel veritabanında durur, analitik kopyası ClickHouse'a akar. İlişkisel tarafta hangi motoru seçeceğinize karar vermediyseniz MySQL ve PostgreSQL karşılaştırması yazısı yardımcı olur.
Sütun Tabanlı Depolama Neden Hızlı#
Klasik bir ilişkisel veritabanı, bir satırın tüm sütunlarını diskte yan yana tutar. SELECT sum(tutar) FROM siparisler sorgusu çalıştığında, yalnızca tutar sütununa ihtiyaç duysanız bile disk her satırın tamamını okumak zorunda kalır — 40 sütunlu bir tabloda okunan verinin yüzde 97'si çöpe gider.
ClickHouse her sütunu ayrı bir dosyada tutar. Aynı sorguda yalnızca tutar dosyası okunur. Bunun üstüne iki kazanç daha biner. Birincisi sıkıştırma: aynı sütundaki değerler birbirine benzediği için (aynı tip, dar aralık, sık tekrar) sıkıştırma oranları çarpıcı biçimde yükselir; on kat ve üzeri oranlar sıra dışı değildir. İkincisi vektörleştirilmiş işleme: veriler bloklar hâlinde okunur ve işlemci her seferinde tek değer yerine bir blok üzerinde çalışır.
Bu üç etkinin birleşimi, "neden bu kadar hızlı" sorusunun tamamıdır. Ama aynı tasarım, tek satır güncellemeyi neden pahalı yaptığını da açıklar: bir satırı değiştirmek, o satırın parçası olduğu tüm sütun bloklarının yeniden yazılması demektir.
Kurulum: Depo, Paketler ve İlk Bağlantı#
Resmî depodan kurmak en sağlıklısıdır; dağıtım depolarındaki sürümler genellikle çok geridir.
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg
# İmzalama anahtarı
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
# Depo tanımı
echo 'deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main' \
| sudo tee /etc/apt/sources.list.d/clickhouse.list
sudo apt update
sudo apt install -y clickhouse-server clickhouse-client
Kurulum sırasında default kullanıcısı için bir parola sorulur. Boş bırakmayın; boş parolayla kurulmuş bir ClickHouse, ağ ayarları yanlışsa doğrudan açık kapıdır. Ardından servisi başlatın:
sudo systemctl enable --now clickhouse-server
sudo systemctl status clickhouse-server --no-pager
# İstemciyle bağlan
clickhouse-client --password
# İlk sorgu
SELECT version(), uptime();
Sunucu açılmıyorsa günlüklere bakın; ClickHouse hata mesajlarında oldukça açıktır:
sudo tail -n 50 /var/log/clickhouse-server/clickhouse-server.err.log
En sık karşılaşılan iki açılış hatası, yetersiz dosya tanıtıcısı sınırı ve dizin izinleridir. Veri dizininin (/var/lib/clickhouse) clickhouse kullanıcısına ait olduğundan emin olun.
Temel Yapılandırma ve Portlar#
Ana yapılandırma /etc/clickhouse-server/config.xml dosyasındadır ama bu dosyayı doğrudan düzenlememeniz önerilir; paket güncellemeleri onu değiştirebilir. Bunun yerine config.d/ ve users.d/ dizinlerine küçük üstyapı dosyaları koyun.
# /etc/clickhouse-server/config.d/dinleme.xml
sudo tee /etc/clickhouse-server/config.d/dinleme.xml > /dev/null << 'XMLSON'
<clickhouse>
<listen_host>127.0.0.1</listen_host>
<listen_host>10.0.0.5</listen_host>
<max_connections>512</max_connections>
</clickhouse>
XMLSON
sudo systemctl restart clickhouse-server
ClickHouse birden fazla protokol üzerinden hizmet verir; hangisinin ne olduğunu bilmek güvenlik duvarı kurallarını doğru yazmanızı sağlar.
| Port | Protokol | Kullanım |
|---|---|---|
| 8123 | HTTP | curl, JDBC, çoğu istemci kütüphanesi |
| 9000 | Yerel TCP | clickhouse-client, en verimli yol |
| 9009 | Sunucular arası | Replikasyon trafiği |
| 9004 | MySQL uyumluluğu | MySQL istemcileriyle bağlanma |
| 9005 | PostgreSQL uyumluluğu | Postgres istemcileriyle bağlanma |
Kullanıcı ve yetki tanımları users.d/ altına yazılır. Uygulamanız için salt okunur bir kullanıcı oluşturmak iyi bir alışkanlıktır:
sudo tee /etc/clickhouse-server/users.d/rapor.xml > /dev/null << 'XMLSON'
<clickhouse>
<users>
<rapor>
<password_sha256_hex>BURAYA_SHA256_OZETI</password_sha256_hex>
<networks><ip>10.0.0.0/24</ip></networks>
<profile>readonly</profile>
<quota>default</quota>
</rapor>
</users>
</clickhouse>
XMLSON
Parola özetini şöyle üretirsiniz:
echo -n 'GucluBirParola' | sha256sum | tr -d ' -'
İlk Tablo: MergeTree, ORDER BY ve PARTITION BY#
ClickHouse'da tablo motoru seçimi, davranışı belirleyen en önemli karardır. Üretimde neredeyse her zaman MergeTree ailesinden birini kullanırsınız.
CREATE DATABASE IF NOT EXISTS analitik;
CREATE TABLE analitik.olaylar
(
zaman DateTime,
tarih Date DEFAULT toDate(zaman),
musteri_id UInt32,
olay LowCardinality(String),
kanal LowCardinality(String),
tutar Decimal(12, 2),
ulke LowCardinality(FixedString(2)),
oturum_id UUID
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(tarih)
ORDER BY (musteri_id, zaman)
TTL tarih + INTERVAL 24 MONTH DELETE
SETTINGS index_granularity = 8192;
Bu tanımdaki dört karar hayatidir.
ORDER BY, ClickHouse'un birincil index'idir. İlişkisel veritabanlarındaki gibi ayrı bir index nesnesi yoktur; veri diskte bu sıraya göre fiziksel olarak yazılır ve seyrek bir index üzerinden aranır. Sorgularınızda en sık filtrelediğiniz sütunları, seçiciliği düşük olandan yükseğe doğru buraya yazın. Yanlış ORDER BY, ClickHouse'da yavaşlığın bir numaralı sebebidir.
PARTITION BY bölümleme sağlar ama index değildir. Genellikle aya göre bölümlemek doğru seçimdir; böylece eski verinin silinmesi tek bir dosya grubunu düşürmek kadar ucuz olur. Çok ince bölümleme (örneğin güne göre, üstelik uzun saklama süresiyle) binlerce küçük parça üretir ve performansı düşürür.
LowCardinality, az sayıda farklı değer alan metin sütunları için sözlük kodlaması yapar. kanal, olay, ulke gibi sütunlarda hem depolama hem sorgu tarafında ciddi kazanç sağlar. Milyonlarca farklı değer alan sütunlarda ise ters etki yapar, kullanmayın.
TTL, satırların ne kadar yaşayacağını tanımlar. Log ve olay verisinde diskin dolmasını önlemenin en temiz yoludur ve elle temizlik betiği yazma ihtiyacını ortadan kaldırır.
Aynı satırın tekrar yazılması durumunda son sürümü tutmak istiyorsanız ReplacingMergeTree kullanılır; ancak birleştirme (merge) asenkron çalıştığı için tekilleştirmenin anında olmadığını bilerek tasarlayın:
CREATE TABLE analitik.musteri_son_durum
(
musteri_id UInt32,
guncelleme DateTime,
durum LowCardinality(String)
)
ENGINE = ReplacingMergeTree(guncelleme)
ORDER BY musteri_id;
-- Sorgu anında kesin tekilleştirme için
SELECT * FROM analitik.musteri_son_durum FINAL WHERE musteri_id = 4821;
Veri Yükleme ve Sorgu Örnekleri#
ClickHouse'a veri yüklerken tek kural vardır ve en sık ihlal edilen kural budur: toplu yükleyin. Her satır için ayrı bir INSERT göndermek, ClickHouse'un en kötü kullanım biçimidir; her ekleme diskte yeni bir parça oluşturur ve arka plandaki birleştirme süreci yetişemez hâle gelir.
# CSV dosyasından toplu yükleme
clickhouse-client --password --query \
"INSERT INTO analitik.olaylar FORMAT CSVWithNames" < /tmp/olaylar.csv
# Sıkıştırılmış dosyadan doğrudan
gzip -dc /tmp/olaylar.csv.gz | clickhouse-client --password --query \
"INSERT INTO analitik.olaylar FORMAT CSVWithNames"
# HTTP arayüzü üzerinden JSON satırları
curl -s 'http://localhost:8123/?query=INSERT%20INTO%20analitik.olaylar%20FORMAT%20JSONEachRow' \
-u default:PAROLA --data-binary @/tmp/olaylar.ndjson
Uygulamanız satır satır olay üretiyorsa, ya kendi tarafınızda tampon tutup binlerce satırlık gruplar hâlinde gönderin ya da ClickHouse'un asenkron ekleme özelliğini açın; ikincisi, tamponlamayı sunucu tarafına devreder:
SET async_insert = 1, wait_for_async_insert = 0;
Analitik sorgular tanıdık SQL'dir, ancak ClickHouse'un kendi fonksiyonları işi çok kolaylaştırır:
-- Son 30 günün günlük cirosu, kanal bazında
SELECT
toDate(zaman) AS gun,
kanal,
count() AS olay_sayisi,
sum(tutar) AS ciro,
uniqExact(musteri_id) AS tekil_musteri
FROM analitik.olaylar
WHERE zaman >= now() - INTERVAL 30 DAY
AND olay = 'satin_alma'
GROUP BY gun, kanal
ORDER BY gun DESC, ciro DESC;
-- Yaklaşık tekil sayım: çok daha hızlı, milyarlarca satırda tercih edilir
SELECT uniq(musteri_id) FROM analitik.olaylar WHERE tarih >= today() - 7;
uniq yaklaşık, uniqExact kesin sonuç verir. Milyarlarca satırda uniqExact ciddi bellek tüketir; kabaca bir gösterge yeterliyse uniq kullanın. Sorgunuzun ne kadar veri okuduğunu görmek için:
EXPLAIN indexes = 1
SELECT count() FROM analitik.olaylar WHERE musteri_id = 4821 AND zaman >= now() - INTERVAL 7 DAY;
Sıkıştırma, Materyalize Görünümler ve İzleme#
Varsayılan sıkıştırma hızlıdır ama daha yüksek oran istiyorsanız sütun bazında codec belirleyebilirsiniz. Zaman serisi sütunlarında özel codec'ler dramatik fark yaratır:
ALTER TABLE analitik.olaylar
MODIFY COLUMN zaman DateTime CODEC(Delta, ZSTD(3));
Delta, ardışık zaman damgaları arasındaki farkı saklar; küçük sayılar çok daha iyi sıkışır. Etkiyi ölçmek için sistem tablolarına bakın:
SELECT
name,
formatReadableSize(sum(data_compressed_bytes)) AS sikistirilmis,
formatReadableSize(sum(data_uncompressed_bytes)) AS ham,
round(sum(data_uncompressed_bytes) / sum(data_compressed_bytes), 1) AS oran
FROM system.columns
WHERE database = 'analitik' AND table = 'olaylar'
GROUP BY name
ORDER BY sum(data_compressed_bytes) DESC;
Aynı toplama sorgusunu her seferinde baştan hesaplamak yerine, materyalize görünümle ekleme anında hesaplatabilirsiniz. Bu, gösterge panolarını milisaniyelere indiren en etkili tekniktir:
CREATE TABLE analitik.gunluk_ozet
(
gun Date,
kanal LowCardinality(String),
ciro AggregateFunction(sum, Decimal(12, 2)),
tekil AggregateFunction(uniq, UInt32)
)
ENGINE = AggregatingMergeTree
ORDER BY (gun, kanal);
CREATE MATERIALIZED VIEW analitik.gunluk_ozet_mv TO analitik.gunluk_ozet AS
SELECT
toDate(zaman) AS gun,
kanal,
sumState(tutar) AS ciro,
uniqState(musteri_id) AS tekil
FROM analitik.olaylar
GROUP BY gun, kanal;
-- Okurken durumları birleştirin
SELECT gun, kanal, sumMerge(ciro) AS ciro, uniqMerge(tekil) AS tekil
FROM analitik.gunluk_ozet
GROUP BY gun, kanal
ORDER BY gun DESC;
⚠️ Materyalize görünüm yalnızca kendisinden sonra eklenen satırları görür; geçmiş veriyi doldurmak için ayrıca bir INSERT SELECT çalıştırmanız gerekir. Bu, yeni başlayanların en çok şaşırdığı davranıştır.
İzleme için sistem tabloları fazlasıyla yeterlidir:
-- En yavaş son sorgular
SELECT query_duration_ms, read_rows, formatReadableSize(memory_usage) AS bellek, substring(query, 1, 120)
FROM system.query_log
WHERE type = 'QueryFinish' AND event_time >= now() - INTERVAL 1 HOUR
ORDER BY query_duration_ms DESC LIMIT 10;
-- Parça sayısı: bölüm başına yüzlerce parça varsa toplu yükleme deseniniz bozuk demektir
SELECT table, partition, count() AS parca
FROM system.parts WHERE active AND database = 'analitik'
GROUP BY table, partition ORDER BY parca DESC LIMIT 10;
Sık Yapılan Hatalar#
- Satır satır
INSERTgöndermek. Her ekleme yeni bir parça yaratır; birleştirme süreci yetişemez ve sonunda "too many parts" hatası alırsınız. Binlerce satırlık gruplar hâlinde yükleyin ya da asenkron eklemeyi açın. ORDER BYseçimini önemsememek. Bu, ClickHouse'un birincil index'idir. Sorgularınızın filtre desenine uymuyorsa tablo taraması yaparsınız ve sütun tabanlı olmanın avantajını büyük ölçüde kaybedersiniz.- Aşırı ince bölümleme. Güne göre bölümlenmiş ve iki yıl saklanan bir tablo, yedi yüzden fazla bölüm demektir. Aya göre bölümleme çoğu durumda doğru ölçüdür.
- ClickHouse'u uygulama veritabanı sanmak. Tek satır güncelleme, benzersizlik kısıtı ve işlem garantisi burada yoktur. Sipariş ve ödeme verisi ilişkisel veritabanında kalmalı, ClickHouse'a kopyalanmalıdır.
SELECT *alışkanlığı. Sütun tabanlı bir sistemde her ek sütun, okunan veri hacmini doğrudan büyütür. Yalnızca ihtiyacınız olan sütunları seçin; buradaki kazanç ilişkisel veritabanlarındakinden çok daha büyüktür.- Belleği sınırsız bırakmak. Büyük toplama sorguları belleği tüketebilir.
max_memory_usagevemax_bytes_before_external_group_byayarlarıyla profil bazında sınır koyun.
Sıkça Sorulan Sorular#
ClickHouse MySQL'in yerini alır mı#
Hayır, ikisi farklı işler için tasarlanmıştır. MySQL tek satır okuma-yazma, işlem bütünlüğü ve benzersizlik kısıtları konusunda güçlüdür; ClickHouse ise çok sayıda satırı okuyup toplama üretmek konusunda. Doğru mimari genellikle ikisini birlikte kullanmaktır: işlem verisi MySQL'de kalır, analitik kopyası ClickHouse'a akar ve raporlar oradan çalışır.
ClickHouse ücretsiz mi#
Evet, ClickHouse Apache 2.0 lisanslı açık kaynak bir projedir ve kendi sunucunuzda ücretsiz çalıştırabilirsiniz. Ticari destek ve yönetilen bulut servisi ayrıca sunulur ama zorunlu değildir. Kurulum tek bir apt komutuyla yapılır, ek bileşen ya da lisans anahtarı gerektirmez.
Ne kadar donanım gerekir#
Küçük bir başlangıç için 4 çekirdek ve 16 GB bellek makul bir zemindir; ClickHouse tek sunucuda milyarlarca satırla çalışabilir. Belirleyici olan iki şey vardır: disk hızı ve çekirdek sayısı. Toplama sorguları çekirdekleri paralel kullanır, bu yüzden çekirdek eklemek doğrudan hız kazandırır. Diskte NVMe kullanmak, dönen diske göre çarpıcı fark yaratır.
Veriyi ClickHouse'a nasıl aktarırım#
En yaygın yol, kaynağınızdan CSV ya da JSON satırları üretip toplu olarak INSERT ... FORMAT ile yüklemektir. Sürekli akış için mesaj kuyruğundan besleyen tablo motorları ve düzenli aralıklarla çalışan aktarım işleri kullanılır. Hangi yolu seçerseniz seçin, satır satır değil gruplar hâlinde yazın; ClickHouse'un tek gerçek kırmızı çizgisi budur.
Silme ve güncelleme yapabilir miyim#
Yapabilirsiniz ama pahalıdır ve anlık değildir. ALTER TABLE ... DELETE ve ALTER TABLE ... UPDATE komutları mutasyon olarak adlandırılır, arka planda çalışır ve etkilenen veri parçalarını yeniden yazar. Bu yüzden ClickHouse'u sık güncellenen veri için değil, yazıldıktan sonra çoğunlukla değişmeyen olay ve ölçüm verisi için kullanın. Eski veriyi temizlemenin doğru yolu ise TTL tanımlamaktır.
Yüksek erişilebilirlik nasıl sağlanır#
Replikasyon için ReplicatedMergeTree motoru ve bir koordinasyon servisi kullanılır; her tablo birden fazla düğümde kopya tutar ve düğümlerden biri kaybolduğunda veri erişilebilir kalır. Yatay ölçekleme içinse Distributed motoruyla veri birden fazla parçaya bölünür. Bunlar ek işletim yükü getirir; tek sunucu kapasitesi yeterliyken kurmak için acele etmeyin.
Kapanış#
ClickHouse, doğru soruya uygulandığında olağanüstü sonuç veren, yanlış soruya uygulandığında ise sizi zorlayan bir araçtır. Aklınızda kalması gereken dört alışkanlık: onu uygulama veritabanı değil analitik katman olarak konumlandırın, ORDER BY seçimini gerçek sorgu desenlerinize göre yapın, veriyi asla satır satır değil toplu gruplar hâlinde yazın ve saklama süresini TTL ile baştan tanımlayın. Gösterge panolarınız yavaşlamaya başladığında ise materyalize görünümlerle ön toplama yapmak, donanım eklemekten çok daha etkilidir.
Analitik iş yükleri diskten ve çekirdekten cömertçe faydalanır; paylaşımlı ortamda ölçüm yapmak yanıltıcı olur. Kendi ClickHouse örneğinizi tam kaynak garantisiyle çalıştırmak için VDS ve bulut sunucu paketlerimize, yüksek hacimli veri setleri için dedicated sunucu seçeneğine göz atabilirsiniz. Kurulum, sıkılaştırma ve izleme yükünü devretmek isterseniz sunucu yönetimi hizmetimiz bu işi üstlenir, veri güvenliği tarafını yedekleme çözümümüzle tamamlayabilirsiniz.