1. Too many parts aslında ne söylüyor?
ClickHouse her INSERT ile tabloya yeni partlar yazar. Arka planda merge işlemleri bu partları birleştirir. Eğer saniyede çok fazla küçük INSERT gönderirseniz merge işlemleri yetişemez; aynı partition altında part sayısı büyür ve sistem size aslında “beni çok küçük lokmalarla besliyorsun” demeye başlar.
Bu sorun genellikle “daha çok worker açalım” refleksiyle kötüleşir. Worker sayısı artınca batch büyümüyor, yalnızca küçük INSERT sayısı artıyorsa ClickHouse daha fazla part üretir.
Partition bazında aktif part sayısı
SELECT database, table, partition, count() AS active_parts, sum(rows) AS rows, formatReadableSize(sum(bytes_on_disk)) AS size FROM system.parts WHERE active AND database = 'default' GROUP BY database, table, partition HAVING active_parts > 50 ORDER BY active_parts DESC LIMIT 20;
Merge kuyruğunu kontrol etme
SELECT database, table, elapsed, progress, num_parts, formatReadableSize(total_size_bytes_compressed) AS compressed FROM system.merges ORDER BY elapsed DESC LIMIT 20;
2. Çözüm: küçük INSERT yerine kontrollü batch
ClickHouse OLTP veritabanı gibi tek tek satır yazmak için tasarlanmamıştır. Daha az sayıda, daha büyük batch genellikle daha sağlıklıdır. Pratik başlangıç noktası olarak binlerce satırlık veya birkaç MB boyutlu batchler denenebilir; ideal değer event boyutuna ve gecikme beklentisine göre ölçülür.
Uygulama tarafında kısa süreli buffer kullanmak, Kafka tüketicilerinde flush aralığı belirlemek veya ClickHouse async insert ayarlarını bilinçli kullanmak part sayısını azaltır.
Node.js tarafında basit batch mantığı
const buffer: EventRow[] = []
const maxRows = 5000
const maxWaitMs = 1000
let lastFlush = Date.now()
export async function enqueue(row: EventRow) {
buffer.push(row)
const shouldFlush = buffer.length >= maxRows || Date.now() - lastFlush >= maxWaitMs
if (!shouldFlush) return
const batch = buffer.splice(0, buffer.length)
lastFlush = Date.now()
await clickhouse.insert({
table: 'events',
values: batch,
format: 'JSONEachRow',
})
}Amaç tek tek INSERT göndermek yerine ölçülebilir büyüklükte batch yazmaktır. Batch büyüklüğü p95 ingest gecikmesi ve part sayısı birlikte izlenerek ayarlanmalıdır.
3. Partition tasarımı insert yükünü etkiler
Partition çok ince seçilirse aynı anda çok sayıda partitiona küçük part yazılır. Örneğin saatlik partition düşük hacimde bile part sayısını şişirebilir. Çok yüksek hacimli event sistemlerinde günlük partition mantıklı olabilir; daha düşük hacimde aylık partition genellikle daha sakindir.
Partition kararı yalnızca sorgu filtresine göre verilmez. Veri yaşam döngüsü, drop/TTL ihtiyacı ve günlük yazma hacmi birlikte değerlendirilmelidir.
- Aynı anda kaç partitiona yazdığınızı ölçün.
- Her partition altında aktif part sayısını izleyin.
- Batchleriniz tek partitiona mı, çok sayıda partitiona mı dağılıyor anlayın.
- Saatlik partition kullanmadan önce gerçekten drop/TTL ihtiyacınız olup olmadığını sorgulayın.
4. Düzeltmeden sonra hangi metrikler iyileşmeli?
Batch düzenlemesi doğruysa aktif part sayısı zamanla düşmeli, system.merges kuyruğu sakinleşmeli ve INSERT p95 süresi stabil hale gelmelidir. SELECT sorguları da daha az part gezdiği için dolaylı olarak rahatlar.
Kapasite artırımı bu noktadan sonra değerlendirilmelidir. Küçük batch sorunu çözülmeden daha büyük makineye geçmek yalnızca merge baskısını daha pahalı çalıştırır.
TürkDB ile operasyonel kontrol
turkdb cluster get product-analytics turkdb cluster events product-analytics --limit 20 turkdb connect product-analytics
Bu komutlar kavramsal kontrol akışını gösterir. Part/merge teşhisi yine ClickHouse sistem tablolarıyla yapılmalıdır.