Modern streaming mimarileri, milyonlarca mesajı saniyede işleyerek dayanıklı kalıcılık ve yatay ölçeklenebilirlik sağlayan Apache Kafka'yı dağıtılmış olay omurgası olarak kullanır. Apache Flink, karmaşık olay zamanı işleme yetenekleri ile gerçek streaming semantiği sağlayan akış işleme motoru olarak kullanılmakta ve Kafka işlemleri ile koordine olarak tüm boru hattında tam bir kez teslim sağlamak için kullanılır. Durum yönetimi, aşamalı asenkron anlık görüntüler ile Amazon S3'e yedekleme yapan RocksDB gömülü arka uçlarla sağlanmakta, terabayt ölçeğinde durumlu işlemler JVM yığın belleğini tüketmeden gerçekleştirilmektedir. Hızlı uyarılar için, sıcak toplama sonuçları Redis'de gerçekleştirilirken, tarihsel veriler maliyet etkin analitik sorgular için Apache Iceberg tabloları aracılığıyla S3 Glacier'a akmaktadır.
Akıllı bir enerji dağıtım şirketi, saniyede on bin olay üreten iki milyon akıllı ölçere göz kulak olmaktadır ve güç şebekesi anomallerini 500 milisaniye içerisinde tespit etmektedir ki bu da kütlesel arızaları önlemek için gereklidir. Temel zorluk, hücresel ağ bölünmeleri nedeniyle beş dakikaya kadar gecikebilen olayları işlemek, sayaçın yeniden deneme mantığından gelen kopyaları ortadan kaldırmak ve yüksek hızda telemetriyi yavaş değişen referans verileri ile birleştirmeyi gerektirmektedir. Mühendisler daha önce sıralı olmayan olaylardan ve zirve yükleri sırasında veri kaybından kaynaklanan yanlış pozitif sonuçlarla mücadele ettiler, bu nedenle gerçek zamanlı yanıt vermeden ödün vermeden doğruluğu koruyan sağlam bir mimariye ihtiyaçları vardı.
Çözüm 1: Spark Streaming ve Batch ile Lambda Mimarisi
Başlangıç önerisi, bir Lambda Mimarisi modeli benimsedi. Apache Spark Streaming, yaklaşık gerçek zamanlı görünümler için hız katmanını sağlarken, her gece Spark SQL batch işleri, önceki 24 saat için kesin sonuçları yeniden hesapladı.
Artılar: Gelişmiş araçlarla olgun bir ekosistem, HDFS çoğaltma yoluyla basit hata dayanıklılığı ve hız katmanı ile batch katmanı arasında net bir ayrım.
Eksiler: Streaming ve batch mantığı arasındaki kod çoğaltımı önemli bir bakım yükü ve senkronizasyon hataları oluşturur. Her gün terabaytları yeniden işlemenin yüksek hesaplama maliyetleri vardır ve batch gecikmesi nedeniyle alt saniye anomali düzeltme gereksinimini ihlal eder.
Çözüm 2: Gömülü Depolar ile Kafka Streams
İkinci tasarım, uygulama pod'larında doğrudan çalışan gömülü RocksDB durum depoları ile Kafka Streams'i dikkate aldı.
Artılar: Ayrı işleme kümeleri olmadan basit işletim topolojisi, Kafka'nın tüketici grupları ile sıkı yerel entegrasyon ve otomatik bölüm atama yönetimi.
Eksiler: Durumlu işlemlerin ölçeklenmesi, tüm bölümlerin pahalı yeniden dengelemesini tetikleyerek önemli gecikme patlamalarına neden olur. Sıralı olmayan olayları işlemek, varsayılan pencereleme olay zamanından ziyade işlem zamanına dayandığı için karmaşık özel zaman damgası çıkarma mantığı gerektirir. Uygulama sunucularındaki bellek kısıtlamaları toplam durum boyutunu ciddi şekilde sınırlar, büyük pencere toplamalarının önüne geçer.
Çözüm 3: Olay Zamanı Semantik ile Apache Flink
Seçilen mimari, Kubernetes üzerinde Apache Flink konuşlandırarak, olay zamanı işleme semantiklerini, su işaretleri ve dışsal aşamalı kontrol noktaları ile Amazon S3'e entegre etti.
Artılar: Su işaretleri ve allowedLateness yapılandırmaları aracılığıyla yerel olay zamanı işleme özelliği, özel mantık gerektirmeden sıralı olmayan verileri işler. Tam bir kez işleme, Flink kontrol noktaları ile Kafka işlemleri arasında iki aşamalı taahhütler aracılığıyla sağlanır. RocksDB aşamalı anlık görüntüleri, bellek baskısı olmaksızın terabayt ölçeğinde anahtar bazlı pencerelerin bağımsız ölçeklenmesini destekler.
Eksiler: Önemli bir işletim karmaşıklığı, kontrol noktası ayarlama, su işareti hizalama ve geri basınç yönetimi konusunda derin bir uzmanlık gerektirir. Flink JobManager, yüksek kullanılabilirlik yapılandırmalarına ihtiyaç duyan potansiyel bir tek hata noktasıdır.
Seçilen Çözüm ve Sonuç
Çözüm 3'ü benimsedik, Flink'in BoundedOutOfOrdernessWatermarks yapılandırmasını beş dakikalık bir tolerans ile ve her 30 saniyede bir RocksDB aşamalı kontrol noktaları ile yapılandırdık. Kopyaların ortadan kaldırılması, Flink'in iki aşamalı taahhüt protokolü ile koordine edilen Kafka'nın idempotent üreticilerini ve işlemci durumunu son başarılı kontrol noktasından geri yüklemeyi etkinleştirerek sağlandı. S3 Glacier'ye veri katmanlama, sorgulanabilir tarihsel veri setlerini aşırı depolama maliyetleri olmadan korumak için Apache Iceberg sıkıştırma stratejileri kullandı.
Bu yapı, üretim denemeleri sırasında 300ms p99 uyarı gecikmesi ve %99.99 işleme doğruluğu sağladı. Sistem, kontrol noktası geri yüklemesi sonrası Kafka kayıtlardan tekrar oynatma yaparak üç saatlik bir hücresel ağ kesintisini nazikçe yönetti, sıfır veri kaybı ile. Depolama maliyetleri, önceki HDFS çözümüne göre %60 azaldı, Grafana panoları Flink'in su işareti gecikmesi ve kontrol noktası süresi metriklerine gerçek zamanlı görünürlük sağladı.
Soru: Apache Flink, Kafka'ya batarken nasıl tam bir kez semantiği korur ve iş yeniden başlatmaları sırasında tekrar yazılmasını ne önler?
Flink, kontrol noktası bariyeri ile Kafka işlemi arasında bir iki aşamalı taahhüt protokolü ile tam bir kez işleme gerçekleştirir. Ön taahhüt aşamasında veriler, benzersiz bir transactional.id kullanılarak Kafka'ya boşaltılır ancak kontrol noktası başarıyla tamamlanana kadar onaylanmamış kalır. Eğer kontrol noktası başarısız olursa, Flink işlemi iptal eder ve Kafka verileri atar; yeniden başlatıldığında, Flink, tamamlanmamış yazımlardan kaçınmak için en son başarılı kontrol noktasından üretici durumunu geri yükler. Adaylar genellikle transactional.id'nin yeniden başlatmalar arasında idempotentliği sağlamak için kontrol noktası kimliğini içermesi gerektiğini ve Flink'in çok kiracılı Kafka kümelerinde çarpışmaların önlenmesi için setTransactionalIdPrefix yapılandırmasına ihtiyaç duyduğunu gözden kaçırır.
Soru: Olay zamanında pencereleme, anahtar bazındaki işlemlerde durum patlamasına neden olur, ve bunu sınırsız cihaz ID'lerini işlerken nasıl azaltırsınız?
Olay zamanında pencereleme, Flink'in su işareti pencere bitiş zamanını ve yapılandırılmış allowedLateness süresini geçene kadar her anahtar için tüm olayları tamponlaması gerektiğinden durum patlamasına neden olur. Benzersiz cihaz tanımlayıcıları gibi yüksek kardinaliteli anahtarlar için, bu milyonlarca eşzamanlı pencere durumunu RocksDB'de biriktirir, en sonunda tüm mevcut disk ve bellek kaynaklarını tüketir. Azaltma, eski pencerelerin otomatik olarak sona ermesini sağlamak için State TTL (Zaman-Aşımı) yapılandırmaları uygulamayı, dış bellek kullanımını sınırlandırmak için RocksDB bellek yönetimli tamponları yapılandırmayı ve anlık görüntü aşırılığını azaltmak için aşamalı kontrol noktaları kullanmayı gerektirir. Adaylar, belirgin bir pencere tahliyeleri ya da TTL ayarları olmadan, durum arka ucunun, özellikle geç gelen tarihsel verileri işlerken, sonsuz büyüyeceğini sık sık gözden kaçırır.
Soru: Tek bir arızalı IoT cihazı 100 kat normal olay hacmi ürettiğinde sıcak anahtar dengesizliğini nasıl çözersiniz ve belirli bir Flink alt görevini aşırı yükler?
Sıcak anahtar dengesizliği, bölüm hashing'in yüksek hacimli anahtarları tek görev örneklerine yoğunlaştırması sonucu oluşarak boru hattı boyunca geri basınç ve gecikme patlamalarına neden olur. Çözüm, başlangıç karışıklığı sırasında sıcak anahtarlara rasgele bir ek (örn. 0-9) ekleyerek çoklu alt görevler arasında iş yükünü dağıtmak ve ardından eki kaldırarak sonuçları bir sonraki genel pencerede yeniden toplamak olan anahtar tuzlamayı içerir. Alternatif olarak, şişme ağ trafiğini azaltmak için karıştırmadan önce Flink'in AggregateFunction kullanarak yerel anahtar ön toplamasını uygulayabilirsiniz veya belirli üreticileri zayıflatmak için Kafka'nın yapışkan bölümlendirmesini kullanabilirsiniz. Adaylar genellikle tuzlamanın ağ karışıklık hacmini ve durum boyutunu artırdığını, bu nedenle rasgele anahtarları yönetmenin maliyeti ile paralellik kazanma arasında dikkatli bir denge gerektirdiğini gözden kaçırır.