Data Engineering

Beyan Edici Akış İşleme Mantığı Yazma: Flink SQL ve Kafka Streams DSL'ye Pratik Bir Rehber

Gerçek zamanlı veri işleme, karmaşık bir emperatif kodlama zorluğundan daha yapılandırılmış, beyan edici bir disipline evrildi. Veri mühendisleri için karmaşık akış mantığını özlü bir şekilde ifade etme yeteneği artık sadece bir lüks değil; ölçeklenebilir mimarileri sürdürmek için bir zorunluluktur. İki önde gelen çerçeve, Apache Flink ve Kafka Streams, güçlü beyan edici arayüzler sunarak bu değişimi benimsemiştir: Flink SQL ve Kafka Streams DSL (Alan-Spesifik Dil).

Bu rehber, daha temiz ve sürdürülebilir akış işleme uygulamaları yazmak için bu beyan edici yaklaşımlardan nasıl faydalanılacağını inceler. Her iki aracın semantik yeteneklerini karşılaştıracağız ve farklı güçlü yönlerini vurgulamak için pratik kod örnekleri sunacağız.

Beyan Edici Mantığın Gücü

Emperatif akış işleme, geliştiricileri genellikle durumu, zaman semantiğini ve pencerelemeyi manuel olarak yönetmeye zorlar. Bu düşük seviyeli kontrol güçlüdür ancak okunabilirlik ve sürdürülebilirlik maliyetiyle gelir. Buna karşılık, beyan edici mantık, verinin adım adım nasıl dönüştürüleceğinden ziyade verinin nasıl görünmesi gerektiğine odaklanır.

Durum yönetimi ve olay zamanı işleme karmaşıklığını soyutlayarak, beyan edici arayüzler ekiplere iş mantığına odaklanma imkanı tanır. Bu, veri boru hatlarının denetlenebilir olması ve derin Java veya Scala uzmanlığına sahip olmayan veri analistleri tarafından kolayca anlaşılması gereken büyük kuruluşlarda özellikle faydalıdır.

Apache Flink SQL: Birleşik Sorgu Katmanı

Apache Flink, SQL'i birinci sınıf bir vatandaş olarak konumlandırmış ve akış ile toplu işlemleri eşit şekilde ele almıştır. Flink SQL, Kafka konularını, HDFS dosyalarını veya JDBC veritabanlarını temsil eden tablolar tanımlamanıza ve bunları statik ilişkisel tablolar gibi sorgulamanıza olanak tanır. Motor, arka planda akış semantiğini otomatik olarak yönetir.

5 dakikalık kayan bir pencere boyunca API isteklerinin ortalama gecikmesini hesaplamanız gereken bir senaryoyu düşünün. Flink SQL'de bu basittir:


CREATE TABLE api_logs (
    request_id STRING,
    user_id STRING,
    latency_ms INT,
    timestamp TIMESTAMP(3),
    WATERMARK FOR `timestamp` AS `timestamp` - INTERVAL '5' SECOND
) WITH (
    'connector' = 'kafka',
    'topic' = 'api-logs',
    'properties.bootstrap.servers' = 'kafka-broker:9092',
    'format' = 'json'
);

CREATE VIEW avg_latency_view AS
SELECT 
    user_id,
    TUMBLE_END(`timestamp`, INTERVAL '5' MINUTE) AS window_end,
    AVG(latency_ms) AS avg_latency
FROM api_logs
GROUP BY 
    user_id,
    TUMBLE(`timestamp`, INTERVAL '5' MINUTE);

INSERT INTO sink_table SELECT * FROM avg_latency_view;

WATERMARK tanımının kullanımına dikkat edin. Flink SQL, olay zamanı ilerlemesini otomatik olarak yönetir, bu da durum TTL'leri veya zaman aşımı işleme için açık kod olmadan, geç veriye toleranslı ve doğru agregasyonlara olanak tanır.

Kafka Streams DSL: Java Odaklı Esneklik

Flink SQL karmaşık birleşimler ve çok tablalı dönüşümler için mükemmel olsa da, Kafka Streams DSL farklı bir değer önerisi sunar: Java ekosistemiyle sıkı entegrasyon ve akış topolojisi üzerinde ince ayarlı kontrol. DSL, metot zinciri tabanlıdır ve güçlü biçimli (strongly typed) kalırken okunabilir, akıcı bir arayüz sağlar.

Kafka Streams DSL'de benzer bir filtreleme ve agregasyon mantığını nasıl ifade edebileceğiniz aşağıda gösterilmektedir:


KStream logs = builder.stream("api-logs", 
    Consumed.with(Serdes.String(), Serdes.Serializer.of(ApiLog.class)));

KTable aggregated = logs
    .filter((key, value) -> value.getLatencyMs() > 0)
    .groupByKey(Grouped.with(Serdes.String(), Serdes.Serializer.of(ApiLog.class)))
    .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))
    .aggregate(
        Aggregation.with(
            () -> new AggregatedLatency(0, 0),
            (key, value, agg) -> agg.add(value),
            Serdes.Serializer.of(AggregatedLatency.class)
        )
    )
    .toStream();

aggregated.to("aggregated-latency", Produced.with(Serdes.String(), Serdes.Serializer.of(AggregatedLatency.class)));

Kafka Streams DSL, SQL'de kolayca ifade edilemeyen özel durum depoları, etkileşimli sorgular veya karmaşık yan çıktılar gerektiğinde parlar. Akıcı API, tip güvenliğini korurken çok aşamalı boru hatları oluşturmayı kolaylaştırır.

Doğru Aracı Seçme

Flink SQL ve Kafka Streams DSL arasında seçim genellikle veri boru hattınızın spesifik gereksinimlerine bağlıdır:

  • Flink SQL'i şu durumlarda kullanın:
    • Karmaşık çok tablalı birleşimlere ihtiyacınız varsa.
    • Ekip üyeleriniz arasında SQL'i tercih eden veri analistleri varsa.
    • Toplu ve akış işleme mantığını birleştirmek istiyorsanız.
    • Şema evrimi ve kataloğu yönetimi kritik önem taşıyorsa.
  • Kafka Streams DSL'yi şu durumlarda kullanın:
    • Mevcut Java servisleriyle sıkı entegrasyona ihtiyacınız varsa.
    • Özel durum deposu uygulamalarına ihtiyacınız varsa.
    • Dış sistemlerden etkileşimli sorgular veya anahtar-değer aramaları sık yapılıyorsa.
    • Kayıt seviyesinde tam bir kez (exactly-once) semantiği üzerinde ince ayarlı kontrole ihtiyacınız varsa.

Sonuç

Beyan edici akış işleme, kontrolü ortadan kaldırmakla ilgili değildir; modern veri mimarilerinin karmaşıklığıyla eşleşecek şekilde soyutlama seviyesini yükseltmekle ilgilidir. Hem Flink SQL hem de Kafka Streams DSL, gerçek zamanlı uygulamalar oluşturmak için sağlam ve üretim hazır araçlar sunar. Her birinin güçlü yönlerini anlayarak, veri mühendisleri yalnızca performanslı değil, aynı zamanda sürdürülebilir ve ölçeklenebilir boru hatları oluşturabilir. Sektör "veri dokuları" ve birleşik veri yönetimine doğru ilerlemeye devam ettikçe, beyan edici ve emperatif paradigmalar arasında sorunsuz geçiş yapabilme yeteneği, her veri profesyoneli için kritik bir beceri olacaktır.

Share: