<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Data Streaming Journal]]></title><description><![CDATA[Thoughts about data streaming, stream processing, and real-time data pipelines. ]]></description><link>https://www.streamingdata.tech</link><image><url>https://substackcdn.com/image/fetch/$s_!_lyL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg</url><title>Data Streaming Journal</title><link>https://www.streamingdata.tech</link></image><generator>Substack</generator><lastBuildDate>Wed, 29 Apr 2026 21:44:17 GMT</lastBuildDate><atom:link href="https://www.streamingdata.tech/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Yaroslav Tkachenko]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[streamingdata@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[streamingdata@substack.com]]></itunes:email><itunes:name><![CDATA[Yaroslav Tkachenko]]></itunes:name></itunes:owner><itunes:author><![CDATA[Yaroslav Tkachenko]]></itunes:author><googleplay:owner><![CDATA[streamingdata@substack.com]]></googleplay:owner><googleplay:email><![CDATA[streamingdata@substack.com]]></googleplay:email><googleplay:author><![CDATA[Yaroslav Tkachenko]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Can Kafka Queues Make Consumers Faster?]]></title><description><![CDATA[Kafka Queues promise consumer scaling beyond partitions, but benchmarks show share consumers still lag far behind standard Kafka consumers.]]></description><link>https://www.streamingdata.tech/p/can-kafka-queues-make-consumers-faster</link><guid isPermaLink="false">https://www.streamingdata.tech/p/can-kafka-queues-make-consumers-faster</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 27 Apr 2026 15:45:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/abe88b1d-fdfc-4838-a38d-3b29d5011358_1802x1114.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For a while, messaging systems like RabbitMQ, ActiveMQ, and AWS SQS have been used as a foundational component of many enterprise architectures. <a href="https://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns</a> is still one of my favourite books. I had my first exposure to messaging systems many years ago: I worked at a startup where we used a combination of ActiveMQ, Camel, and Akka to build event-driven microservices. </p><p>Then Apache Kafka became popular. The Distributed Log is a more generic abstraction, but many people have tried using it as a message queue, not always successfully. </p><p>Finally, Apache Kafka 4.x introduced Queues as a first-class citizen! And Queues are officially GA in Kafka 4.2.0. </p><p>Many more knowledgeable engineers have already extensively written about this:</p><ul><li><p><a href="https://www.morling.dev/blog/kip-932-queues-for-kafka/">Let&#8217;s Take a Look at... KIP-932: Queues for Kafka!</a></p></li><li><p><a href="https://www.confluent.io/blog/kafka-queue-semantics-share-consumer-ga/">Queues for Apache Kafka&#174; Is Here: Your Guide to Getting Started in Confluent</a></p></li><li><p><a href="https://rion.io/2026/02/02/surviving-the-streaming-dungeon-with-kafka-queues/">Surviving the Streaming Dungeon with Kafka Queues</a></p></li></ul><p>And the official <strong><a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka">KIP-932: Queues for Kafka</a></strong>. </p><p>Instead of repeating after everyone, I wanted to explore one idea that immediately came to mind once I learned about the Queues.</p><h3>What&#8217;s in It for Data Streaming Engineers?</h3><p>Queues are a great building block if you&#8217;re building a workflow orchestrator, a task scheduler, event-driven microservices, etc. </p><p>But what about data streaming projects? Will Queues help with Spark, Flink, Kafka Connect, and similar technologies? </p><p>I thought they could be applicable in two ways:</p><ul><li><p>Helping to build complex state machines. For example, if your stream-processing engine needs to perform a lot of work per message (e.g., calling an external endpoint, enriching data, performing conditional lookups), the ability to acknowledge or reject and reprocess messages is really valuable. Ideally, you also want to use the Dead Letter Queue (DLQ): it&#8217;s coming to Kafka as a first-class citizen too. </p></li><li><p>Scaling consumers beyond the partition count. The parallelism of Kafka consumers is generally limited by the partition count: you can&#8217;t have more instances consuming data than the number of partitions. There are some workarounds (like multi-threading consumers), but they&#8217;re quite complex and not supported in popular OSS projects like Spark and Flink. Queues seemed to offer a solution: a share group (a new Queues feature) can have more instances than partitions, and the work will be distributed accordingly. </p></li></ul><p>I focus on the latter next. It seems great in theory, but does it actually work? I decided to test it.</p><h3>The Benchmark</h3><ul><li><p>3-node Apache Kafka 4.2.0 cluster deployed using Strimzi Operator 0.51.0 on m8i.xlarge machines in AWS.</p></li><li><p>A single topic with <strong>4 partitions</strong> and 400M records, each record is a JSON payload with 1KB average size.</p></li><li><p>Two Kafka consumer apps that read data from the topic (using the Bytes deserializer, so no JSON deserialization overhead) as fast as possible, perform some conditional logging, but nothing else (essentially no-op). </p><ul><li><p>The Standard Consumer app just uses the regular KafkaConsumer</p></li><li><p>The Share Consumer app uses the new KafkaShareConsumer with <strong>implicit acknowledgement</strong> and <strong>batch_optimized</strong> share.acquire.mode.</p></li><li><p>Both consumers have the standard high-throughput tuning (increased fetch.max.bytes, fetch.max.wait.ms, max.partition.fetch.bytes, etc.)</p></li></ul></li></ul><p>Kafka brokers were configured with:</p><pre><code>group.coordinator.rebalance.protocols: &#8220;classic,consumer,share&#8221;
share.coordinator.state.topic.replication.factor: 3
share.coordinator.state.topic.min.isr: 2
group.share.partition.max.record.locks: 10000
group.share.record.lock.duration.ms: 15000
group.share.delivery.count.limit: 10</code></pre><p>As I understand, group.share.partition.max.record.locks is especially important for high throughput - we&#8217;d like to process as many records as possible. 10000 is the maximum value allowed.</p><p>I ran several experiments:</p><ul><li><p>Standard consumer (baseline): 1 instance and 4 instances. Can&#8217;t go higher because of the partition limit.</p></li><li><p>Share consumer: 1 instance, 4 instances, 8 instances. The goal was to compare with the baseline and observe the throughput increase with more instances.</p></li></ul><p>The logic of the share consumer looked like this (a bit simplified):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;22a40084-184e-4a26-9079-9da921e666ca&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">AtomicBoolean running = new AtomicBoolean(true);

try (KafkaShareConsumer&lt;byte[], byte[]&gt; consumer = new KafkaShareConsumer&lt;&gt;(props)) {
    consumer.subscribe(List.of(topic));

    long consumed = 0L;

    while (running.get()) {
        ConsumerRecords&lt;byte[], byte[]&gt; records = consumer.poll(pollTimeout);
        consumed += records.count();

        // logging the number of consumed messages and the processing rate
        // every 5 seconds
    }
}</code></pre></div><h3>Results</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z-JR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z-JR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 424w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 848w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 1272w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z-JR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png" width="728" height="268.27086614173226" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:468,&quot;width&quot;:1270,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:75101,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/188944425?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Z-JR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 424w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 848w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 1272w, https://substackcdn.com/image/fetch/$s_!Z-JR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4421857-6afa-4557-b8e5-8b1d7afcd696_1270x468.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, the standard consumer was able to achieve almost 1M rec/s throughput with 4 instances. </p><p>The throughput of the new share consumer is dramatically lower. We can definitely see the improvement when adding more instances, but the difference is still brutal: even eight instances of the share consumer are slower than a single standard one.</p><h2>Analysis and Conclusion</h2><p>So, why is the share consumer performance so different? I&#8217;m not a KIP-932 expert; I might be missing something (in which case, I welcome feedback!). But, as far as I understand:</p><ul><li><p>Queues add additional overhead. They&#8217;re designed around the idea of <em>acquisition locks</em>, and the locks are managed on the broker side.</p></li><li><p>Most importantly, even though you can have multiple instances <em>receiving</em> the data on the consumer side, the <em>fetching</em> is still pretty much bottlenecked by the number of partitions:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UmIC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UmIC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 424w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 848w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 1272w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UmIC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png" width="1456" height="282" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:282,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:116738,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/188944425?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UmIC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 424w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 848w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 1272w, https://substackcdn.com/image/fetch/$s_!UmIC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1382b4d6-438f-4a17-aac6-af6a7ca9b479_1510x292.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Perhaps throughput could be improved if the fetch-from-follower optimization is implemented by the share groups, but it seems quite challenging (the state will have to be distributed). </p></li></ul><p>Apache Kafka Queues is a very powerful abstraction, but as far as I can see, it won&#8217;t simply eliminate partitions as a scaling bottleneck for your consumers. At least, not yet. </p><div><hr></div><h3>Other Posts</h3><p>I recently wrote <a href="https://thenewstack.io/postgres-iceberg-cdc-benchmarks/">Postgres to Iceberg in 13 minutes: How Supermetal compares to Flink, Kafka Connect, and Spark</a> and <a href="https://streamacademy.io/tutorial/flink-kafka-consumer-offsets-with-the-state-processor-api/">Apache Flink: Reading and Modifying Kafka Consumer Offsets Using the State Processor API</a>, which you may find interesting.</p><div><hr></div><h3>Advanced Apache Flink</h3><p><a href="https://streamacademy.io/course/advanced-apache-flink/">Advanced Apache Flink</a> is an on-demand course focused on Flink internals, production deployment best practices, and advanced patterns.</p>]]></content:encoded></item><item><title><![CDATA[Advanced Apache Flink On-Demand Course]]></title><description><![CDATA[A few months ago, I announced the Advanced Apache Flink Bootcamp, a deeply technical training focused on Apache Flink internals, production deployment, and advanced patterns.]]></description><link>https://www.streamingdata.tech/p/advanced-apache-flink-on-demand-course</link><guid isPermaLink="false">https://www.streamingdata.tech/p/advanced-apache-flink-on-demand-course</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 23 Mar 2026 14:02:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a9b78853-08cb-4eb7-89c0-22870312c2d1_705x397.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few months ago, I <a href="https://www.streamingdata.tech/p/announcing-data-streaming-academy">announced</a> the <strong>Advanced Apache Flink Bootcamp</strong>, a deeply technical training focused on Apache Flink internals, production deployment, and advanced patterns.</p><p>I ran the first cohort in January and also had the chance to conduct several corporate training sessions using the same program. I&#8217;ve received a lot of great feedback, iterated and polished my content.</p><p>Today, I&#8217;d like to announce the self-paced, on-demand version of the training!</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9de4ac31-b10c-4f62-9168-bb2316cf2b51&quot;,&quot;duration&quot;:null}"></div><p>Check the <strong><a href="https://streamacademy.io/course/advanced-apache-flink/">Advanced Apache Flink course</a></strong>. Expect more courses in the future!</p><p></p>]]></content:encoded></item><item><title><![CDATA[Benchmarking CDC Tools: Supermetal vs Debezium vs Flink CDC]]></title><description><![CDATA[Classic "Big Data" stack vs Rust & Arrow.]]></description><link>https://www.streamingdata.tech/p/benchmarking-cdc-tools</link><guid isPermaLink="false">https://www.streamingdata.tech/p/benchmarking-cdc-tools</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Tue, 17 Feb 2026 15:02:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/06b93b75-2d94-465f-a944-0a8a929df3c4_1200x886.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you&#8217;ve been following my writing recently, you likely know I&#8217;m very bullish on the <a href="https://www.streamingdata.tech/p/streaming-and-the-rad-stack">Rust &amp; Apache Arrow data stack</a>. </p><p>So when I first learned about <a href="https://www.supermetal.io/">Supermetal</a> (almost 2 years ago), I got really excited! Finally, some innovation in the Change Data Capture (CDC) space.  </p><p>Recently, Supermetal <a href="https://www.supermetal.io/blog/kafka-target">announced support for Kafka sinks</a>, making it a competitor to open-source tools like <a href="https://debezium.io/">Debezium</a> and <a href="https://github.com/apache/flink-cdc">Flink CDC</a>. </p><p>I worked with the Supermetal team to run a series of independent benchmarks. This post summarizes my findings. </p><blockquote><p>DISCLOSURE: this work was sponsored by Supermetal. All benchmarks were executed myself in my AWS account. All numbers and findings are shared as is.</p></blockquote><h3>About CDC Tools</h3><h4>Supermetal</h4><p>Supermetal is a new CDC tool implemented using Rust and Apache Arrow. It&#8217;s very easy to use: it can be deployed as a single binary. Get the trial version <a href="https://trial.supermetal.io/">here</a> (includes 1000 hours of free sync). </p><p>It scales well <em>vertically</em> (by leveraging available CPU cores). It supports many popular databases and data warehouses. It doesn&#8217;t rely on Kafka or any kind of orchestrator: data can be delivered directly from a source to a sink (with optional object storage buffering). You can check its architecture <a href="https://docs.supermetal.io/docs/main/concepts/architecture/">here</a>.</p><p>Supermetal supports both live (e.g. reading from a replication slot) and snapshotting modes. Snapshots are always parallelizable.</p><p>Supermetal can be configured using the <a href="https://docs.supermetal.io/docs/main/quickstart/">built-in UI</a>. <a href="https://docs.supermetal.io/docs/api/">REST API</a> is also available. Finally, a JSON config file in the same format as the API can be used, which I chose to deploy (a better fit for containerized workloads). The config file just describes sources and sinks.</p><h4>Debezium</h4><p>Debezium is likely the most popular CDC tool in the world. It&#8217;s implemented in Java and typically deployed as a connector in a Kafka Connect cluster. This means it relies on Kafka: CDC data is first ingested into a set of Kafka topics, and then can be delivered to sinks via another connector. </p><p>It supports pretty much all relational databases and some non-relational ones.</p><p>Debezium supports both live and snapshotting modes as well. An important architectural detail: Debezium connectors (at least the most popular ones, such as MySQL and Postgres) can only be deployed as single-task connectors in the Kafka Connect cluster. Snapshotting can be parallelized by increasing the number of snapshot threads (a relatively new feature). </p><p>Debezium connector was deployed with a simple, flat config file. </p><h4>Flink CDC</h4><p>Flink CDC originally started as a collection of Flink CDC sources; nowadays, it&#8217;s a fully-fledged data integration framework. It&#8217;s also implemented in Java using Flink as the engine.</p><p>Flink CDC supports both live and snapshotting modes as well. For live mode, it mostly relies on Debezium, since Debezium can be deployed in embedded mode, which doesn&#8217;t require a Kafka Connect cluster. For snapshotting, Flink CDC uses a custom implementation that heavily relies on the <a href="https://cwiki.apache.org/confluence/display/FLINK/FLIP-27%3A+Refactor+Source+Interface">Flink Source API</a>. Most notably, this is the only of the three implementations that allows&nbsp;<em>horizontal</em>&nbsp;scaling of the snapshotting stage: input chunks (a range of a Postgres table, for example) can be processed in&nbsp;<em>parallel</em>&nbsp;across <em>different</em> TaskManager nodes. </p><p>In the case of the Flink CDC framework, you can use YAML-based declarative pipelines, but since I used it as a source connector, I needed to implement a pipeline programmatically. </p><h3>Test Setup</h3><p>As you can guess, I had a pretty trivial (and common) goal: replicate data from Postgres to Kafka.</p><p>I used the TPC-H dataset with a scale factor (SF) of 50. If you&#8217;re not familiar with it, it consists of 8 tables of different sizes. With SF=50, the largest table (lineitem) has 300M rows, the second-largest (orders) has 75M rows, and so forth. </p><p>On the infra side, I had:</p><ul><li><p>AWS RDS Aurora Postgres 16, 48 ACUs (increased to 96 later).</p></li><li><p>AWS MSK with 3 express.m7g.xlarge brokers.</p></li><li><p>AWS EKS 1.34 using m8i.xlarge nodes (4 CPU cores, 16 GB RAM). </p><ul><li><p>All workloads (Supermetal agent, Kafka Connect node, Flink TaskManager) used a single node pretty much exclusively (configured to request 3.5 CPU cores and 13 GB RAM). Flink TaskManager used 4 task slots.</p></li></ul></li></ul><p>Regarding versions:</p><ul><li><p>Latest Supermetal build (provided by the Supermetal team as a Docker image).</p></li><li><p>Flink CDC 3.5.0 with Flink 1.20 deployed using Flink Kubernetes Operator 1.13.</p></li><li><p>Debezium 3.4.1.Final with Kafka Connect 4.1.1 deployed using Strimzi Operator 0.50.0.</p></li></ul><h3>Generated Data</h3><p>All three tools generated Kafka topics with JSON records. By default, Supermetal uses Debezium envelope schema, and I was able to confirm that it&#8217;s actually <em>identical</em> to what Debezium emits, not just payload fields, but message keys and headers too.</p><p>Flink CDC provides a standard JsonDebeziumDeserializationSchema for obtaining Debezium records as JSON, but you need to implement a Kafka serializer yourself. The serializer I implemented produced the same Kafka message payloads, but <strong>I skipped the message keys and headers</strong>, which likely somewhat affected the rates you see below. </p><p>Finally, I spot-checked data across topics and didn't observe any data loss. </p><h3>Snapshotting Mode</h3><p><strong>I primarily wanted to test snapshotting performance</strong>; I expected to see the most drastic differences there. I also tested live mode, but skipped Flink CDC for it (since it essentially wraps Debezium, so performance would be roughly the same or lower). </p><p>Ok, let&#8217;s explore the benchmarks now!</p><h4>Supermetal</h4><p>The baseline run with the default configuration looked like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5_eU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5_eU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 424w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 848w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 1272w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5_eU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png" width="1456" height="522" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:522,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5_eU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 424w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 848w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 1272w, https://substackcdn.com/image/fetch/$s_!5_eU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd38c2b-b782-4b1e-920f-6314d88e2e52_2048x734.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It finished in <strong>72 minutes</strong> with <strong>174 MB/s</strong> peak throughput and <strong>105 MB/s</strong> average throughput.</p><p>Supermetal team recommended to also test with:</p><ul><li><p>Disabled intra-table chunking (parallel_snapshots_enabled = false). For Kafka sinks, this improves throughput since Kafka partitions are the bottleneck, not table parallelism. This is typically not needed for sinks like data warehouses.</p></li><li><p>Producer pool size equal to the number of input tables (8). </p></li></ul><p>Another run with the updated configuration finished in <strong>60 minutes</strong> with <strong>275 MB/s</strong> peak throughput and <strong>123 MB/s</strong> average throughput. Spoiler: this is the best result I saw!</p><h4>Flink CDC</h4><p>The baseline run with the default configuration looked like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8JVr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8JVr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 424w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 848w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 1272w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8JVr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png" width="1456" height="524" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:524,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8JVr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 424w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 848w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 1272w, https://substackcdn.com/image/fetch/$s_!8JVr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278f4d5-c573-4f4e-a2c6-77e79b817a1f_2048x737.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It finished in <strong>210 minutes</strong> with <strong>29 MB/s</strong> peak throughput and <strong>22 MB/s</strong> average throughput. Pretty big difference compared to Supermetal, but it&#8217;s important to establish a baseline. Can we improve it?</p><p>First obvious optimization to try was tweaking the Kafka Producer configuration: using <strong>linger.ms</strong> of <strong>100</strong> and <strong>batch.size</strong> of <strong>1000000</strong>. Actually, these are the values that are used by Supermetal by default, so it&#8217;s only fair to set the same here. But this change <em>didn&#8217;t show any performance gains</em>. I may have an explanation below. </p><p>Another thing I decided to try was scaling the job horizontally. I added <strong>three</strong> more TaskManagers, which increased total parallelism from <strong>4</strong> to <strong>16</strong>. This led to almost linear improvement in throughput: I was able to consistently achieve <strong>84 MB/s</strong> after ramping up. But, of course, it also means additional infrastructure. </p><p>Another optimization I tried separately was increasing fetch size (how many rows a connector polls at once) and chunk/split size (how many rows are logically grouped together for processing). I increased the fetch size to <strong>5000</strong> (from the default 1024) and chunk/split size to <strong>50000</strong> (from the default 8096). This led to <strong>54 MB/s</strong>.</p><h4>Debezium</h4><p>The baseline run with the default configuration looked like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eeco!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eeco!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 424w, https://substackcdn.com/image/fetch/$s_!eeco!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 848w, https://substackcdn.com/image/fetch/$s_!eeco!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 1272w, https://substackcdn.com/image/fetch/$s_!eeco!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eeco!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png" width="1456" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eeco!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 424w, https://substackcdn.com/image/fetch/$s_!eeco!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 848w, https://substackcdn.com/image/fetch/$s_!eeco!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 1272w, https://substackcdn.com/image/fetch/$s_!eeco!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F837b4d7a-75c8-48bc-aa25-4920094a381a_2048x634.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It finished in <strong>170 minutes</strong> with <strong>74 MB/s</strong> peak throughput and <strong>43 MB/s</strong> average throughput. Also, much slower than Supermetal and comparable to Flink CDC.</p><p>I tried the same obvious optimization with tweaking the Kafka Producer configuration: using <strong>linger.ms</strong> of <strong>100</strong> and <strong>batch.size</strong> of <strong>1000000</strong>. This time, it was beneficial: I was able to nearly double the throughput and consistently achieve <strong>100 MB/s</strong> after ramping up</p><p>Another optimization I tried separately was increasing the number of snapshot threads, from <strong>1</strong> to <strong>4</strong>. This also gave a nice boost, reaching <strong>70 MB/s</strong>. Increasing further to <strong>8</strong> threads didn&#8217;t help though.</p><p>I also tried combining the tweaked Kafka Producer config and 4 snapshot threads, but it made things <strong>worse than the baseline</strong>. Too much contention, I guess.</p><h3>Live Mode</h3><p>The data generator I used was able to emit the same TPC-H data consistently at a given rate. It only wrote data to the top two tables: lineitem and orders.</p><h4>Debezium</h4><p>With the default config, Debezium could keep up with&nbsp;<strong>15k ops/s</strong>. Things didn&#8217;t look good at <strong>30k ops/s</strong>, the replication lag started growing.</p><p>I applied the same optimization and increased the producer&#8217;s batch.size and linger.ms. That made it possible to sustain <strong>30k ops/s</strong>. The replication slot lag remained around 800 MB.</p><p>Unfortunately, I couldn&#8217;t get my data generator to write more than ~35k ops/s&#8230; Even after increasing the Postgres database to 96 ACUs. This is likely possible with the different Postgres setup, but I was happy with the numbers at that point.</p><p>I think live Debezium connector throughput could be improved further by increasing max.batch.size and max.queue.size config options, but I couldn&#8217;t test it. Also, it&#8217;s likely possible to lower the replication slot lag by reducing the flush time on the Kafka Connect side. </p><h4>Supermetal</h4><p>Supermetal was able to keep up with <strong>35k ops/s</strong> using the default config. The replication slot lag stayed below 100 MB.</p><p>When it comes to live data, throughput is just one consideration. Latency can be as important. I admit it wasn&#8217;t the goal of my benchmark, but just looking at the replication lag, it seems very promising. Maybe we&#8217;ll have a part 2?</p><h3>Other Notes</h3><p>Supermetal used the CPU more efficiently (typically ~50% of the allocated 4 cores), while Debezium and Flink CDC mostly stayed around 25%.</p><p>Supermetal also used less memory (2GB), whereas Debezium and Flink CDC consumed much more (8GB - 10GB). </p><h3>Analysis &amp; Conclusion</h3><h4>Parallelization</h4><p>If you compare the three graphs again, you&#8217;ll notice that Debezium and Flink CDC demonstrated the same behaviour: achieving a certain throughput level and roughly staying at that level during the test. This was true regardless of the optimizations I applied (they just affected the rate). </p><p>Supermetal behaved differently: you can see a big jump at the beginning, where it processes most of the tables in parallel, and then the throughput decreases as only the biggest table (lineitem) remains. </p><p>I think it means Supermetal can parallelize processing more efficiently, so it can likely achieve better throughput with larger tables.</p><h4>Why is Flink CDC the Slowest? </h4><p>Flink CDC seemed to be the slowest option, but why is that? It has a sophisticated snapshotting mechanism, but it still appears to be slower than Debezium. </p><p>Flink was designed to run at a large scale. There is definitely some overhead that affects workloads with the smaller scale - a distributed system almost always pays some coordination cost compared to a single-node architecture (this is why systems like DuckDB are almost always faster than Spark on small data, for example).</p><p>But I think, at least in part, it can be attributed to the amount of JSON serialization/deserialization it performs. Here&#8217;s the CPU flamegraph I took:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F04g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F04g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 424w, https://substackcdn.com/image/fetch/$s_!F04g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 848w, https://substackcdn.com/image/fetch/$s_!F04g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 1272w, https://substackcdn.com/image/fetch/$s_!F04g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F04g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png" width="1456" height="699" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:699,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1539958,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/187903110?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F04g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 424w, https://substackcdn.com/image/fetch/$s_!F04g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 848w, https://substackcdn.com/image/fetch/$s_!F04g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 1272w, https://substackcdn.com/image/fetch/$s_!F04g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18a90b1a-6e06-479c-ad21-535f727acd2e_3802x1824.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Purple color highlights JSON serialization/deserialization, which takes almost a third of the CPU. In general, when it comes to stateless streaming systems, data serialization/deserialization is the slowest part. This is especially evident here, since the data goes through a few serialization/deserialization roundtrips (first in Debezium, then in Flink). Jackson, the heavily used Java JSON library, is not the fastest out there. If you&#8217;re dealing with JSON in a high-performance Java system, check <a href="https://github.com/alibaba/fastjson2">fastjson2</a> and <a href="https://github.com/simdjson/simdjson-java">simdjson-java</a>.</p><h4>I Expect Even Bigger Difference With Transformations</h4><p>Supermetal leverages a highly optimized columnar Apache Arrow format, which will likely deliver even better performance when a transformation (such as a filter or projection) is involved, thanks to low-level compute kernels. </p><p>Supermetal doesn't support transformations yet, but it's on the roadmap. I'd love to re-run the benchmark when it ships. I believe that columnar data layout will make a huge difference!</p><h4>Summary</h4><p>Supermetal clearly delivers the best performance. Debezium and Flink CDC, once optimized, can get close. At the same time, Supermetal shows much better usage of allocated resources (better CPU and memory utilization). </p><p>If you still think that <a href="https://github.com/rewrite-bigdata-in-rust/RBIR">Rewrite Bigdata in Rust</a> is just hype, maybe reconsider. I think we&#8217;ll see more tools purposely designed to run very efficiently on modern hardware. </p><p>If you need to optimize Debezium or Flink CDC pipelines, look into tuning the Kafka Producer configuration and consider the best way to parallelize snapshots.</p><p>It&#8217;s worth highlighting that Flink CDC has a working horizontally scalable snapshotting mechanism. If you&#8217;re willing to throw more <s>money</s> compute at the problem, you can likely achieve a similar (or higher) level of performance as Supermetal.</p><p>Horizontal scalability may seem like a must-have, but ultimately, your database will eventually become the bottleneck. Also, you can go really far by logically sharding your CDC workloads by table: I could&#8217;ve deployed 8 supermetal agents or 8 debezium tasks, one for each table. Definitely more painful to manage at scale.</p><p>I also have to mention the difference in developer experience: having a single binary and not relying on operators, clusters, and much configuration / glue code felt amazing!</p>]]></content:encoded></item><item><title><![CDATA[Why Apache Flink Is Not Going Anywhere]]></title><description><![CDATA[Not in the next few years.]]></description><link>https://www.streamingdata.tech/p/why-apache-flink-is-not-going-anywhere</link><guid isPermaLink="false">https://www.streamingdata.tech/p/why-apache-flink-is-not-going-anywhere</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Wed, 03 Dec 2025 14:03:26 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/39a7c3af-72cf-4198-be04-20b81954d9c9_600x443.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Astrologers proclaim the month of criticizing Apache Flink<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, I thought to myself recently. In the last few months, I have read many posts on social media, company blogs, and newsletters that attack Flink from different angles. So, today, I&#8217;d like to reply with this statement: Flink is not going anywhere. </p><h3>What Critics Say</h3><h4>Flink Is Too Complex</h4><p>&#8220;Flink is a complex distributed system, it&#8217;s a mistake to start with it&#8221;, &#8220;Watermarking and windowing are so complex&#8221;, &#8220;Stateful Flink pipelines are so hard to manage, RocksDB is a PITA and requires tons of tuning&#8221;, &#8220;Schema and state evolution are impossible to get right&#8221;, &#8220;There are very few real low-latency use cases&#8221;, etc.</p><p>I can go on, but you got the gist. </p><p>First of all, complexity is not something you can measure. You can&#8217;t say that tool A is 37% more complex than tool B. Something that is complex for one individual/team/organization is not necessarily complex for another, and vice versa. People often cite Postgres as an example of a simple tool that does the job. However, I believe most of them don&#8217;t mean you should actually set up and manage a Postgres cluster yourself. Because managing Postgres, especially after reaching a certain scale, can be quite painful. Even managed solutions like AWS RDS don&#8217;t fully shield you from that.</p><p>Second, you need to differentiate essential and accidental complexity. Accidental complexity comes from lack of experience, over-engineering, frequent pivots, and tight deadlines. But essential complexity exists no matter what we do (that&#8217;s why it&#8217;s called <em>essential</em>). For example, everyone agrees that Kubernetes is a very complex technology. But I&#8217;d argue that most of the complexity is essential: reliable infrastructure and application management are just really hard by definition. </p><p>I believe the same applies to Flink. Why? Supporting a variety of data streaming use cases (from data integration to streaming ETL to real-time analytics to Complex Event Processing) is quite hard. It&#8217;s also one of the most popular Apache projects with thousands of contributors who run Flink in many different scenarios. When a project gets to be that popular for so long, it&#8217;ll inevitably reduce its accidental complexity with time; otherwise, it&#8217;d be impossible to keep adding new features.</p><p>But, most importantly, you need to see what Flink is being compared with. When many critics say that Flink is complex, they compare it with a <strong>proprietary, managed, paid</strong> service they offer. It&#8217;s easy to make that statement because you have:</p><ul><li><p>On one side, an open-source technology that you need to deploy and manage yourself. </p></li><li><p>On the other side, <em>a small surface area</em> of a managed service. </p></li></ul><p>And when it comes to operating Flink, you can&#8217;t avoid infrastructure management, SRE practices, observability, and CI/CD tooling. But the claims that it&#8217;s really hard to manage are, at least, outdated. You can choose from many vendors (all major clouds, Confluent, Ververica). Also, the Flink Kubernetes Operator makes it <a href="https://github.com/apache/flink-kubernetes-operator/blob/main/examples/basic.yaml">very easy</a> to deploy and manage Flink in a Kubernetes environment. </p><p>There are also claims that Flink requires a &#8220;cluster setup&#8221; and that it&#8217;s &#8220;centralized&#8221;, therefore, you need a specialized team to manage it. I guess this stems from the fact that Flink has a JobManager component which communicates with many TaskManagers (or &#8220;workers&#8221;). But with modern infrastructure management tools like the Flink Kubernetes Operator, all of this is mostly abstracted from you. And managing Flink becomes almost as easy as managing a pool of stateless web applications. I said &#8220;almost&#8221; because every Flink pipeline is stateful in some way (e.g., storing Kafka consumer group offsets), so it requires an extra step to take or recover from a savepoint, etc. But it can be easily automated.</p><p>Another claim I&#8217;ve seen: Flink is complex because it guarantees exactly-once delivery. However, this is a connector-level property: some connectors offer at-least-once, some exactly-once, and some both. Exactly-once <em>can</em> complicate your end-to-end system significantly (e.g. Kafka sink uses Kafka transactions), but you can almost always fallback to at-least-once.</p><p>Finally, I&#8217;d like to add this: <em>of course,</em> you shouldn&#8217;t use Flink for simple use cases that don&#8217;t require it. And <em>of course,</em> you don&#8217;t need to use <em>all</em> the features that Flink provides. Also, Flink is a great, versatile tool; however, sometimes, it&#8217;s more efficient to use it with something else. For example, arguably, many aggregation-related use cases can be better supported by a modern OLAP database like ClickHouse. But in some cases, it makes total sense to use windowed aggregations in Flink: ML feature engineering and sessionization come to mind. As usual, the answer to &#8220;should I use this or that&#8221; is not binary; it requires planning and research<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. </p><h4>Nobody Needs Realtime</h4><p>Data streaming is usually associated with low-latency, as opposed to batch processing. &#8220;Low-latency&#8221; can mean a lot of different things in many contexts, but let&#8217;s assume that in the case of Flink, we&#8217;re talking about sub-100ms processing latency. Many critics say that very few use cases actually demand latency like this; therefore, Flink is not needed. </p><p>And this is a completely wrong take. </p><p>Data streaming is not about latency. It&#8217;s definitely helpful to have <em>relatively</em> low-latency, but to me it can be 100 milliseconds, 1 second or even 10 seconds in most scenarios. </p><p>Data streaming <strong>semantics</strong> and <strong>continuous processing</strong> are important parts. The ability to process data streams with transformations that leverage continuous processing is extremely powerful. For example, I can design my data streams as changelogs and enjoy end-to-end upsert semantics that automatically correct data. I wrote about it here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;8edeb273-eef3-4434-b1d6-813dc7d5cf35&quot;,&quot;caption&quot;:&quot;The idea of changelog topics or data streams is not new: stream-table duality advertised by Kafka Streams was popularized quite a bit in 2018 (paper, blog). Related concepts have been mentioned regularly in the past 30 years (the earliest paper I could find is from 1992). And nowadays, you can see it everywhere, not just in Kafka Streams:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Changelog vs Append-Only Data Streams&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-08-07T16:04:10.132Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/changelog-vs-append-only-data-streams&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:135723081,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1787299,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!_lyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Modern data streaming semantics have evolved from decades-old messaging semantics. <a href="https://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns</a> is a book released 20+ years ago, and I still recommend it today. This book explains that messaging is the best approach for integrating different systems, something that data systems still struggle with today. It also describes <a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/">patterns</a> that became the foundation for many of the tools we use today, including Kafka and Flink.</p><p>So, yes, we rarely need 50ms processing latency. But we need reliable ways to process data streams, and stream-processing tools like Flink are, arguably, the best answer we have.</p><h4>Look at the Confluent Earnings Report!</h4><p>For some reason, people think looking at how much Confluent makes by selling Flink is a good indicator of&#8230; I don&#8217;t really know what. Flink adoption? Popularity? Growth? Not sure. But it&#8217;s being used <em>widely</em> as an argument to support their claims. </p><div class="pullquote"><p>Context: Confluent <a href="https://investors.confluent.io/static-files/0ee39fd5-5a96-432c-b6d3-f2d5cf2c5aaf">reported</a> its Flink ARR (Annual Recurring Revenue) for Q2 of 2025 to be $10M, stating 3x growth from the previous quarter. Q3 2025 <a href="https://investors.confluent.io/static-files/a2cf1818-192e-48c0-bcc5-2b85b1be3b6d">report</a> shows another 70% growth. So, the full picture so far, as far as I understand it: $3M (Q1) &#8594; $10M (Q2) &#8594; $17M (Q3).</p></div><p>Is it a low number? I don&#8217;t know. What are we comparing it with? </p><p>I&#8217;m confident that most of the data infrastructure companies launched in the past few years that compete with Flink aren&#8217;t even remotely close to that ARR number. But sure, public company vs startups, not a fair comparison.</p><p>Anyway, whatever number Confluent reports is pretty much irrelevant to Apache Flink, <em>the technology</em>. Here&#8217;s why:</p><ul><li><p>Confluent Cloud doesn&#8217;t support the DataStream API, which is still the most popular and widely used way to author Flink pipelines.</p></li><li><p>Confluent Cloud doesn&#8217;t support any Flink connectors except the Kafka ones (or, to be correct, Confluent Kafka ones: you can&#8217;t use Confluent Flink without Confluent Kafka). This, again, eliminates a huge number of reasons to use Flink in the first place (e.g. compared to Kafka Streams). The ability to connect to arbitrary data stores, and not just Kafka, is really powerful.</p></li><li><p>Their SQL / Table API Cloud offering seemed to target the wrong audience: you had to write Flink SQL in a browser in a notebook-like environment. This is not what most engineers would want to use. This is not a Flink problem; this is a product problem. Thankfully, they&#8217;re addressing it now with IDE extensions (and the API is getting more mature).</p></li></ul><h4>The &#8220;I Don&#8217;t Know Java&#8221; Argument Is Outdated</h4><p>Don&#8217;t want to write Java? Just use Flink SQL.</p><p>The majority of the new data processing technologies tend to favour SQL. Many of them also implement Incremental View Maintenance (IVM) semantics: reusing previously computed results to avoid full re-processing. </p><p>And it&#8217;s quite common to see this comparison: &#8220;look at the complex Flink Java code on one side and this simple SQL query on the other side&#8221;. Of course, the SQL query typically looks more concise. But Flink SQL has been around for <em>years</em>; you should really compare with that!</p><p>Flink SQL has its own problems, of course. State evolution is still a big problem. But it&#8217;s generally a tough problem for any system: very few IVM tools can actually <em>reuse</em> internal state when the query <em>is modified</em>.</p><p>Other than handling state evolution, Flink SQL (and the Table API) is mature and stable. Netflix has 10000+ Flink SQL pipelines. Shopify heavily invests in Flink SQL. LinkedIn uses Flink SQL to unify streaming and batch queries. </p><p>I believe Flink SQL can cover over 70% of common Flink use cases. If you&#8217;re writing a new Flink pipeline, look at Flink SQL first (then the Table API, and only then consider using the DataStream API).</p><p>I agree that trying to bridge databases and stream-processing systems is the right direction. Adopting the SQL-first approach makes sense. You get declarative pipelines, you leverage query optimizations, you get fully schematized datasets, etc. But you can not, and you should not discard Flink because it&#8217;s not a database-native tool: Flink SQL gets you really close. </p><h3>Flink Is Ubiquitous</h3><p>No matter what critics say, Flink adoption is really strong. Pretty much all Big Tech companies use Flink (it&#8217;s a long list to type, but just to name a few: Apple, Airbnb, Alibaba, Booking, DoorDash, eBay, Instacart, LinkedIn, Lyft, Netflix, Pinterest, Reddit, Salesforce, Shopify, Stripe, Uber). Name the top 10 companies in pretty much any vertical, and most of them would use Flink. </p><p>You could say that it happens because of historical reasons or due to inertia. Look at OpenAI then<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>: they could&#8217;ve chosen any bleeding-edge tech for their data processing needs, but they ended up using Flink. There are plenty of startups that choose Flink too. My favourite example is <a href="https://www.grepr.ai/">Grepr</a>: you won&#8217;t find Flink mentioned anywhere except the job postings, yet it&#8217;s in the core of the product. </p><p>I also don&#8217;t see many examples of companies switching from Flink to other technologies. Of course it happens, but it&#8217;s quite rare (or I just don&#8217;t hear about this, so let me know).</p><h3>Flink Future: Process Table Functions (PTFs) and Disaggregated Storage</h3><p>I believe that Process Table Functions (PTFs) will take Flink to another level. </p><p>PTFs give access to state and timer primitives inside the Table API. So it&#8217;s possible to implement low-level, DataStream-style operators and seamlessly integrate them into your SQL logic. </p><p>Just <a href="https://nightlies.apache.org/flink/flink-docs-release-2.1/docs/dev/table/functions/ptfs/#greeting-with-memory">look at this example</a>. No, seriously, look at it and come back.</p><p>It&#8217;s amazing, isn&#8217;t it? If you scroll a bit further, you&#8217;ll find the example with timers. </p><p>I&#8217;m not aware of any other data processing technology that exposes such powerful primitives as state and timers to user-defined functions (UDF). And not just exposes, but does it so elegantly. Most UDFs out there are simple, stateless bits of logic. But with PTFs, it&#8217;s possible to implement any kind of stateful operator (join, aggregation, etc.) optimized for your specific use case. </p><p>I can even imagine a PTF marketplace in the future!</p><p>Disaggregated state backend storage introduced in Flink 2.x is another major initiative that I&#8217;m excited about. Large stateful Flink pipelines can be hard to manage, especially when it comes to recovery. Flink follows the popular trend of shifting local storage to object storage, which makes it possible to have relatively cheap pipelines with a lot of state without thinking about local storage.</p><p>Disaggregated storage is still rough around the edges, but the upcoming Flink 2.2 release should address some of the issues. Even though it&#8217;s still marked as experimental, I&#8217;d consider it for some production workloads after 2.2 is out.</p><h3>Conclusion</h3><p>I believe Flink has a very bright future. I made <a href="https://irontools.dev/blog/announcement/">a big bet</a> on that. </p><p>You could say I am incentivized to present Flink in the best light possible. But even if it&#8217;s the case, there is nothing wrong with that - I&#8217;m sure my readers are capable of making their own decisions. I&#8217;ve been writing repeatedly about the&nbsp;<a href="https://www.streamingdata.tech/p/streaming-and-the-rad-stack">RAD stack</a>&nbsp;(Rust, Arrow, DataFusion) as the next iteration of&nbsp;data processing tooling. I truly believe that Rust, Arrow, DataFusion and related projects will slowly replace Flink, Spark and a bunch of other &#8220;classic&#8221; Big Data tools. Not in the next few years, though. </p><p>Flink has a lot to offer. That&#8217;s why I&#8217;m working on <strong><a href="https://streamacademy.io/course/advanced-apache-flink/">an advanced Flink bootcamp</a></strong> and training - I&#8217;d like to spread my knowledge as much as I can. This bootcamp will be great for you if you already have some Flink knowledge, but you&#8217;d like to become an expert. </p><p>Finally, some recommendations to the critics: </p><ul><li><p>Do better than forming echo chambers. We can learn from each other.</p></li><li><p>If you criticize Flink, try to be specific and offer an alternative solution. It&#8217;s easy to criticize without offering anything.</p></li><li><p>Vague statements like &#8220;Flink is complex&#8221; and &#8220;nobody needs realtime&#8221; are not helpful.</p></li></ul><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Kudos to those few who got the HOMM3 reference.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Which is another way to say: it depends.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Sure it was founded in 2015, but it really started to grow only in 2023.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Current New Orleans 2025]]></title><description><![CDATA[Conference highlights.]]></description><link>https://www.streamingdata.tech/p/current-new-orleans-2025</link><guid isPermaLink="false">https://www.streamingdata.tech/p/current-new-orleans-2025</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 03 Nov 2025 16:46:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/52b64b33-d2ed-46f1-8ce3-5992279f37c0_3439x2563.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Current 2025</strong> happened last week in New Orleans, USA. I&#8217;ve had a chance to attend it, and I&#8217;d love to share some of my notes with you.</p><h3>Keynotes &amp; Announcements</h3><p><strong><a href="https://www.confluent.io/product/confluent-intelligence/">Confluent Intelligence</a></strong> likely was the biggest announcement. It&#8217;s a combination of three products:</p><ul><li><p>Built-in ML functions for forecasting, anomaly detection, fraud detection, etc. These are implemented as Flink UDFs that call internal models. Some examples: ML_FORECAST, ML_DETECT_ANOMALIES, ML_PREDICT, etc. I believe that at least some of these functions have been supported for a while.</p></li><li><p><a href="https://www.confluent.io/product/streaming-agents/">Streaming Agents</a>. I&#8217;m not a big fan of this name. There is actually very little <em>agentic</em> functionality: if you think about it, these are Flink pipelines with UDFs that can call LLMs and MCP servers. That&#8217;s it. In my opinion, a truly agentic framework needs to support branching, loops, and, most importantly, somewhat non-deterministic execution that&#8217;s generated by the LLM output. So, workflow orchestration frameworks such as Restate, Temporal, DBOS, etc., are a better fit for this, in my opinion.</p></li><li><p><a href="https://www.confluent.io/blog/introducing-real-time-context-engine-ai/">Real-Time Context Engine</a>. A fancy name for what it seems like, an in-memory query engine (likely an Incremental View Maintenance system), which sits on top of hot (Kafka) and cold (Iceberg) data and exposes itself over MCP. This is the most interesting announcement for me, because the IVM system will <em>actually</em> be useful even after the current AI bubble bursts. Building a new IVM system is no small feat, and I&#8217;d love to learn more about its implementation!</p></li></ul><p>And I have to mention <a href="https://blog.airy.co/airy-is-joining-confluent/">Airy&#8217;s acquisition</a> (acquihire?). Airy had a lot of experience with Flink AND LLMs, so this move makes a lot of sense.</p><p><a href="https://www.confluent.io/blog/introducing-confluent-private-cloud/">Confluent Private Cloud</a> is another big announcement worth mentioning. Confluent is going to offer a flavour of its cloud product for on-prem deployments. But I&#8217;m confused: they already have Confluent Platform for that (which still generates a lot of revenue), so will Private Cloud replace Platform? Complement it? Evolve it? Someone, please clarify. You could also say that WarpStream is another on-prem product offered by Confluent, so will they compete? </p><p>By the way, WarpStream was mentioned for about 10 seconds in a 2-hour keynote. I understand they still operate as a separate org, but they build a lot of cool features. Please share them with the world!</p><p>Another series of announcements was about Tableflow. Support for Delta Lake and Unity Catalog is now GA. They also released upserts and DLQs (Dead Letter Queues). It&#8217;s funny to see how much Confluent invests in better supporting Databricks as a partner, while <a href="https://www.databricks.com/blog/announcing-public-preview-zerobus-ingest">Databricks is working</a> on a data ingestion solution that doesn&#8217;t require Kafka&#8230;</p><p>Most of the other announcements can be found <a href="https://www.confluent.io/blog/2025-q4-confluent-cloud-launch/">here</a>.</p><p>Other random observations:</p><ul><li><p>Jay Kreps (CEO @ Confluent) noticed the importance of Flink <em>batch</em> jobs for iterating on data.</p></li><li><p>Shawn Clowes (CPO @ Confluent), about Flink: &#8220;One of the most <em>successful</em> products we&#8217;ve ever launched as a company&#8221;.</p></li><li><p>Also from Shawn: we have &#8220;the <em>largest</em> number of connectors in the entire streaming ecosystem&#8221;. Seems like it&#8217;s targeting Redpanda Connect (which claims a higher number of connectors). </p></li></ul><h3>AI</h3><p>Stateful computations such as aggregations, joins and windowing, as well as products like Streaming Agents and Real-Time Context Engine, enable Flink to do one thing really well: build context for LLMs. I don&#8217;t think it&#8217;s currently capable of much more than that, but building real-time, highly personalized and relevant context is already a big win. As I mentioned above, I don&#8217;t believe we should be calling it an agentic framework, but does it really matter?</p><p>&#8220;Just&#8221; being the best way to build LLM context should make data streaming extremely attractive in the current AI hype cycle. </p><p>Confluent announced Real-Time Context Engine last week, but some companies have been working on similar approaches for a while. For example, check the <a href="https://www.deltastream.io/blog/">DeltaStream blog</a>, which shares many concrete use cases for building context using Flink stateful operations and then calling LLMs.</p><p>Of course, aside from the announcements, AI was a hot topic in many private conversations I had. In person, most people are not very impressed with the current AI tooling (just as I am), to say the least. <a href="https://www.linkedin.com/feed/update/urn:li:activity:7389635987397738496/">Stanislav Kozlovski nicely summarized</a> my concerns, and he didn&#8217;t even touch on the moral or environmental considerations. And, sometimes, I feel like <a href="https://bsky.app/profile/noethematt.bsky.social/post/3m4aqwrmqtk2r">Emma Thompson</a>. </p><p>I can&#8217;t say what&#8217;s going to happen, but I feel like we&#8217;re in some sort of bubble. If you overly rely on AI tools right now, my suggestion is to have a backup plan (for when the underlying service either completely disappears or increases its price by 10x - 100x). </p><h3>Interesting Talks</h3><p>Here are some of the interesting talks I&#8217;ve had a chance to attend.</p><h4>FlinkSketch: Democratizing the Benefits of Sketches for the Flink Community</h4><p>This was a short, lightning talk about <a href="https://github.com/ProjectASAP/FlinkSketch">FlinkSketch</a>: a library of sketching algorithms for Flink. I think this library deserves more attention: it&#8217;s very common to use Flink for streaming analytics and generating ML features, both of which typically rely on windowed aggregations.</p><p>Sketching algorithms can significantly reduce resource usage (e.g., memory) while slightly sacrificing accuracy. This is a great compromise for many workloads.</p><h4>Change Data Capture at Scale: Insights from Slack&#8217;s Streaming Pipeline</h4><p>This was a talk about the Change Data Capture architecture for Slack&#8217;s sharded MySQL setup (Vitess). I really liked the very methodical approach to performance optimizations; it can be generally applied to most data-intensive applications.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UVUK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UVUK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 424w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 848w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 1272w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UVUK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:380161,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/177483816?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UVUK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 424w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 848w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 1272w, https://substackcdn.com/image/fetch/$s_!UVUK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d13ccaa-9886-4eeb-9170-36dac041198f_3466x1981.heic 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Making agents, workflows, and event-driven apps as simple as SpringBoot, with Restate</h4><p>The latest demo of <a href="https://www.restate.dev/">Restate</a>, a durable execution engine. Even if you&#8217;re somewhat familiar with the product, it might still be worth watching: I was surprised to discover it now comes with a very powerful UI for introspecting any aspect of execution. </p><p>I&#8217;m not sure if it was recorded at all, but if it was, watch the recording until the end. You may hear a Grammy-winning marching band crashing the talk (only in New Orleans!) </p><h4>StreamLink: Real-Time Data Ingestion at OpenAI Scale</h4><p>Insightful talk about OpenAI&#8217;s Flink infrastructure in the context of data ingestion. OpenAI uses YAML files for topic configuration (surprise) with the ability to add any topic for data lake ingestion. I also liked the clever use of Airflow sensors to mark partitions as completed.</p><p>In addition, they covered many details about their Flink control plane called Watchdog, which relies on the Flink Kubernetes Operator. Some great learnings here about the Flink Table API challenges and issues with job restarts.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SPUM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SPUM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 424w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 848w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 1272w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SPUM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic" width="1456" height="906" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:906,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:261188,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/177483816?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SPUM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 424w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 848w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 1272w, https://substackcdn.com/image/fetch/$s_!SPUM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b700b4-9250-45bf-833e-368c86131b23_2872x1787.heic 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Sizing, Benchmarking and Performance Tuning Apache Flink Clusters</h4><p>Great talk from Robert Metzger, Flink PMC. A lot of it was about establishing a systematic approach to performance engineering, including setting a baseline, running experiments, and employing first-principles thinking. He also talked about choosing between horizontal and vertical scaling, tuning RocksDB and Kafka producers, as well as tweaking Flink memory.</p><p>If you are interested in improving the performance of your Flink pipelines, you may want to scroll to the end of the newsletter &#128521;.</p><h4>Press Play on Data: Netflix&#8217;s Journey from Streams to Gaming Insights</h4><p>Great talk about Netflix&#8217;s Streaming SQL (Flink) infrastructure and a specific gaming insights use case. I like how many guardrails and validation checks it has, which are absolutely necessary when operating thousands of Flink pipelines. </p><p>Many gaming-related challenges reminded me of the challenges we faced back at Activision: even though the games could be very different, collecting, analyzing and storing telemetry data can be similar.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dSYm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dSYm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 424w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 848w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 1272w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dSYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic" width="1456" height="835" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:835,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:560245,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/177483816?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dSYm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 424w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 848w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 1272w, https://substackcdn.com/image/fetch/$s_!dSYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a42d17-15f7-4b38-a7ab-362257341e36_3630x2083.heic 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Redpanda Resistance</h3><p>As you may recall, Redpanda <a href="https://www.streamingdata.tech/i/163988023/kafka-summit-current">was banned</a> from Current London earlier this year. It looks like the ban is still in effect, but Redpanda is not giving up. </p><p>In addition to buying ads in the New Orleans airport (which happened to run after the Confluent ones), they also set up a camp directly across the street from the conference venue. They had <a href="https://www.linkedin.com/posts/redpanda-data_current2025-streamingdata-currentnola-activity-7389339053126709248-E7rU/">puppies, ice cream and good vibes</a>.</p><p>By the way, a day before Current, Redpanda announced a new <a href="https://www.redpanda.com/blog/agentic-data-plane-adp">Agentic Data Plane</a>, as well as the <a href="https://www.oxla.com/">Oxla</a> acquisition, which will allow them to offer a SQL query engine on top of their data. I&#8217;m particularly excited about it because SQL is useful not just for agents!</p><p>You can learn more at <a href="https://www.redpanda.com/streamfest">Redpanda Streamfest</a> later this week.</p><h3>Confluent Catalysts</h3><p>I&#8217;m thrilled to be in the <a href="https://developer.confluent.io/catalysts/">Confluent Community Class of 2025 - 2026</a>! I attribute this to the newsletter you&#8217;re reading, so thank you A LOT for that!</p><div><hr></div><h3>Upstream: New Webinar Series </h3><p>I was fortunate enough to be the first guest on a new webinar series called Upstream by Jan Siekierski, you can watch the first episode <a href="https://www.youtube.com/watch?v=X6Ukpi2p4y4">here</a>.</p><div id="youtube2-X6Ukpi2p4y4" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;X6Ukpi2p4y4&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/X6Ukpi2p4y4?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><h3>Data Streaming Academy</h3><p>I&#8217;ve recently announced <a href="https://streamacademy.io/">Data Streaming Academy</a>: the best place to master data streaming technologies. Join the <a href="https://streamacademy.io/#waitlist">waitlist</a> now to be notified about the upcoming Advanced Apache Flink bootcamp. </p>]]></content:encoded></item><item><title><![CDATA[Announcing Data Streaming Academy]]></title><description><![CDATA[The best place to master data streaming technologies.]]></description><link>https://www.streamingdata.tech/p/announcing-data-streaming-academy</link><guid isPermaLink="false">https://www.streamingdata.tech/p/announcing-data-streaming-academy</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 27 Oct 2025 16:18:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/56e674f0-15cf-4d79-8fc8-fd95a1594c59_1426x1001.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the past few years, many of you have suggested the same thing: <em>&#8220;You should write a book or launch a course.&#8221;</em> It&#8217;s something I&#8217;ve always taken seriously (even started writing a book during Covid), but the time commitment never quite aligned with having a full-time job. </p><p>This past year, however, has been one of exploration: building a developer tooling company, consulting, and doing a lot more writing. So I started thinking: maybe this is the right moment to experiment with education too.</p><p>So today I&#8217;m announcing <strong>Data Streaming Academy</strong>: the best place to master data streaming technologies. I&#8217;m going to kick off with a hands-on, deeply technical development bootcamp dedicated to Apache Flink: <strong>Advanced Apache Flink Bootcamp</strong>.</p><p>There are many resources online dedicated to Flink, but most of them are only helpful when you&#8217;re just starting. It&#8217;s really hard to find advice and best practices based on the years of experience actually running Flink in production. And this is exactly what I offer. We&#8217;ll go deep into the DataStream and Table APIs, understand the internals of connectors, and, most importantly, learn how to make Flink pipelines resilient, scalable, and observable. </p><p>So, here it is: <strong><a href="https://streamacademy.io/">StreamAcademy.io</a>.</strong> </p><p>If you&#8217;re even remotely interested in learning Flink or other data streaming technologies, join <a href="https://streamacademy.io/#waitlist">the waitlist</a> - it&#8217;s the only way to get early access (and discounted pricing). </p><p>And if you&#8217;d like to influence which modules or future courses come next, please share your input by filling out <a href="https://forms.gle/YRJ5hfqZkKzPDgWM7">this form</a>.</p>]]></content:encoded></item><item><title><![CDATA[Flink Forward 2025]]></title><description><![CDATA[Conference highlights.]]></description><link>https://www.streamingdata.tech/p/flink-forward-2025</link><guid isPermaLink="false">https://www.streamingdata.tech/p/flink-forward-2025</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Wed, 22 Oct 2025 15:51:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/44d349e5-2759-42c4-98c2-d00752490437_4032x3024.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Flink Forward</strong> conference happened last week in Barcelona, Spain. It&#8217;s the main Apache Flink event organized by Ververica, which includes many practitioners from companies like Netflix, Apple, Shopify, LinkedIn, etc.</p><h3>Ververica Announcements</h3><p>Ververica has made several announcements during the keynote:</p><ul><li><p><a href="https://fluss.apache.org/">Apache Fluss</a> is now available in the Ververica Platform. This makes a lot of sense given the significant investment in the project. </p></li><li><p><a href="https://www.ververica.com/blog/vera-x-introducing-the-first-native-vectorized-apache-flink-engine">VERA-X</a>: A native vectorized Apache Flink engine. I share some thoughts below.</p></li><li><p>&#8220;Real-Time AI With Rag And LLM Support&#8221;: It sounds fancy, but in practice, it typically means having a few UDFs that call OpenAI APIs, which is not that exciting. Also, RAG is so last year! &#128578; </p></li></ul><p>The rest of the keynote was a bit underwhelming, but I did appreciate Ben Gamble&#8217;s whirlwind demo of the latest features, like the Delta join.</p><p>&#8220;AI co-host&#8221; was very cringe. Please don&#8217;t do it.</p><h3>VERA-X</h3><p>Here&#8217;s my reaction:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5B2n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5B2n!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 424w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 848w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 1272w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5B2n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png" width="728" height="546.9629629629629" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/db41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:852,&quot;width&quot;:1134,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:627693,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/176212846?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5B2n!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 424w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 848w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 1272w, https://substackcdn.com/image/fetch/$s_!5B2n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb41ed09-34a1-402f-8d9a-fde01881d04a_1134x852.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As I said, VERA-X is not a new product; Alibaba has been working on it for years (under the name <a href="https://www.alibabacloud.com/blog/flash-a-next-gen-vectorized-stream-processing-engine-compatible-with-apache-flink_602088">Flash</a>).</p><p>After studying the implementation details, I was surprised to realize how similar it is to Iron Vector. E.g., having specialized Row-to-Column and Column-to-Row operations, columnar UDF support, a memory manager, etc.</p><p>I&#8217;m <em>really</em> excited about this direction. People have tried to replace Flink with new stream-processing engines, but they haven&#8217;t succeeded. I think Iron Vector or VERA-X is a healthier approach to getting a significant runtime upgrade.</p><h3>The Atmosphere on the Ground</h3><p>The event felt on the smaller side. Only a handful of sponsors and no real &#8220;expo hall&#8221;. When talks started, the hallways immediately emptied, which to me indicates the large number of engineers in attendance. And whenever I talked to someone in the crowd, they almost always ended up being an engineer or a manager closely involved in using or building on top of Flink.</p><p>I also heard many questions like &#8220;Why do you think data streaming is not getting enough adoption?&#8221;. I have some thoughts, so stay tuned. In the meantime, I&#8217;d be curious to compare this event to Current next week. </p><h3>Interesting Talks</h3><h4>The *Big State* Monster: Taming State Size in Multi-Way Joins with FLIP-516</h4><p>Great overview of a problem with large joins: they can grow in complexity and state size very quickly. For example, multi-step joins are usually translated into a chain of binary joins, which explodes the state.</p><p>The new multi-way join operator can alleviate this problem (and multi-way joins can also be chained to support complex topologies).</p><p>This reminds me of <a href="https://www.youtube.com/watch?v=tiGxEGPyqCg">the work we did at Shopify</a> to support joins of 10+ streams.</p><h4>Apache Fluss and the Seven Deadly Sins of Streaming Analytics</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qZUU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qZUU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qZUU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic" width="728" height="546" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:1252714,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/176212846?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qZUU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 424w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 848w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 1272w, https://substackcdn.com/image/fetch/$s_!qZUU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652bf099-2896-4d96-ab7b-3c4d58ddf198_4032x3024.heic 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Great talk. The reasoning behind Fluss is solid - I&#8217;m sold! The adoption is lacking, and the fact that Fluss doesn&#8217;t support the Kafka protocol (and may never will!) is not helping. Still, I hope Fluss will get more recognition. </p><h4>Petabytes, Pipelines &amp; PyFlink: How We Stream, Enrich &amp; Validate Billions of Events</h4><p>Good talk showing how to build data pipelines with PyFlink. Mentions advanced concepts like data enrichment, DLQs, etc.</p><h4>Redefining Flink Reliability &#8212; Blue/Green Deployments in Production</h4><p>Blue/Green deployments were one of the key features absent from the Flink Kubernetes Operator. However, basic support for Blue/Green has been added in recent versions. This is a good talk covering the reasons why you may want to use it, along with lots of gotchas and implementation details. Make sure to listen to the Q&amp;A after the talk.</p><h4>Democratizing Flink SQL at Shopify: Scaling Streaming for Every Developer</h4><p>In my opinion, my ex-coworker Ryan delivered the best talk of the conference.</p><p>Shopify has been busy building an impressive developer experience for Flink. A custom VS Code extension is at the center of it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mu68!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mu68!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 424w, https://substackcdn.com/image/fetch/$s_!mu68!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 848w, https://substackcdn.com/image/fetch/$s_!mu68!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 1272w, https://substackcdn.com/image/fetch/$s_!mu68!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mu68!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png" width="1456" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:453047,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/176212846?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mu68!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 424w, https://substackcdn.com/image/fetch/$s_!mu68!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 848w, https://substackcdn.com/image/fetch/$s_!mu68!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 1272w, https://substackcdn.com/image/fetch/$s_!mu68!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F531f9d42-4b33-44a4-8ee9-7c2a22e7ade1_2204x1060.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It offers:</p><ul><li><p>Flink Notebook experience right in your IDE</p></li><li><p>Flink Catalog integration</p></li><li><p>Access to local and remote Flink session clusters</p></li><li><p>CLI tool for creating UDFs</p></li></ul><p>It seems to be inspired by <a href="https://github.com/eBay/Flink-SQL-Extension">this project</a> from eBay. Shopify is planning to open-source its extension as well. </p><p>The talk also covered a brief history of Flink at Shopify, Stream/Batch unification efforts and their K8S setup for Flink.</p><h4>Flink SQL 2025: Powering Real-Time AI and Stream Processing Innovations</h4><p>A good overview of the latest additions to Flink SQL: things like CREATE MODEL and ML_PREDICT for working with LLMs, VARIANT type for making it easier to work with JSON, Delta and Multi-way Joins.</p><h4>Powering Stateful Joins at Scale with Flink SQL at LinkedIn</h4><p>This talk describes some of the internals of the managed streaming SQL platform at LinkedIn, focusing on practical challenges when running a large stateful Flink pipeline. </p><p>A few interesting observations: </p><ul><li><p>LinkedIn still uses Flink 1.16 (released exactly 3 years ago!)</p></li><li><p>They switched from SATA SSDs to NVMe SSDs to boost IO performance (duh). Whenever someone asks me how to speed up a stateful Flink pipeline, my top answer is always: use the fastest SSDs you can get.</p></li></ul><h4>Dynamic, Scalable, and Schema-Evolving: Introducing the Flink Dynamic Iceberg Sink</h4><p>A must-watch if you use Apache Iceberg sink with Flink.</p><div><hr></div><p>There were many more great talks I didn&#8217;t have a chance to attend. The recordings will be available soon, and I highly recommend checking them out.</p><div><hr></div><h3>Irontools</h3><p><a href="https://irontools.dev/product/iron-vector/">Iron Vector</a> is a native, columnar, vectorized, high-performance accelerator for Apache Flink SQL and Table API pipelines.</p><p>It&#8217;s easy to install, requires no code changes, and can increase compute efficiency by up to 2x (as of now).</p><p>Check the announcement <a href="https://irontools.dev/blog/introducing-iron-vector/">here</a>.</p><div><hr></div><h3>Events</h3><p>Find me at <a href="https://current.confluent.io/new-orleans">Current, New Orleans</a> &#127482;&#127480; next week (October 29th - October 30th).</p><p></p>]]></content:encoded></item><item><title><![CDATA[Streaming and the RAD Stack]]></title><description><![CDATA[RAD: Rust, Arrow, DataFusion]]></description><link>https://www.streamingdata.tech/p/streaming-and-the-rad-stack</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-and-the-rad-stack</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 22 Sep 2025 15:56:40 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a50516aa-d86c-4b0a-a066-b7791b886c16_1260x900.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Earlier this year, I wrote a post about exploring Apache DataFusion as a foundation for a streaming framework:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;8a673446-474e-4a9c-8dab-551f46749a7c&quot;,&quot;caption&quot;:&quot;Please pledge your support if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Exploring Apache DataFusion as a Foundation for Streaming Framework&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-02-10T16:57:53.055Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22480225-6681-4cd6-aa74-153c77f571e5_840x600.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/exploring-apache-datafusion-streaming-framework&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:155738973,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:9,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!_lyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>At the time, it was mostly theoretical: I had started working on a streaming framework for a client of mine, and I only had a couple of months of Rust and DataFusion experience. </p><p>Over the course of this year, the framework became feature-complete, and it&#8217;s being integrated as a core product offering. I hope to write more about it one day; there is a plan to open-source it eventually. </p><p>At the same time, I started to work on the new <a href="https://irontools.dev/">Irontools</a> extension called <a href="https://irontools.dev/product/iron-vector/">Iron Vector</a>. It&#8217;s a native, columnar, vectorized, high-performance accelerator for Apache Flink SQL and Table API pipelines. I&#8217;m building it with Rust, Arrow and DataFusion. Feel free to check the announcement post with more details <a href="https://irontools.dev/blog/introducing-iron-vector/">here</a>.</p><p>So, this post is my attempt to summarize my actual, hands-on learnings from building several streaming products with what I call <strong>the RAD Stack: Rust, Arrow, DataFusion.</strong></p><h3>Following Up </h3><p>First, let me follow up on a few key areas I identified in the previous post.</p><h4>Checkpointing and Fault Tolerance</h4><p>I implemented the classic Chandy&#8211;Lamport style algorithm for checkpointing. I also added a simple, pluggable state backend (with Postgres support being the target). </p><p>The main use case for this was storing Kafka consumer group offsets, but only when all nodes in a pipeline acknowledge processing (up to a certain epoch). You get at-least-once delivery guarantee. </p><p>The implementation was pretty straightforward. It&#8217;s important to have decent test coverage to catch edge cases.</p><p>I really liked Postgres as the main state backend: it&#8217;s perfect for storing small amounts of data (like the consumer offsets). If you need to modify the consumer position, you just modify a table row in Postgres. </p><p>If I were to look at storing larger amounts of data, I&#8217;d seriously consider using <a href="https://slatedb.io/">SlateDB</a>.</p><h4>Scaling Out Beyond a Single Node</h4><p>As you probably guessed, we ended up relying on Kafka consumer groups quite a bit, Kafka Streams style. You can spin up many pods in parallel; each gets its own share of partitions. Adding autoscaling can be pretty straightforward. </p><p>In other scenarios, we could rely on the data source characteristics to parallelize data processing. E.g., if a data source supports range scanning, it&#8217;s possible to spin up several pods in parallel and assign a different range to each. It&#8217;s definitely not a generic solution. </p><p>Also, in many situations, having just a single pod was enough. You can go pretty far with vertical scaling.</p><p>I didn&#8217;t have a chance to explore <a href="https://datafusion.apache.org/ballista/">Ballista</a> or <a href="https://www.ray.io/">Ray</a>. </p><h4>Connectors: Building Your Own</h4><p>I built several connectors (typically implemented as <a href="https://datafusion.apache.org/library-user-guide/custom-table-providers.html">TableProviders</a>), but there are no interesting insights to share: you take an external client, wrap it into DataFusion primitives, hook it up to the checkpointing system, and it&#8217;s done. Converting to/from Arrow can be tricky, but Arrow support is getting better<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>I do want to share my experience about using <a href="https://github.com/datafusion-contrib/datafusion-table-providers">datafusion-table-providers</a>: a <em>somewhat</em> official repository of the community &#8220;connectors&#8221; (TableProviders). </p><p>My experience aligns with the observation I&#8217;ll make below in the post: there is just not much awareness about streaming use cases at the moment. Look at the way <a href="https://github.com/datafusion-contrib/datafusion-table-providers/blob/main/core/src/postgres/write.rs">the Postgres sink</a> is implemented:</p><ul><li><p>It starts a transaction</p></li><li><p>It writes all input RecordBatch records as inserts. <em>It keeps writing until the input stream is terminated</em>:</p><ul><li><p>while let Some(batch) = data.next().await</p></li></ul></li><li><p>Finally, it commits the transaction</p></li></ul><p>Can you see the problem? <em>The input stream never ends</em> when running in the streaming environment. So this logic has to be modified to introduce triggers (e.g. record-based or time-based) to periodically commit the current transaction and start a new one.</p><h3>Implementing a Plugin System</h3><p>If you build a connector (or any kind of library) using Java, you typically just need to:</p><ul><li><p>Implement a certain interface </p></li><li><p>Package it in a JAR file </p></li><li><p>Make it available in the classpath, either by using a dependency manager or simply adding the JAR file to the classpath</p></li></ul><p>This is not the case with compiled languages like Rust. With Rust, the path of the least resistance is building static binaries. This means recompiling your application <em>every time you change any of your dependencies</em>, including external libraries. This can be very painful at scale or when dealing with external contributions. </p><p>Using dynamic, not static linking, is the typical answer to this problem. However, dynamic linking with Rust comes with its own challenges. Rust ABI is unstable, so a minor Rust version difference (or even having different compiler flags enabled) can lead to compatibility issues. </p><p>Using Foreign Function Interface (FFI) and crates like the <a href="https://crates.io/crates/abi_stable">abi_stable</a> is the standard workaround. But it&#8217;s not for the faint of heart! There is a great post series called <a href="https://nullderef.com/series/rust-plugins/">A Plugin System in Rust</a> that walks you through the implementation end-to-end, covering many learnings along the way. However, even if you follow all best practices, you can still end up with many unsolved problems. For example, there are no good solutions to share Tokio runtimes. So, if your plugin needs to perform async functions (and it almost certainly does), you have a choice between creating a Tokio runtime per plugin (which becomes prohibitively expensive with every plugin you add) or exposing a small subset of functionality via FFI-safe structures (thanks to <a href="https://docs.rs/async-ffi/latest/async_ffi/">async_ffi</a>).</p><p>Whew, I know. It&#8217;s messy.</p><h3>Performance Gain Is Visible</h3><p>Performance is one of the reasons we&#8217;re doing it in the first place, and oh boy, it delivers. I ran hundreds of benchmarks for the past few months, and it&#8217;s not uncommon to see 2x, 3x or even 5x throughput increase after rewriting something with the RAD stack. I believe Arrow is one of the reasons behind it. Columnar, vectorized execution can be much more efficient for streaming workloads. </p><p>This aligns with benchmarks by Arroyo (which claimed 3x - 5x throughput increase) and <a href="https://risingwave.com/blog/the-preview-of-stream-processing-performance-report-apache-flink-and-risingwave-comparison/">RisingWave</a> (with 2x throughput increase as a norm for stateless workloads).</p><p>DataFusion is not <em>that</em> high in the <a href="https://benchmark.clickhouse.com/">ClickBench results</a>, but it doesn&#8217;t mean it&#8217;s not fast. It&#8217;s just that there are faster solutions for certain types of queries, but none of which come even close when it comes to extensibility, which is covered in the next section.</p><h3>Extending DataFusion: Lessons Learned</h3><p>DataFusion was initially designed as a batch query engine. There were many improvements over the years to make it more compatible with streaming semantics. Sometimes, the batch nature is very obvious (e.g. operators with EmissionType::Final: <em>Records are only emitted once all input has been processed</em>). But sometimes, it&#8217;s so subtle that it&#8217;s very hard to notice until you hit issues in production.</p><h4>Pay Attention to Your Functions</h4><p>DataFusion has a variety of standard system functions commonly found in any SQL database: comparison, string, math, etc. Most of the functions are either <strong>immutable</strong> (<em>always return the same output when given the same input</em>) or <strong>volatile</strong> (<em>may change the return value from evaluation to evaluation</em>). </p><p>There are also several <strong>stable</strong> functions. From documentation:</p><pre><code><em>A stable function may return different values given the same input across different queries but must return the same value for a given input within a query.</em></code></pre><p>These functions are now(), current_time() and current_date(). From the batch engine perspective, it may make sense to keep the value of now() the same during the execution of a given query. However, in the streaming context, we only have one never-ending query! This means that by default, now() will always return the same value (captured as the beginning of execution), even if called a week after the streaming query was started. </p><p>Thankfully, it&#8217;s very easy to come up with custom implementations of those functions that are basically the same as the built-in ones, but marked as Volatile. Then it&#8217;s trivial to override a system function with a custom function that has the same name: DataFusion doesn&#8217;t really differentiate between system and user-defined functions. They use exactly the same API and registration mechanism. </p><h4>Stateless and Incremental Doesn&#8217;t Mean Streaming Friendly</h4><p>Projections and filters form the foundation of stateless stream processing. Surely such primitive operators support streaming execution. <a href="https://i.imgflip.com/a6iu6j.jpg">Right? Right???</a></p><p>Well, kinda. Let&#8217;s look at the filter (FilterExec operator). It propagates the input emission type, so if the input emits data incrementally, the filter operator does the same.</p><p>However, there is one implementation detail that can come back to haunt you. If the filter operator filters out <em>all</em> rows from the current batch, it doesn&#8217;t emit an empty batch. Instead, it just waits for the next batch that&#8217;s not empty &#129760;. This is ok for the batch engine, but a streaming system could be relying on a continuous stream of batches (even empty ones) for many reasons (e.g. observability). </p><p>And again, DataFusion makes it very easy to replace the built-in filter operator with a custom one. Just fork it, tweak the logic, and then add a PhysicalOptimizerRule that replaces any FilterExec with your custom operator. It takes a few lines of code. Seriously, is there a query engine out there that allows you to replace the operator behind such an important, fundamental feature (a WHERE clause) with this kind of simplicity?</p><h4>Not Optimizing Is Sometimes a Good Thing</h4><p>Imagine you have an Iceberg table as a data source and you want to run two queries against it. Naturally, these queries have different projections and filters. Any reasonable query engine implements optimizations like projection and predicate pushdown, which limit the amount of data returned by the source. From the query plan perspective, you query the same table twice, but you expect different outputs. </p><p>Now, take a Kafka topic as a data source. Kafka doesn&#8217;t support projection or predicate pushdown<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. And when you issue two queries with different projections and filters, you actually DO want to query this source <em>once</em>, and apply the projections and filters <em>later</em>. I believe it&#8217;s called <em>scan sharing</em> in some literature. But it&#8217;s not the way DataFusion (and most query engines) are designed to behave, so you end up reading the same topic multiple times, even though it could&#8217;ve been done just once. </p><p>I haven&#8217;t implemented a good workaround for this just yet, but I believe it&#8217;ll involve disabling certain optimizer rules and broadcasting the data from one operator to many. Btw, Apache Flink has scan sharing implemented: you can find the <em>reuse</em> marker in its query plans.</p><p>I could go on, but I think these findings paint a clear picture: DataFusion is extensible enough to support anything you want, but it takes some effort to get there.</p><h3>Community Alignment Is Not Quite There</h3><p>As you probably understand by now, streaming support is not a very high priority for the DataFusion project. It feels like, sometimes, it happens to support some streaming primitives by accident (and because it&#8217;s actually a very good thing to do even in many batch-oriented scenarios). </p><p>However, the community is generally interested in this:</p><ul><li><p><a href="https://github.com/apache/datafusion/issues/4285">[Proposal] Streaming execution support roadmap</a></p></li><li><p><a href="https://github.com/apache/datafusion/issues/11404">[DISCUSSION] Support for Streaming in DataFusion</a></p></li></ul><p>So, I think it&#8217;s just a matter of time and the number of contributors involved. Folks from <a href="https://www.synnada.ai/">Synnada</a> have been contributing a lot on the streaming side, and I&#8217;m very grateful for that! I hope that more contributors can start thinking about streaming scenarios, e.g. modifying that Postgres sink to support streaming execution can actually be beneficial for batch workloads too (you don&#8217;t want to keep open transactions for long).</p><h3>Conclusion</h3><p><a href="https://github.com/rewrite-bigdata-in-rust/RBIR">Rewriting Bigdata in Rust</a> is slowly happening. Arrow is becoming the standard for data exchange. I haven&#8217;t even mentioned <a href="https://arrow.apache.org/docs/format/Flight.html">Arrow Flight</a>, <a href="https://arrow.apache.org/adbc/current/index.html">ADBC</a> and <a href="https://substrait.io/">Substrait</a> (which Iron Vector uses). </p><p>Overall efficiency (and cost efficiency in particular) has been quite a focus in the past few years. I hope <strong>the RAD stack</strong> is here to stay: let&#8217;s try to get more from the infrastructure we have.</p><div><hr></div><h3>Irontools</h3><p><a href="https://irontools.dev/product/iron-vector/">Iron Vector</a> is a native, columnar, vectorized, high-performance accelerator for Apache Flink SQL and Table API pipelines.</p><p>It&#8217;s easy to install, requires no code changes, and can increase compute efficiency by up to 2x (as of now).</p><p>Check the announcement <a href="https://irontools.dev/blog/introducing-iron-vector/">here</a>.</p><div><hr></div><h3>Events</h3><p>Find me at the following events next month:</p><ul><li><p><a href="https://www.polyglotsoftware.com/">Polyglot Unconference</a>, Vancouver &#127464;&#127462;, October 11th</p></li><li><p><a href="https://www.flink-forward.org/barcelona-2025">Flink Forward</a>, Barcelona &#127466;&#127480;, October 15th - October 16th</p></li><li><p><a href="https://current.confluent.io/new-orleans">Current</a>, New Orleans &#127482;&#127480;, October 29th - October 30th</p></li></ul><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Also, this is one of the areas where LLMs can really shine: hand-writing boilerplate conversion logic from one format to another is no fun.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>You could filter data by partition or by the Kafka message timestamp, but that&#8217;s pretty much it.</p></div></div>]]></content:encoded></item><item><title><![CDATA[No More Excuses for Stream/Table Duality]]></title><description><![CDATA[Kafka IS your LakeHouse now, accept it.]]></description><link>https://www.streamingdata.tech/p/no-more-excuses-for-streamtable-duality</link><guid isPermaLink="false">https://www.streamingdata.tech/p/no-more-excuses-for-streamtable-duality</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 18 Aug 2025 16:02:02 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8f9d60c5-6566-4a76-bc11-10e50a9dda97_1434x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week, <a href="https://aiven.io/blog/iceberg-topics-for-apache-kafka-zero-etl-zero-copy">Aiven announced</a> a free, open-source implementation of Apache Iceberg support for Apache Kafka topics. This is such an important milestone that I decided to take a quick break from building <a href="https://irontools.dev/">Irontools</a> and write this short post.</p><p>Many Kafka vendors already support Iceberg sync (Confluent, Redpanda, Bufstream, Streambased), but this seems to be the first <strong>free</strong> and <strong>open-source</strong> implementation<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. </p><p>It&#8217;s not quite production-ready at the moment (it needs to at least support basic schema evolution), but I imagine they&#8217;ll catch up quickly.</p><p>I don&#8217;t want to rephrase many posts about why Iceberg is important for Kafka. Feel free to check Aiven&#8217;s announcement, as well as posts from other companies:</p><ul><li><p><a href="https://www.confluent.io/blog/introducing-tableflow/">Introducing Tableflow</a> from Confluent </p></li><li><p><a href="https://www.redpanda.com/blog/apache-iceberg-topics-streaming-data">Apache Iceberg Topics: Stream directly into your data lake</a> from Redpanda</p></li></ul><h3>Single-Copy Implementation </h3><p>Perhaps the most interesting implementation detail mentioned in the <a href="https://github.com/Aiven-Open/tiered-storage-for-apache-kafka/blob/main/iceberg_whitepaper.md">whitepaper</a> is the absence of data copying. Log segments are converted to Parquet files and stored in the object storage. These files are used <strong>both</strong> by the Iceberg reader, as well as the Kafka Tiered Storage components that serve Kafka requests. This likely means extra work on the fly, and it must affect read latency. This may sound like a bad idea, but I think it&#8217;s already proven - <a href="https://www.youtube.com/watch?v=M5UyngLQzzo">Streambased works in a similar fashion</a>.</p><h3>Streaming-First Architecture</h3><p>I wrote about Streaming-First Architecture last year:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f9192cea-9274-4030-a490-c9db716bcb0a&quot;,&quot;caption&quot;:&quot;Please pledge your support if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Streaming-First Architecture&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-09-02T15:47:29.914Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/077e4280-258f-4dca-8881-f907c768a799_420x300.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/streaming-first-archirecture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:147981517,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:8,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!_lyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>I believe it&#8217;s a very powerful way of building streaming data pipelines. However, I identified LakeHouse support as the last missing building block. But it&#8217;s no longer missing! I didn&#8217;t want to say this when Confluent or Redpanda made their announcements: in the end, those were proprietary products. But with Aiven&#8217;s latest release, we also have a free, open-source implementation that will surely drive the adoption. Maybe we&#8217;ll even see some unification (e.g., a standard set of Kafka metadata columns&#8230; a man can dream).</p><h3>Data Platforms in 2030</h3><p>And here&#8217;s another post I wrote a year before that:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3c367d0d-fc66-43ad-9c82-b4fa6a747511&quot;,&quot;caption&quot;:&quot;Spoiler alert: I&#8217;m not a psychic and don&#8217;t have a time machine, so I can&#8217;t really say what the data platforms will look like in 5-7 years. But I&#8217;ve been noticing some trends that are hard to ignore, so I wanted to make a prediction or two. Maybe there is also a bit of a wish list from me here &#128578;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Data Platforms in 2030&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-09-05T15:46:25.896Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa249188e-8320-4e3b-8eb0-b1a9c40f329d_1298x1180.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/data-platforms-in-2030&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:136208753,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:14,&quot;comment_count&quot;:4,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!_lyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>In that post, I described the idea of a &#8220;consolidated data engine&#8221;: tightly integrated streaming log (e.g. Kafka), a LakeHouse (e.g. Iceberg) and a fast OLAP database (e.g. ClickHouse). You can build almost any data product with that combo. </p><p>It&#8217;s 2025, and it seems like we&#8217;re already 2/3 there &#128526;. I&#8217;m really excited about the next 5 years!</p><div><hr></div><p><em>I&#8217;m building <a href="https://irontools.dev/">Irontools</a>: a suite of Apache Flink extensions to make your streaming pipelines faster, cheaper, and more flexible.</em> </p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>For <strong>Apache</strong> Kafka. There are Kafka-compatible products like AutoMQ that released their support earlier.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Current London 2025]]></title><description><![CDATA[Keynote]]></description><link>https://www.streamingdata.tech/p/current-london-2025</link><guid isPermaLink="false">https://www.streamingdata.tech/p/current-london-2025</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Thu, 29 May 2025 16:12:24 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/90984058-48ed-483c-9533-0c679076aaba_4032x3024.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Current London 2025</strong> happened last week in London, UK. I was fortunate enough to attend it, and I&#8217;d love to share some notes with you.</p><h3>Key Themes</h3><p>Of course, AI was everywhere: keynote, talks, and hallway chats. AI for coding, AI agents, AI for writing Flink jobs (!). It seems inevitable for any tech conference nowadays, regardless of its focus. To me, this is both exciting and scary; I&#8217;ll expand on this another day. </p><p>Iceberg, Tableflow, Delta Lake, and similar tech are still extremely relevant, but people seem to be more informed nowadays. The current version of Iceberg is not ideal for streaming, and it&#8217;s just terrible for changelog data streams. </p><p>Finally, I feel like the data streaming industry is still in a tough spot. The growth is slow, and the sales cycles are long. One person I spoke with said that &#8220;80% of the companies in the Expo hall will be dead in two years&#8221;. I don&#8217;t want to believe them, but it might be true. </p><h3>Keynote</h3><p>The keynote didn&#8217;t have any big, jaw-dropping announcements (I hope to see them in the next Current in New Orleans). </p><p>AI was obviously mentioned several times. Confluent&#8217;s messaging stays consistent over the years: AI needs data, specifically real-time data. But this year they introduced the idea of Flink jobs as AI agents! Coincedentaly, at the same time, <a href="https://cwiki.apache.org/confluence/display/FLINK/FLIP-531%3A+Initiate+Flink+Agents+as+a+new+Sub-Project">FLIP-531: Initiate Flink Agents as a new Sub-Project</a> was introduced, and 2/3 authors are Confluent employees. This tells me that Confluent is serious about the agents idea getting open-source adoption quickly.</p><p>One of the most interesting announcements for me was the snapshot queries. This is how I understood it:</p><ul><li><p>Confluent Flink SQL queries can operate in a &#8220;snapshot&#8221; / batch way: they don&#8217;t run continuously, but stop after getting initial (?) results.</p></li><li><p>If Tableflow is enabled for a source topic, the query leverages the underlying Iceberg storage first, and then switches to Kafka, if needed (?).</p></li></ul><p>This makes a lot of sense! I&#8217;ve been sharing this pattern for a while: Flink&#8217;s <a href="https://nightlies.apache.org/flink/flink-docs-release-1.20/docs/connectors/datastream/hybridsource/">HybridSource</a> makes it really straightforward to implement. It&#8217;s nice to see this as a fully managed product feature.</p><p>I also captured several great quotes during the keynote:</p><ul><li><p>&#8220;Apache Flink is the key to making shift left practical&#8221; (Shaun Clowes).</p></li><li><p>&#8220;With Flink, what was possible in the analytical estate, now is possible in the operational estate&#8221;  (Shaun Clowes).</p></li><li><p>&#8220;We don&#8217;t need ETL, we don&#8217;t need ELT&#8221;, in the context of Tableflow (Shaun Clowes).</p></li><li><p>&#8220;With Tableflow, your streams are tables&#8221; (Ahmed Saef Zamzam).</p></li><li><p>&#8220;Companies are becoming software&#8221; (Jay Kreps).</p></li></ul><h3>Talks</h3><p>Here are a few solid talks I had a chance to attend:</p><ul><li><p><strong>Flink Jobs as Agents &#129302; &#8211; Unlocking Agentic AI with Stream Processing</strong>. As I mentioned above, AI was everywhere. This talk showed a way to leverage Flink for building agents: using various sources and transformations to build context, performing actions using that context, and then consuming events emitted by those actions, which potentially affects the context. Steffen also mentioned using AI for creating Flink SQL pipelines (!) and Complex Event Processing (CEP). </p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!65jG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!65jG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 424w, https://substackcdn.com/image/fetch/$s_!65jG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 848w, https://substackcdn.com/image/fetch/$s_!65jG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 1272w, https://substackcdn.com/image/fetch/$s_!65jG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!65jG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic" width="1456" height="1080" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1080,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:758867,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/163988023?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!65jG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 424w, https://substackcdn.com/image/fetch/$s_!65jG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 848w, https://substackcdn.com/image/fetch/$s_!65jG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 1272w, https://substackcdn.com/image/fetch/$s_!65jG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d770596-eebc-4ab3-ae11-5303b6c68438_2500x1854.heic 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p><strong>Building Stream Processing Platform at OpenAI</strong>. Great coverage of OpenAI&#8217;s data platform and their challenges with PyFlink. OpenAI introduced proxies for consumers and producers, hiding cluster abstractions<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. This has a number of benefits, like straightforward HA, better scaling, etc. OpenAI heavily uses PyFlink; they shared their concerns about PyFlink's efficiency and lack of some features. </p></li><li><p><strong>FlinkSQL Powered Asynchronous Data Processing in Pinterest&#8217;s Rule Engine Platform</strong>. Pinterested shared some insights about their rule engine, which helps fight spam (one of many use cases). It was interesting to see backfilling mentioned as a first-class citizen: this is a very mature and pragmatic decision, I&#8217;d like to see more data streaming projects acknowledging it. </p></li><li><p><strong>Unified CDC Ingestion and Processing with Apache Flink and Iceberg</strong>. How far can you go to engineer a feature that&#8217;s not supported out of the box? Medidata Solutions and Decodable gave a masterclass &#128578;. They had to engineer a sophisticated system to handle changelog data streams in Flink Iceberg, which is not supported out of the box<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. </p></li><li><p><strong>Simplifying Real-Time Vector Store Ingestion with Apache Flink</strong>. This was another masterclass, specifically on writing SQL UDFs. I loved detailed code snippets shared by Hans-Peter: we need more hands-on talks like this one.</p></li><li><p><strong>Democratising Stream Processing: How Netflix Empowers Teams with Data Mesh and Streaming SQL</strong>. Netflix has been working on their internal data streaming platform for a while. It currently handles 14 trillion records a day (~160M/s on average), which is very impressive! Sujay talked about their latest initiative called &#8220;Data Mesh&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>, which offers a high-level interface for defining streaming sources, sinks, and processors (using Flink SQL). I liked how they rigorously rely on schemas to prevent breaking changes. Also, Data Mesh has some really neat features: Iceberg Lookup join, query preview, revision history, and autoscaling. Unfortunately, they still haven&#8217;t figured out updates for stateful Flink SQL jobs.  </p></li><li><p><strong>Flink SQL Revolutions: Breaking Out of the Matrix with PTFs</strong>. This talk is similar to previous talks by Timo about PTFs, but it has many neat examples! So, if you&#8217;re interested in learning about PTFs, I recommend this talk. At the end of it, I was convinced that when PTFs are mature and polished, the need to use the DataStream API will be significantly reduced.</p></li></ul><p>There were so many great talks I haven&#8217;t had a chance to watch! I&#8217;m eagerly waiting for the recordings of these:</p><ul><li><p>From Zero to Hero: petabyte-scale Tiered Storage lessons. </p></li><li><p>Building Stream Processing Platform at OpenAl.</p></li><li><p>Tableflow: Not Just Another Kafka-to-Iceberg Connector. </p></li><li><p>Queues for Kafka.</p></li><li><p>&#8230; and many more!</p></li></ul><h3>Kafka Summit &#8594; Current</h3><p>This was the first Current London. Last year and a few years before, London hosted Kafka Summits. </p><p>When <a href="https://www.confluent.io/blog/introducing-current-next-generation-of-kafka-summit/">Confluent announced Current as the next generation of Kafka Summit</a>, they talked about &#8220;<strong>a place for everyone in the ecosystem to come together and share their knowledge and best practices</strong>&#8221;.  Hilariously, the reality was quite the opposite. </p><p><a href="https://www.linkedin.com/posts/redpanda-data_currentlondon-current25-kafka-activity-7330614591606902785-61Lp/">Redpanda was banned from participating in the event</a>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bC5z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bC5z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 424w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 848w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 1272w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bC5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png" width="1150" height="652" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:652,&quot;width&quot;:1150,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:142325,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.streamingdata.tech/i/163988023?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bC5z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 424w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 848w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 1272w, https://substackcdn.com/image/fetch/$s_!bC5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da4a2c7-f8e6-4ab7-ae77-cebd4c5e6671_1150x652.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I don&#8217;t know the details, but I got a confirmation from several Redpanda employees. </p><p>I guess this could&#8217;ve been one of the reasons to rebrand the <strong>community</strong> Kafka Summit conference, an event about the open-source Apache Kafka technology, into a <strong>vendor-specific</strong> event<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. </p><p>Also, AWS didn&#8217;t have a booth at the conference despite being a gold sponsor (most of the other gold sponsors had presence). I can&#8217;t say why. AWS competes with Confluent with their managed Kafka and Flink offerings.</p><p>All of this suggests that the competition in the data streaming space is only intensifying &#127871;.</p><div><hr></div><h3>Personal Announcement</h3><p>I&#8217;ve recently launched <strong><a href="https://irontools.dev/">Irontools</a></strong>: a suite of Apache Flink extensions to make your streaming pipelines faster, leaner, and more flexible. </p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This is a well-known pattern. I believe Netflix started using it as early as 2017.  </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>IMO, implementing this as a feature in Iceberg could&#8217;ve probably been easier&#8230;</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Which has nothing to do with <a href="https://martinfowler.com/articles/data-mesh-principles.html">this Data Mesh</a>.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Yes, Confluent organized many Kafka Summits in the past. However, my point is that the <em>spirit</em> of those events was always community-first.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Announcing Irontools]]></title><description><![CDATA[Making Apache Flink more efficient and accessible]]></description><link>https://www.streamingdata.tech/p/announcing-irontools</link><guid isPermaLink="false">https://www.streamingdata.tech/p/announcing-irontools</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Wed, 07 May 2025 15:44:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ce1eb654-cc5c-4231-abc0-dffd74d7877d_840x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ll be brief - I launched something! </p><p>Introducing <strong><a href="https://irontools.dev/">Irontools</a></strong>: a suite of Apache Flink extensions to make your streaming pipelines faster, leaner, and more flexible. Check out the full announcement <a href="https://irontools.dev/blog/announcement/">here</a>. </p><p>Irontools is my way of tackling some of the data streaming challenges I recently wrote about - from developer experience to runtime efficiency:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;334b3c5b-1b45-4993-af9b-54c61e12aa6e&quot;,&quot;caption&quot;:&quot;I&#8217;ve been building data streaming systems for the past 8 years, and I feel like, as an industry, we haven&#8217;t made a huge amount of progress when it comes to data streaming and stream-processing adoption. Yes, Kafka 4.0 and Flink 2.0 are very different from the versions of Kafka and Flink from 8 years ago (in a really good way). Streaming databases are he&#8230;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Modern Data Streaming Challenges: Part 1&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-03-31T16:18:25.083Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/streaming-challenges-part-1&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:157562652,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:9,&quot;comment_count&quot;:2,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;13aee1f5-f99f-4b90-b550-b18951b7c974&quot;,&quot;caption&quot;:&quot;This is part 2 of the Modern Data Streaming Challenges series. Part 1 is available here.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Modern Data Streaming Challenges: Part 2&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-04-24T16:31:03.523Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/streaming-challenges-part-2&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:161636743,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:4,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div>]]></content:encoded></item><item><title><![CDATA[Modern Data Streaming Challenges: Part 2]]></title><description><![CDATA[Developer experience.]]></description><link>https://www.streamingdata.tech/p/streaming-challenges-part-2</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-challenges-part-2</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Thu, 24 Apr 2025 16:31:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_lyL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is part 2 of the Modern Data Streaming Challenges series. Part 1 is available <a href="https://www.streamingdata.tech/p/streaming-challenges-part-1">here</a>.</em></p><p>Today, I want to talk about developer experience.</p><h3>What is Developer Experience, Exactly? </h3><p>Ask ten different people; I bet you&#8217;d get ten different answers. In my opinion, Developer Experience (DX) includes everything that&#8217;s related to how you <em>interact</em> with a piece of technology: writing code, debugging, deploying, etc. You want to be able to iterate fast. Testing should be easy. Low coupling, high cohesion. And so on and so forth. Overall, you want the development process to be clear and efficient.</p><p>When talking about DX, some people focus on technicalities: you need to implement a CLI this way, local development should be done like this, or you need to be able to deploy that way, etc. Of course, a lot of these things are very important, but I think they&#8217;re somewhat secondary. In my opinion, everything originates from the <strong>programming language</strong> and <strong>programming model</strong>. Choosing the right language and model <em>makes it much easier</em> to have good DX.</p><h3>Programming Languages and Models</h3><p>I don&#8217;t want to give you a history lesson or theorize which language is supposedly the best for data streaming: history is history, and choosing the language is often subjective. However, what&#8217;s clear to me is that making it possible to author data streaming pipelines in <strong>more languages</strong> is going to be a huge win for the industry. So, whenever a company decides to adopt data streaming to support some new <s>AI</s> data use case, they don&#8217;t need to necessarily learn new language, new tooling, or <em>new DX</em>!</p><p>I want to live in a world where the most demanding data streaming abstractions can be expressed in TypeScript. Or Ruby. Or whatever works for <em>you</em>. </p><p>Of course, you probably immediately hear an inner voice saying: but what about using the right tool for the right job? Sure, but how can we say something <em>is not right</em> in this case? What do you actually <em>need</em>?</p><p>In my opinion, you can identify two distinct levels of abstraction for any data streaming technology:</p><ul><li><p><strong>Dataflow definition</strong>: creating a graph of connected sources, transforms and sinks. This can be expressed quite easily in any high-level language, either with functional composition, OOP, or a Builder pattern. A DataFrame-like interface is quite popular in modern data processing frameworks.</p></li><li><p>Optionally, <strong>message processing</strong>: how each individual message should be transformed, enriched, etc. Marked as optional since it is not always needed (e.g. in a case of simple count without any transformations). </p></li></ul><p>As you can see, there is nothing special in either of those. Any general high-level programming language should be capable of expressing both abstraction levels. </p><p>So, if this is so straightforward, why don&#8217;t we see more data streaming tech implemented in various languages? In my mind, it&#8217;s a combination of historical decisions (betting on Java and Python), architectural gravity (it&#8217;s hard to migrate away) and a lot of recent focus on SQL&#8230;</p><p>And just to clarify: there are definitely many new data streaming frameworks and stream-processing libraries written in Rust, Go, TypeScript, and some exotic languages. However, none of them is even close to getting the same level of adoption as Flink, Spark, or Kafka Streams. </p><p>In fact, you can even get by with YAML for the dataflow definition (see <a href="https://github.com/apache/flink-cdc">Flink CDC</a>, <a href="https://docs.redpanda.com/redpanda-connect/get-started/quickstarts/rpk/#run-a-pipeline">Redpanda Connect</a>). This is where the right <strong>programming model</strong> helps a lot: typically, in this case, you want a strict declarative language with no side effects. It&#8217;s funny how the slightest mismatch in the model perception makes things much worse: Spark and Flink both need to serialize method closures in order to send them over the network to workers / task managers; this breaks &#8220;this is just a declaratively defined dataflow definition&#8221; abstraction. So, naturally, it&#8217;s one of the first issues any engineer faces when they start using Spark or Flink.</p><p>Finally, I want to highlight that I&#8217;m not advocating for any specific language: I really want to avoid a situation like getting <a href="https://www.thoughtworks.com/radar/languages-and-frameworks/node-overload">Node overload</a>. The ability to choose is more important.</p><h3>Shifting Left to Make It Right</h3><p>The discussion about programming languages can&#8217;t be complete without the &#8220;shift left&#8221; trend. Historically, data teams have been treated as pretty much a separate organization: most data pipelines populated internal datasets not exposed to users, so application developers never cared about the data world. This led to database migrations and back-end changes routinely breaking data pipelines. </p><p>&#8220;Shift left&#8221; prescribes that data developers be more involved in the application domain, e.g. by partnering with application teams and crafting end-to-end data products. As usual, this is mostly a people problem, so easier said than done&#8230; But this is the best approach I can think of.</p><p>Maybe surprisingly, but in practice, &#8220;shift left&#8221; works both ways. You also want your application developers to care about datasets and data pipelines. And this can be extremely challenging if all your data pipelines are implemented using a different language (and maybe even a completely different programming model). </p><p>The &#8220;AI&#8221; craziness that we experience right now will make this even more important: you can&#8217;t build a decent, personalized &#8220;AI&#8221; experience without having real-time data.</p><h3>About SQL</h3><p>I feel like I'm starting to sound repetitive, so bear with me. I love streaming databases and streaming SQL. It means that people without a software engineering background, but with some SQL knowledge, can build streaming workloads (at least in theory). <a href="https://materializedview.io/p/everything-to-know-incremental-view-maintenance">IVM databases have made a lot of progress</a>. <a href="https://www.timeplus.com/">TimePlus</a> is great at combining historical and real-time data. DeltaStream has announced support for <a href="https://www.deltastream.io/product/deltastream-fusion/">unified batch/streaming/real-time SQL</a>. <a href="https://www.arroyo.dev/">Arroyo got acquired</a>. </p><p>And yet, I don&#8217;t think we&#8217;ll ever be able to satisfy <em>all</em> data streaming use cases with SQL. It&#8217;s coming back to having the right programming model. And, sometimes, declarative dataflow is not expressive enough. Or precise enough to get the right semantics or the right performance optimizations. For example, no matter how smart and powerful your query optimizer, sometimes we know exactly the level of parallelism a certain operator needs. Or that you really need to add an extra shuffle over there. It can also be hard to reuse, refactor and unit-test your SQL logic. dbt templating can only go so far.</p><p>User-defined functions (UDFs) help, but they only operate at the <em>message processing</em> level. And, unfortunately, they&#8217;re frequently a black-box for the runtime.</p><p>And then, getting DX for streaming SQL is <strong>hard</strong>! I gave <a href="https://www.confluent.io/events/current/2022/streaming-sql-for-data-engineers-the-next-big-thing/">this talk</a> a few years ago, thinking that I figured out most of the challenges. But that was just the tip of the iceberg. There are still really hard, unsolved problems like state reuse and evolution in streaming queries.</p><p>SQL does try to evolve (e.g Polymorphic table functions look really cool), so, in a way, it feels like we&#8217;re just starting (even though the language is 40+ years old!). Some companies don&#8217;t want to wait and extend streaming SQL with useful abstractions like changelogs right now<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. </p><h3>Conclusion</h3><p>So, what am I trying to say? We need to build more! More declarative (SQL) and imperative. More programming models and abstractions. More languages. Time will tell what works. </p><p>Here are a few things on my mind recently. </p><p><a href="https://blog.cloudflare.com/data-anywhere-events-pipelines-durable-execution-workflows/">Cloudflare Pipelines</a> made a lot of noise when it was announced, but it doesn&#8217;t look like it can support any advanced use cases (the documentation is just <em>sad</em> to look at). Integrating Arroyo actually feels like a step back: we want streaming JavaScript, not SQL!</p><p><a href="https://www.hytradboi.com/2025/020d7499-c6d0-471a-8346-1fa53ea17fa0-aqualang---a-streaming-dataflow-programming-language">AquaLang</a> is a great attempt to properly bridge dataflow and message processing levels together. I like this project a lot, it shows the kind of innovation we need.</p><p>Server-side <a href="https://webassembly.org/">WebAssembly</a> is finally reaching the point where it can be widely used.</p><p>And I still think about actors, especially with all the new durable execution tech:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;bf39f27b-961a-45f7-8d9f-2542479a68dc&quot;,&quot;caption&quot;:&quot;Most of the modern data streaming frameworks focus on the idea of a dataflow (probably inspired by papers from Google). You define sources, transformations, and sinks. The system compiles them to a dataflow topology and runs it. You could even build a layer of relational algebra on top and end up with a &#8220;streaming database&#8221;. However, most of the streami&#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Actor-Oriented Data Streaming, Anyone?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-01-15T17:04:28.362Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da4e8d64-b168-4760-9a97-3b221ccf75c7_1024x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/actor-oriented-data-streaming-anyone&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:140378685,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:2,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p><a href="https://docs.timeplus.com/proton-create-stream#changelog-stream">https://docs.timeplus.com/proton-create-stream#changelog-stream</a></p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p><a href="https://docs.deltastream.io/reference/sql-syntax/query/create-changelog-as">https://docs.deltastream.io/reference/sql-syntax/query/create-changelog-as</a></p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Modern Data Streaming Challenges: Part 1]]></title><description><![CDATA[Efficiency.]]></description><link>https://www.streamingdata.tech/p/streaming-challenges-part-1</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-challenges-part-1</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 31 Mar 2025 16:18:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_lyL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been building data streaming systems for the past 8 years, and I feel like, as an industry, we haven&#8217;t made a huge amount of progress when it comes to data streaming and stream-processing adoption. Yes, Kafka 4.0 and Flink 2.0 are very different from the versions of Kafka and Flink from 8 years ago (in a really good way). Streaming databases are here, and streaming SQL is a thing. ML / &#8220;AI&#8221; requirements made near-realtime data pipelines very important. </p><p>And yet, data streaming is struggling. I know many startups in the space have a hard time attracting customers. Confluent&#8217;s growth is steady but not that impressive. </p><p>Why? </p><p>I don&#8217;t have a simple answer. But I&#8217;m trying to come up with a few themes explaining the challenges of modern data streaming. I&#8217;m going to use Apache Flink for my examples since it&#8217;s the most popular stream-processing technology out there.</p><p>Today, I want to talk about efficiency. </p><h3>Large-Scale Systems Are Not Necessarily Efficient</h3><p>Many large-scale distributed systems like Hadoop, Spark, Kafka, Flink, etc. are very impressive in many dimensions, but they <strong>were built to solve the scalability problem first</strong>. They&#8217;re not necessarily efficient. You should really understand the difference. For example, just because Flink can scale to thousands of task slots doesn&#8217;t mean that each task slot will perform the most efficient computation. It&#8217;s actually much more challenging to build. </p><p>Here are just a few examples from Flink&#8217;s Slack and mailing list. One person wrote:</p><blockquote><p>I wanted to discuss our current system setup and see if Apache Flink would be a good fit to replace one of our consumer groups. Right now, we have two Kafka consumer groups: the raw-consumer group, which is scalable and handles the input from vehicles, and the parsed-consumer group, which handles the post-processing tasks like decoding and filtering. The issue we&#8217;re facing is that while the raw-consumer group can scale effectively with the number of vehicles, the parsed-consumer group starts to slow down when we increase the load, especially as the tasks it performs are quite <strong>CPU-intensive</strong>.</p><p>Currently, we&#8217;re running the system with 20 vehicles, and here&#8217;s the resource breakdown: ... However, when scaling to 10,000 vehicles, we&#8217;re expecting a significant increase in resource usage. &#8230;</p><p>Given this, we&#8217;re wondering if replacing the parsed-consumer group with Apache Flink would be a good solution. <strong>Flink is known for handling heavy processing tasks like decoding and filtering efficiently</strong>, and we believe it could scale better to meet the needs of our growing vehicle fleet. Would Flink be able to handle this load more effectively than our current parsed-consumer group? And if we were to make this transition, would it provide the scalability we need without running into performance issues or excessive resource consumption?</p></blockquote><p>The person asking this question has a CPU-bound Kafka Consumer with straightforward <em>stateless</em> logic. But for some reason, they think that Flink could be more efficient for this workload. This doesn&#8217;t make sense - a Flink job will need to do <em>at least</em> the same amount of work by leveraging <em>the same</em> Kafka Consumer logic. In practice, it&#8217;ll do much more: checkpointing, maybe additional serialization/deserialization, shuffling, etc. </p><p>Flink excels at <em>stateful</em> computations like joins and aggregation, but if you have a simple stateless Kafka Consumer that&#8217;s CPU bound, you should focus on profiling it, not rewriting it to a Flink job. </p><p>Here&#8217;s another one:</p><blockquote><p>I have a job entirely written in Flink SQL. The first part of the program processes 10 input topics and generates one output topic with normalized messages and some filtering applied (really easy, some where by fields and substring). Nine of the topics produce between hundreds and thousands of messages per second, with an average of 4&#8211;10 partitions each. The other topic produces 150K messages per second and has 500 partitions. They are unioned to the output topic. </p><p>The average output rate needed to avoid lag after filtering messages should be around 60K messages per second. I&#8217;ve been testing different configurations of parallelism, slots and pods (everything runs on Kubernetes), but I&#8217;m far from achieving those numbers. </p><p>In the latest configuration, I used 20 pods, a parallelism of 120, with 4 slots per taskmanager. With this setup, I achieve approximately 20K messages per second, but I&#8217;m unable to consume the largest topic at the rate messages are being produced. Additionally, <strong>setting parallelism to 120 creates hundreds of subtasks for the smaller topics, which don&#8217;t do much but still consume minimal resources even if idle</strong>. </p><p>&#8230;</p><p><strong>When I check the use of cpu and memory to the pods and don't see any problem and they are far from the limit</strong>, each taskmanager has 4gb and 2cpus and they are never close to using the CPU.</p><p>&#8230;. How can I improve the throughput rate? Should I be concerned about the hundreds of subtasks created for the smaller topics?</p></blockquote><p>The author later mentions that they perform <em>a join</em>, which probably (at least partially) explains the performance degradation. Unfortunately, it&#8217;s very easy to write a poorly performing join in Flink, especially in Flink SQL. </p><p>However, it&#8217;s pretty interesting to highlight another inefficiency: because Flink doesn&#8217;t allow fine-grained parallelism tuning for Kafka sources in Flink SQL<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, the author had to apply unnecessarily high levels of parallelism to <em>every</em> source, allocating a lot of wasteful resources. </p><p>So, repeat after me: scalability != efficiency. My advice here is to try building good mental models for the technologies that you use and choosing the right tool for the job.</p><h3>Efficiency == &#128176;&#128176;&#128176;</h3><p>You may say: but why do you care about the efficiency so much? </p><p>Well, efficiency translates to cost savings. From <a href="https://engineering.fb.com/2025/01/21/production-engineering/strobelight-a-profiling-service-built-on-open-source-technology/">Meta&#8217;s blog</a>:</p><blockquote><p>So, the engineer typed an &#8220;&amp;&#8221; after the auto keyword to indicate we want a reference instead of a copy. It was a one-character commit, which, after it was shipped to production, equated to an estimated 15,000 servers in capacity savings per year!</p></blockquote><p>Not bad for having a <em>slightly</em> more efficient system? </p><p>Or look at <a href="https://github.com/apache/datafusion-comet">Apache DataFusion Comet</a>. It reimplements a bunch of Spark operators in a more efficient language (Rust) and runtime (Arrow/DataFusion) with ~2x overall speedup, which could mean ~2x lower bill. And it&#8217;s a drop-in replacement!</p><p>Cost efficiency is especially important in the post-ZIRP era and for teams with reduced headcounts. </p><h3>But Is It Really a Big Deal?</h3><p>Cost savings are nice, sure, but is it really a deal-breaker? </p><p>OK, not necessarily, I agree. Even without the cost aspect, inefficiency is just one particular thing that contributes to the overall problem. </p><p>However, inefficiencies can be multiplicative. </p><p>Having a single poorly performing join might be fine, but it&#8217;s hard to deal with eight of them. A slow Kafka Avro source could be ok to use, but if you need to regularly reprocess petabytes of data, it could even affect the way you design your overall architecture. </p><p>Another way to look at this: a vendor that sells a somewhat inefficient product needs to adjust its margins accordingly, which affects the final cost and experience. This gets passed on to you. If you do the same for your customers, the effect multiplies. </p><p>By the way, I also think it&#8217;s the reason why the Lambda architecture is still alive. It&#8217;s still much more efficient to process a LakeHouse table / a bunch of Parquet files than the same amount of data sitting in a Kafka topic. </p><h3>Learn From Databases</h3><p>I hope you&#8217;re convinced by now. What can we do? </p><p>I think the solutions are out there. &#8220;Just&#8221; copy the ideas from the database research in the past 5-10 years. </p><ul><li><p>Storage / compute separation is an example that everyone understands. Tiered storage in Kafka, disaggregated state store in Flink. The idea initially appeared in the database world. </p></li><li><p>Another idea is applying query engine optimizations like predicate pushdown. This makes a massive impact on query performance and efficiency. Unfortunately, standard Kafka storage is not designed to support this. That&#8217;s why I&#8217;m very bullish on LakeHouse support in Kafka like <a href="https://www.confluent.io/product/tableflow/">Confluent Tableflow</a> and <a href="https://docs.redpanda.com/current/manage/iceberg/topic-iceberg-integration/">Iceberg Topics in Redpanda</a>. Combine that with a <a href="https://nightlies.apache.org/flink/flink-docs-release-2.0/docs/connectors/datastream/hybridsource/">Hybrid Source</a> in Flink, and you get a very efficient engine. </p></li><li><p>A more interesting one is columnar data processing and <a href="https://15721.courses.cs.cmu.edu/spring2024/papers/06-vectorization/p1493-polychroniou.pdf">vectorization</a>. I keep linking to <a href="https://www.arroyo.dev/blog/arrow-migration">this blog</a> from Arroyo because it&#8217;s so good. Alibaba is working on a lot of innovations here with <a href="https://github.com/alibaba/fluss">Fluss</a> (columnar streaming storage) and <a href="https://www.alibabacloud.com/blog/flash-a-next-gen-vectorized-stream-processing-engine-compatible-with-apache-flink_602088">Flash</a> (vectorized Flink-compatible engine). </p></li><li><p>Finally, <a href="https://15721.courses.cs.cmu.edu/spring2024/papers/07-compilation/p539-neumann.pdf">code specialization / compilation</a>. Frequently used to optimize queries, but why not apply it more widely? We deal with a lot of schemas, so let&#8217;s leverage that!</p></li></ul><p>Another thing worth mentioning is <a href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=298781093">Polymorphic Table Functions</a> (PTFs) in Flink. A declarative language like SQL can make writing some simple things very hard (or inefficient). PTFs allow you to stay in the SQL ecosystem but create new, highly customizable operators.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Actually, it looks like the support for specifying individual Kafka source parallelism in Flink SQL <a href="https://github.com/apache/flink-connector-kafka/commit/a52f15a958e8f1a040e9df899f47552181c0398c">was merged</a> a month ago! Still not released, though.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Exploring Apache DataFusion as a Foundation for Streaming Framework]]></title><description><![CDATA[I&#8217;ve been working on a new project that heavily uses Apache DataFusion in a streaming fashion, and I&#8217;d love to share some discoveries.]]></description><link>https://www.streamingdata.tech/p/exploring-apache-datafusion-streaming-framework</link><guid isPermaLink="false">https://www.streamingdata.tech/p/exploring-apache-datafusion-streaming-framework</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 10 Feb 2025 16:57:53 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/22480225-6681-4cd6-aa74-153c77f571e5_840x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><h3>Rust, Arrow, and DataFusion</h3><p>Over the past few years, &#8220;<a href="https://github.com/rewrite-bigdata-in-rust/RBIR">Rewrite Bigdata in Rust</a>&#8221; has become a real movement. The idea is that Rust can bring modern systems-level performance to data processing without the usual trade-offs. One of the key enablers in this space is <strong>Apache Arrow</strong>, an in-memory columnar format that has rapidly become the go-to for high-performance analytics.</p><p><strong>Apache DataFusion</strong> is a query engine written in Rust that heavily leverages Arrow. It&#8217;s primarily used for building databases and query engines, but there&#8217;s also plenty of excitement in the community around real-time data processing. DataFusion was designed to be very extensible. You can add your own connectors, formats, and operators.</p><p>I&#8217;ve been working on a new stream-processing framework on top of DataFusion for the past few months<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. If you may remember, I shared some thoughts on what a new stream-processing framework may look like:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;da6f6314-e166-4525-88df-20276c152719&quot;,&quot;caption&quot;:&quot;It would probably be implemented in Rust &#128578; And it would probably leverage the Apache Arrow DataFusion ecosystem (but it looks like the streaming support is not very mature).&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;If I Were to Create a New Stream Processing Framework Today...&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-03-11T16:28:24.065Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/new-stream-processing-framework-today&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:142502326,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:8,&quot;comment_count&quot;:4,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>This post looks at DataFusion and tries to answer the following question: Can it serve as a solid foundation for a streaming framework? Or, put differently, how close does it come to offering what systems like Apache Flink provide out of the box?</p><h3>What Does a Streaming Framework Need?</h3><p>A reliable and performant stream-processing framework does more than just shuffle Kafka records around in real time. It typically addresses several key areas:</p><p>First, it needs an internal <strong>data format</strong> that can efficiently store different data types. Historically, streaming frameworks used row-based formats, but lately, I have seen more adoption of columnar formats.  </p><p>Second, it provides an <strong>execution runtime</strong> that can handle unbounded data. This means the runtime must keep up with a continuous flow of records. It usually operates in a distributed fashion, so you can scale horizontally across many nodes. The runtime also tends to include backpressure mechanisms so that if downstream operators get overwhelmed, upstream producers can slow down or queue data more gracefully.</p><p>Third, <strong>connectors</strong> are essential to bring data in from external sources - like Kafka, Pulsar, Redpanda, or various databases over CDC - and send processed results to sinks such as data lakes and OLAP databases. Connectors also need to handle the offset or checkpoint mechanism so that if a job crashes, it doesn&#8217;t start from the very beginning unless explicitly told to do so.</p><p>Another area is <strong>fault tolerance</strong>. Continuous data processing systems are expected to run for days, weeks, or even months without interruption. Yet all things fail, patches and updates need to happen, etc. A typical approach is <a href="https://en.wikipedia.org/wiki/Chandy%E2%80%93Lamport_algorithm">Chandy&#8211;Lamport checkpointing</a>, which involves periodically saving the progress of the streaming pipeline so it can be reconstructed after a restart. </p><p>Finally, <strong>state management</strong> and <strong>time-based semantics</strong> are required to support stateful transformations like joins and aggregations. I previously wrote about it here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3a91aeaa-2bba-46ef-af3e-b3f278675bb6&quot;,&quot;caption&quot;:&quot;Stateful stream processing is a complicated topic. Windowing. Streaming joins. Late-arriving data and watermarks. Sessionization. Streaming analytics&#8230; It&#8217;s hard to say where to start.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;State and Timers&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-09-18T15:37:58.718Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761d50c8-d9ea-4381-ad91-a7b7d62fee4f_1750x496.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/state-and-timers&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:136475557,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h3>Prior Art</h3><p>I know about a few projects that build stream-processing frameworks on top of DataFusion:</p><ul><li><p><a href="https://www.arroyo.dev/">Arroyo</a>. It is one of the earliest projects in the space (btw, Arroyo&#8217;s blog is top-notch, and I highly recommend following it). However, as far as I know, it mostly uses DataFusion for SQL parsing and generating logical plans. It does use Arrow as a data format. The execution runtime is custom-built, as well as connectors. </p></li><li><p><a href="https://www.synnada.ai/">Synnada</a>. I don&#8217;t think any of their work on top of DataFusion is open-sourced. They do give a lot of great talks, especially in the context of building a <em>unified</em>, not just a stream-processing engine.</p></li><li><p><a href="https://www.denormalized.io/">Denormalized</a>. The latest addition.  Denormalized tries to be a &#8220;DuckDB for streaming&#8221; by focusing on single-node execution. </p></li></ul><h3>DataFormat and Execution Runtime</h3><p>Apache DataFusion operates by processing Arrow batches of records (<code>RecordBatch</code>) through a pipeline of operators.</p><p>Arrow is a <em>columnar</em> data format. It means that your intermediate data is stored as a set of arrays. Each <code>RecordBatch</code> is 8192 records by default. Some purists may say, isn&#8217;t it an indicator of a micro-batch system? Well, I don&#8217;t think so. Even in the case of Apache Flink, data is always batched at many levels. Processing semantics are more important in this case. </p><p>Does batching increase latency? Well, it may, but there are ways to work around it. Micah Wylde, CEO and Founder of Arroyo, explained it really well <a href="https://www.arroyo.dev/blog/why-arrow-and-datafusion#streaming-on-columns">here</a>.</p><p>DataFusion is designed as a pull-based engine. Conceptually, it means that each operator runs a tight loop that pulls data from the upstream sources. In practice, DataFusion uses <a href="https://tokio.rs/tokio/tutorial/streams">Tokio Streams</a>. I want to highlight two observations:</p><ul><li><p>Tokio Stream (kinda like an iterator of Futures) is the primary abstraction, even when it comes to bounded sources (e.g. reading a bunch of Parquet files).</p></li><li><p>Pull-based execution doesn&#8217;t offer much control over backpressure. This makes it very different from Apache Flink, which can offer reliable backpressure, fine-grained flow control and adaptive buffers between operators. These things are not as important in the context of a query engine (whose goal is to read a bunch of files as fast as possible), but they do matter a lot for a streaming engine. </p></li></ul><p>Anyway, having the Stream abstraction as a default way of dealing with data seems like a huge help when building a stream-processing engine! </p><p>Does it mean that DataFusion&#8217;s runtime can be easily used as a streaming runtime out of the box? Almost, but not quite. Each operator in DataFusion defines its execution mode: <strong>Bounded</strong>, <strong>Unbounded</strong> or <strong>PipelineBreaking</strong>. The first two should be pretty straightforward to understand: use Unbounded operators (and build your custom ones as Unbounded) and avoid Bounded operators in the streaming context. As far as I can see, Bounded is mostly used by the source operators that scan files (also things like the LIMIT clause, EXPLAIN command, etc.)</p><p>The PipelineBreaking operators are more complicated. Here&#8217;s the description of this execution mode:</p><blockquote><pre><code><em>Some of the operator's input stream(s) are unbounded, but the operator
cannot generate streaming results from these streaming inputs.

In this case, the execution mode will be pipeline breaking, e.g. the
operator requires unbounded memory to generate results. This
information is used by the planner when performing sanity checks
on plans processings unbounded data sources.</em></code></pre></blockquote><p>As you probably guessed, this means that some types of joins and aggregations are PipelineBreaking operators, which means that they can&#8217;t be used in the streaming context!</p><p>The only workaround in this case is implementing your own operator. This is what Denormalized has done to support windowed aggregations. </p><p>DataFusion operators also support partitioning. By default, since DataFusion is a single-node engine, it uses the number of CPU cores as a number of partitions. It&#8217;s possible to define the number of partitions and the partitioning strategy in your custom operators.</p><h3>Connectors: Building Your Own</h3><p>For a streaming framework to be truly useful, it has to integrate with real data sources. DataFusion doesn&#8217;t provide an extensive set of built-in connectors at the moment, mostly because it was never designed specifically for data integration use cases. Out of the box, you can read different types of files (locally or from the object storage). There is no standard Kafka connector.</p><p><a href="https://github.com/datafusion-contrib/datafusion-table-providers">DataFusion Table Providers</a> is an excellent source of community-provided connectors. However, some of those connectors were not designed to be executed in the streaming environments, so some tweaks may be needed.</p><p>You can create a custom connector by implementing a <code>TableProvider</code> trait. Check <a href="https://datafusion.apache.org/library-user-guide/custom-table-providers.html">this</a> handy guide. I&#8217;ve had a chance to build both source and sink connectors, and I&#8217;d say that the experience is quite nice<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. </p><p>Overall, it doesn&#8217;t seem too hard to write a Rust connector for common platforms like Kafka, but it becomes trickier when you factor in the need for failure recovery. </p><h3>Checkpointing and Fault Tolerance</h3><p>Checkpointing is one of the biggest differences between a &#8220;batch query engine&#8221; and a genuine streaming framework. Systems like Apache Flink store a snapshot of the entire pipeline state at regular intervals so they can resume from the last good snapshot if something goes wrong. DataFusion just doesn't have anything like that. </p><p><strong>I&#8217;d say that correctly implementing checkpointing and failure recovery would probably be the hardest thing for implementing an MVP of a streaming engine on top of DataFusion.</strong> </p><p>I&#8217;d encourage you to check checkpointing implementation in Arroyo and Denormalized.</p><h3>Scaling Out Beyond a Single Node</h3><p>DataFusion runs on a single node by default. While that might be sufficient for some workloads, many streaming use cases can easily exceed the capacity of one machine. Two main paths come to mind: </p><ul><li><p>You can run multiple instances of DataFusion in a Kafka Streams&#8211;style model, where a consumer group is used to coordinate partition assignment across different instances. Of course, it means you can only support Kafka-compatible sources.</p></li><li><p>You could look at distributed frameworks like <a href="https://datafusion.apache.org/">Ballista</a> (part of the DataFusion ecosystem) or general-purpose engines like <a href="https://www.ray.io/">Ray</a> for parallel execution across many nodes. Both Ballista and Ray have been getting a lot of attention recently from the folks wanting to run DataFusion at scale. Anyway, this option means your system now needs to support shuffles, which brings a lot of complexity. I haven&#8217;t had a chance to explore these tools yet, but the first thing that comes to mind when evaluating these options is support for streaming execution. Just having a shuffle operator is not enough, you need a <em>streaming</em> shuffle.</p></li></ul><h3>No Typical Stateful Streaming Features</h3><p>It looks like DataFusion doesn&#8217;t have built-in operators that provide arbitrary state access (something similar to ValueState in Flink). Creating such functionality feels straightforward - &#8220;just&#8221; add a wrapper for RocksDB or <a href="https://slatedb.io/">SlateDB</a>. However, again, I think a lot of complexity around checkpointing and failure recovery will need to be addressed. </p><p>Many streaming scenarios revolve around time-based aggregations and handling out-of-order events with watermarks. DataFusion currently doesn&#8217;t support these concepts at all (there is no need for this in batch execution). <a href="https://docs.rs/tokio/latest/tokio/time/index.html">Tokio timers</a> would probably be a way to implement windowing. </p><h3>Conclusion</h3><p>Building on top of DataFusion is not for the faint of heart. There is very little documentation, and most of the time, you end up reading the source to understand what&#8217;s going on. Thankfully, the source code is very friendly! </p><p>If you&#8217;re serious about building a production-grade stream-processing framework, you&#8217;ll need to invest a lot: </p><ul><li><p>make sure the operators you want to support can be executed in the streaming environment. </p></li><li><p>have some form of failure recovery.</p></li><li><p>build source and sink connectors. </p></li><li><p>find a way to scale out (either via something like Kafka consumer groups or by adopting Ballista/Ray).</p></li><li><p>(if you need stateful streaming): introduce key-value store and windowing abstractions. </p></li></ul><p>Sounds like a lot of work! &#128578; However, building an engine from scratch is way more work. DataFusion is an excellent foundation, and it&#8217;s highly customizable - you can change almost any aspect of the system if you don&#8217;t like it. <a href="https://datafusion.apache.org/user-guide/introduction.html#known-users">The list of known users</a> is very impressive!</p><p>Also, the &#8220;Rewrite Big Data in Rust&#8221; movement has momentum, and plenty of folks are intrigued by the idea of a next-generation streaming engine that combines safety, speed, and a modern language ecosystem. Watch this space. </p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>It&#8217;s part of a consulting project I&#8217;m working on for a client. There is no appetite for open-sourcing it anytime soon.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Unless you need to deal with Avro. Unfortunately, its support is still not great.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Fluss: First Impression]]></title><description><![CDATA[Table is a new stream.]]></description><link>https://www.streamingdata.tech/p/fluss-first-impression</link><guid isPermaLink="false">https://www.streamingdata.tech/p/fluss-first-impression</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Thu, 05 Dec 2024 21:32:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!d-E7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><h3>Intro</h3><p><a href="https://github.com/alibaba/fluss">Fluss</a> is a new streaming platform from Alibaba that was open-sourced last week. Check <a href="https://www.ververica.com/blog/fluss-is-now-open-source">the announcement post</a>.</p><p>It&#8217;s quite similar to other streaming platforms like Apache Kafka, Apache Pulsar, Redpanda, etc., but also very different in some aspects (and has some truly unique features). It&#8217;s designed to be tightly integrated with LakeHouses like Apache Iceberg and Apache Paimon.</p><p>Currently, Fluss doesn&#8217;t implement Kafka protocol, but it&#8217;s on the roadmap. It makes it difficult to evaluate properly - right now, you have to use Apache Flink and/or Apache Paimon to interact with it. However, it&#8217;s modelled similarly: <em>tables</em> instead of topics, <em>buckets</em> instead of partitions, etc.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d-E7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d-E7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 424w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 848w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 1272w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d-E7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png" width="1456" height="1063" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1063,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1377946,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d-E7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 424w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 848w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 1272w, https://substackcdn.com/image/fetch/$s_!d-E7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c06f48d-295f-45eb-bc3c-4dfcd7324e64_6714x4904.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://alibaba.github.io/fluss-docs/docs/concepts/architecture/">Fluss Architecture</a></figcaption></figure></div><h3>Table as a primary concept</h3><p>Something that jumps out immediately when you check the documentation is that Fluss organizes data streams as <strong>schematized tables</strong>, not topics. It&#8217;s quite common to use Avro or Protobuf with a schema registry when using Kafka. However, it&#8217;s never required: to Kafka, every record value is just an array of bytes, which makes it possible to deal with semistructured or unstructured data. </p><p>Fluss <strong>demands</strong> a schema to be defined before you can write anything. I think it&#8217;ll make it much harder to use for semistructured data or data streams with schemas that need to evolve a lot. </p><p>Putting tables at the front also indicates that Fluss tries to be more of a database than a streaming platform. It makes a lot of sense given the advertised use cases: fast ingestion for real-time data and union read with LakeHouses (more on this below) for real-time analytics.</p><h3>PrimaryKey Table</h3><p>Fluss supports regular append-only <a href="https://alibaba.github.io/fluss-docs/docs/table-design/table-types/log-table/">Log Tables</a>, as well as <a href="https://alibaba.github.io/fluss-docs/docs/table-design/table-types/pk-table/">PrimaryKey Tables</a>. PrimaryKey Tables seem to be the most impressive feature of Fluss at first glance. Lookup queries are Kafka&#8217;s bane: it&#8217;s very common to have a need to find a very specific subset of messages in a topic, and the only way to do it in almost any Kafka-compatible platform is to scan the whole topic from the beginning&#8230; which can take <em>hours</em>. Tiered storage can improve this, but not significantly. </p><p>PrimaryKey Tables are backed by RocksDB to support updates, deletes and <strong>efficient lookup queries</strong>! So, it&#8217;s possible to execute something like &#8220;SELECT * FROM users_table WHERE user_id = 123&#8221; in Flink SQL and get the results back reasonably fast. </p><p>These tables also support changelog semantics and partial updates.</p><p>There is no free lunch, and I think that the performance of these tables will be an order of magnitude lower compared to Log Tables.  </p><h3>More unification</h3><p>I wrote this post last year:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;85f8f382-2e0e-490d-bb20-9761f976aeea&quot;,&quot;caption&quot;:&quot;Spoiler alert: I&#8217;m not a psychic and don&#8217;t have a time machine, so I can&#8217;t really say what the data platforms will look like in 5-7 years. But I&#8217;ve been noticing some trends that are hard to ignore, so I wanted to make a prediction or two. Maybe there is also a bit of a wish list from me here &#128578;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Data Platforms in 2030&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-09-05T15:46:25.896Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa249188e-8320-4e3b-8eb0-b1a9c40f329d_1298x1180.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.streamingdata.tech/p/data-platforms-in-2030&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:136208753,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:11,&quot;comment_count&quot;:4,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>I predicted to see data platform unification, where a streaming log (e.g. Kafka),  a LakeHouse (e.g. Iceberg) and an OLAP database (e.g. ClickHouse) become much more unified &#8220;consolidated data engine&#8221; that&#8217;s easier to use and manage, not three separate systems. I stand corrected, we may see this much earlier &#128578;. Several vendors have announced plans to integrate Kafka with Iceberg API (Redpanda already has <a href="https://docs.redpanda.com/current/manage/topic-iceberg-integration/">Iceberg support in beta</a>), which also applies to Fluss. It <a href="https://alibaba.github.io/fluss-docs/docs/streaming-lakehouse/overview/">tightly integrates with LakeHouses</a> and highlights the union read use case (also known as <a href="https://nightlies.apache.org/flink/flink-docs-master/docs/connectors/datastream/hybridsource/">Hybrid Source</a> in Apache Flink). </p><p>However, one can argue that Fluss goes beyond just these two dimensions with the PrimaryKey Table abstraction. The underlying RocksDB database can be used to serve not just efficient lookup queries but aggregations as well! There is <a href="https://alibaba.github.io/fluss-docs/docs/engine-flink/reads/#aggregations">a small example</a> in the docs. RocksDB was also used by the Rockset database as an underlying storage for their <a href="https://rockset.com/blog/how-we-use-rocksdb-at-rockset/">analytical storage engine</a>, so it&#8217;s clearly possible to pull off, at least at a certain scale.</p><h3>Delta Join</h3><p>This is something that I really wanted to see in Flink several years ago. It may finally happen! </p><p>The idea here is very simple: </p><ul><li><p>A typical &#8220;windowless&#8221; stream-stream join needs to accumulate state for both sides forever. This becomes very challenging at scale. <a href="https://sap1ens.com/blog/2020/12/12/streaming-systems-and-global-state/">I wrote</a> about this before.</p></li><li><p>Streaming platform provides a form of tiered storage with effectively infinite retention.</p></li><li><p>So, instead of accumulating data in state, we can perform a lookup when needed and query the tiered storage instead. Some form of batching will likely be required.</p></li><li><p>In a typical tiered storage implementation that&#8217;s available in Apache Kafka, Confluent or Redpanda, these lookups are not as efficient. But in Fluss, PrimaryKey Tables make it possible. I imagine Fluss contributors can also decide to add additional secondary indexes to make lookups faster.</p></li></ul><p>Feel free to check <a href="https://cwiki.apache.org/confluence/display/FLINK/FLIP-486%3A+Introduce+A+New+DeltaJoin">the official proposal</a> for the Delta Join in Flink.</p><h3>Implementation</h3><p>Fluss is implemented in Java and currently requires Zookeeper for coordination. Tables are partitioned and replicated similarly to Kafka topics. Data is stored on local disks. Overall, this feels like a reliable but somewhat dated design (what is this, 2019? where is Rust?! &#128540;). The roadmap already mentions planned changes like Zookeeper removal and zero disk architecture though.</p><p>When reading through some parts of the source code, I couldn&#8217;t get rid of the impression that I was looking at an amalgamation of Flink (Fluss borrowed its type system), Paimon (some design decisions) and Kafka (same abstractions, configuration, etc.). This is not surprising at all, given the team who&#8217;s working on Fluss (Flink and Paimon contributors). </p><p>Using Arrow as a primary data exchange protocol is what makes Fluss very interesting. Producers accumulate batches of Arrow vectors and send them to the server using Arrow IPC. </p><p>I invite you to check <a href="https://github.com/alibaba/fluss/blob/a1280c6888c20d4318ea3bee4784dd0ee321c6c4/fluss-client/src/main/java/com/alibaba/fluss/client/write/ArrowLogWriteBatch.java">ArrowLogWriteBatch.java</a> and <a href="https://github.com/alibaba/fluss/blob/a1280c6888c20d4318ea3bee4784dd0ee321c6c4/fluss-common/src/main/java/com/alibaba/fluss/record/MemoryLogRecordsArrowBuilder.java">MemoryLogRecordsArrowBuilder.java</a> to understand how Arrow batches are written.</p><p>If you still question whether vectorized columnar format is a good choice for a streaming system, I recommend you to read <a href="https://www.arroyo.dev/blog/why-arrow-and-datafusion">this blog post</a> from Arroyo. Some highlights:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Iql!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Iql!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 424w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 848w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 1272w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Iql!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png" width="1456" height="531" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:531,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:165387,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Iql!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 424w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 848w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 1272w, https://substackcdn.com/image/fetch/$s_!6Iql!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457776e0-2031-4f1a-b550-7a5db4fd710f_1606x586.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://www.arroyo.dev/blog/why-arrow-and-datafusion">We built a new SQL Engine on Arrow and DataFusion</a></figcaption></figure></div><p>Fluss protocol is implemented using Protobuf, and it&#8217;s quite easy to grasp: check the full spec <a href="https://github.com/alibaba/fluss/blob/a1280c6888c20d4318ea3bee4784dd0ee321c6c4/fluss-rpc/src/main/proto/FlussApi.proto">here</a>. It&#8217;s less than 1K LOC at the moment (I&#8217;m curious what it&#8217;ll look like after adding support for consumer groups&#8230;). </p><h3>Conclusion </h3><p>Fluss is a truly unique system that tries to model real-time data streams as schematized tables. It&#8217;s still very early, but I&#8217;d keep an eye on it: PrimaryKey Tables and Delta Joins can become killer features. </p><p>And Apache Flink users should be really excited about the roadmap:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dB3f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dB3f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 424w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 848w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 1272w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dB3f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png" width="1456" height="443" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:443,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:154102,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dB3f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 424w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 848w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 1272w, https://substackcdn.com/image/fetch/$s_!dB3f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fce15df-c9ba-4000-8a11-437aa879c0ea_1736x528.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://alibaba.github.io/fluss-docs/roadmap/">Fluss Roadmap</a></figcaption></figure></div><p>Things like predicate pushdown and cost-based optimizer can really make a 10x - 100x difference. </p><div><hr></div><h2>Events</h2><p>I&#8217;ll be speaking at these events next week:</p><ul><li><p><a href="https://www.redpanda.com/streamfest">Redpanda Streamfest</a>. Come join us to hear my predictions about the future of data streaming!</p></li><li><p><a href="https://www.linkedin.com/events/7265063843909767168/comments/">Apache Flink 2.0: What&#8217;s to come and the impact on stream processing</a> webinar from DeltaStream.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Streaming Data Best Practices]]></title><description><![CDATA[Newsletter highlights.]]></description><link>https://www.streamingdata.tech/p/streaming-data-best-practices</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-data-best-practices</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Fri, 29 Nov 2024 05:04:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e21630f5-b6e9-4c24-8ae5-92ee98a6a8f7_1429x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This post is a periodically updated collection of publications from this newsletter highlighting the best practices for building data streaming pipelines and platforms.</p><ul><li><p>Start with <a href="https://streamingdata.substack.com/p/streaming-first-archirecture">Streaming-First Architecture</a>. Even if you&#8217;re not going to follow it, it offers a lot of food for thought.</p></li><li><p>Design your messages with <a href="https://streamingdata.substack.com/p/approaches-for-defining-message-metadata">Approaches for Defining Message Metadata</a>.</p></li><li><p>Decide on using <a href="https://streamingdata.substack.com/p/changelog-vs-append-only-data-streams">Changelog vs Append-Only Data Streams</a>.</p></li><li><p>Understand how to ingest operational data with <a href="https://streamingdata.substack.com/p/change-data-capture-is-still-an-anti">Change Data Capture Is Still an Anti-pattern. And You Still Should Use It</a>.</p></li><li><p>Understand how to ingest event data with <a href="https://streamingdata.substack.com/p/building-event-ingestion-http-api">Building Event Ingestion HTTP API for Kafka</a>.</p></li><li><p>Decide what data streams to materialize after reading <a href="https://streamingdata.substack.com/p/considerations-for-data-stream-materialization">Considerations for Data Stream Materialization</a>.</p></li><li><p>Determine if exactly-once delivery is a must with <a href="https://streamingdata.substack.com/p/do-you-really-need-exactly-once-delivery">Do you really need exactly-once delivery?</a></p></li><li><p>Think about stateful stream processing after reading <a href="https://streamingdata.substack.com/p/state-and-timers">State and Timers</a>.</p></li><li><p>Consider how to deploy your stateful applications with <a href="https://streamingdata.substack.com/p/blackhole-sink-pattern-for-blue-green">Blackhole Sink Pattern for Blue-Green Deployments</a>.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Do you even need Kafka?]]></title><description><![CDATA[Most likely.]]></description><link>https://www.streamingdata.tech/p/do-you-even-need-kafka</link><guid isPermaLink="false">https://www.streamingdata.tech/p/do-you-even-need-kafka</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 28 Oct 2024 15:52:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_lyL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><p>Recently, I&#8217;ve heard arguments like &#8220;Our solution doesn&#8217;t require Kafka&#8221; or &#8220;You can do data streaming without Kafka&#8221; from several vendors. I wanted to zoom in and understand if a streaming platform like Kafka is still needed nowadays (spoiler alert: it&#8217;s not going anywhere). </p><h3>Which Kafka?</h3><p>But first of all, ask people what they mean when they say Kafka. It could either mean Apache Kafka or another tool that supports Kafka API. </p><p>Historically, Apache Kafka was perceived as a fairly complicated system that was hard to deploy and maintain. Using Kafka in a small or medium-sized company was often considered to be overengineering (&#8220;of course there is a simpler way to do X!&#8221;). I guess it might still be the case, but things have changed drastically. </p><p>Modern Apache Kafka doesn&#8217;t need Zookeeper, <a href="https://www.redpanda.com/">Redpanda</a> doesn&#8217;t need JVM, and <a href="https://www.warpstream.com/">WarpStream</a> doesn&#8217;t even need any disks or state to manage. There are also <a href="https://pulsar.apache.org/">Apache Pulsar</a>, <a href="https://www.automq.com/">AutoMQ</a>, <a href="https://buf.build/">Buf</a> and probably other solutions that support Kafka API. Many have fully managed offerings. </p><p>So, let&#8217;s forget about the &#8220;Kafka is really hard to run&#8221; argument for a second.</p><h3>Streaming databases</h3><p>Coming back to the original statements, I frequently hear them in the context of streaming databases. For example, when using <a href="https://materialize.com/">Materialize</a>, you can get <a href="https://materialize.com/blog/zero-staleness-faster-primary/">really strong consistency AND latency guarantees</a> when connecting directly to Postgres. If all you need is to offload a complicated query or report from your read replica, then the Postgres &amp; Materialize combo is sufficient. I do feel like it can be a powerful way to build user-facing data products: ingest data from an operational database, transform it into the right shape, and serve API requests using the underlying storage. <a href="https://www.confluent.io/events/current/2022/oh-that-microservice-should-have-been-a-sql-query/">OH: That microservice should have been a SQL query</a> is still my favourite talk on this topic.</p><p>Or perhaps you just want to move your operational data from MySQL to Snowflake. It seems like the Change Data Capture tools (e.g. Debezium) made operational databases really popular as a data source. Even five years ago, application or clickstream events were much more favoured data source. But nowadays, thanks to reliable CDC tools, many companies want to see their operational data in their data lake or data warehouse first.</p><p>Also, some application events could be translated into CDC streams thanks to the <a href="https://microservices.io/patterns/data/transactional-outbox.html">Outbox pattern</a>.   </p><p>So, to summarize, streaming databases can act as a bridge between operational data (thanks to CDC capabilities), which could be messy, require normalization, etc., and a primary data lake / data warehouse. </p><h3>The best data hub</h3><p>But despite the increased popularity of operational data, a typical enterprise data platform consists of many more sources of data: not just application or clickstream events but also third-party data, SaaS vendor data, legacy applications data, and many more. </p><p>When I worked at Activision, we ingested game data from game consoles (like PlayStation), mobile devices, and our partners. The game telemetry we received could contain anything: match summary, marketplace purchase, GPU temperature or even binary crash dump data. </p><p><strong>Messaging or streaming platform is still the best way to do data integration.</strong> <a href="https://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns</a> is 20 years old, but it&#8217;s incredibly relevant. I doubt things will drastically change in the next 20 years. Yes, perhaps we&#8217;ll see data lakehouses play a larger role, but they won&#8217;t be able to replace realtime use cases (without evolving a lot).</p><p>Also, a streaming platform like Kafka is still one of the best ways to <em>quickly</em> and <em>reliably</em> ingest large volumes of <em>structured</em> or <em>unstructured</em> data. </p><p>Finally, a streaming platform like Kafka is great at dataset reuse. Consumers are very cheap. The same topic could be used for writing data to the data lake, powering an OLAP database, hydrating a cache, populating a search index, and emitting user notifications.</p><p>To be honest, I feel a bit silly repeating these features (like I&#8217;m a salesperson trying to sell Kafka). The industry should&#8217;ve learned the power of reusable data streams by now, but I guess it&#8217;s good to remind about it once in a while. </p><h3>Verdict</h3><p>If you <em>just</em> need to move your relational database data into a data warehouse, you don&#8217;t necessarily need to use a streaming platform like Kafka. However, any decently sized enterprise data platform would benefit from it anytime.</p><div><hr></div><h4>Events</h4><p>I&#8217;ll be speaking at Redpanda&#8217;s Streamfest online conference in early December. You can register <a href="https://www.redpanda.com/streamfest#register">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Current 2024]]></title><description><![CDATA[Announcements:]]></description><link>https://www.streamingdata.tech/p/current-2024</link><guid isPermaLink="false">https://www.streamingdata.tech/p/current-2024</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 23 Sep 2024 16:04:11 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/83931058-8932-4879-b82c-2588ca304621_1512x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><p><strong>Current</strong> is one of the main events in the data streaming space. <strong>Current 2024</strong> happened last week in Austin, Texas. </p><h3>Keynotes</h3><p>The keynotes were somewhat underwhelming. There were no huge announcements or new product launches. Even Jay&#8217;s &#8220;one more thing&#8221; announcement regarding the WarpStream acquisition already wasn&#8217;t big news at the time.</p><p>It was great to hear that Confluent&#8217;s Tableflow will be in the open preview very shortly. Also, many Flink-related updates from them:</p><ul><li><p>Python and Java <strong>Table API</strong> support is coming.</p></li><li><p>Flink private networking and external schema registry support.</p></li><li><p>Flink available in the Confluent <em>Platform.</em></p></li></ul><p>I think it&#8217;s clear Flink users require much more than a Flink SQL editor.</p><p>But probably the main theme of the first day keynote was &#8220;AI&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.  I feel like <a href="https://x.com/TechCrunch/status/1790504691945898300">every vendor must mention &#8220;AI&#8221;</a> at any serious tech event nowadays: you want to show your customers and your investors that you can either leverage or assist with building the new wave of &#8220;AI&#8221; products. </p><p>However, in Confluent&#8217;s case (or any streaming data infra company, for that matter), I feel like the value is real: many user-facing products need near real-time data, which is hard to implement without streaming. I&#8217;m not convinced that a Flink UDF calling OpenAI endpoint is all we need (see more on this below).</p><p>The second day keynote was focused on developers. Kafka Docker images, DLQ for Kafka Streams, PATCH endpoints for Kafka Connect, and, of course, the <a href="https://www.confluent.io/product/vs-code/">VS Code extension</a> were all very welcomed. </p><p>When Tim Berglund appeared on stage, I felt like the world became a little bit brighter. I missed him<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>! Btw, Tim <a href="https://www.buzzsprout.com/186154/episodes/2555848-streaming-call-of-duty-at-activision-with-apache-kafka-ft-yaroslav-tkachenko">interviewed</a> me on the Streaming Audio podcast a few years ago. </p><h4>&#8220;Shifting left to make it right&#8221;</h4><p>&#8220;Shifting left&#8221; was mentioned during the keynotes five times (I counted). I also heard it in the hallways a lot. In case you don&#8217;t know, in the data platform context, shifting left means working more closely with operational / application development teams. For example, it means shared ownership over data products or data pipelines with the goal of stopping data artifacts from being treated as a second-class citizen. <a href="https://martinfowler.com/articles/data-mesh-principles.html">Data Mesh architecture</a> is one of the ways to implement this principle. </p><p>It&#8217;s quite refreshing to hear this not just from consultants or vendors but large enterprises as well. I suspect that execs have finally started to understand the importance of high quality data. If you want to build <em>actually useful</em> user-facing &#8220;AI&#8221; products, you can&#8217;t do it without clean and fresh datasets. And yet, most of the enterprises still struggle with basic BI projects&#8230;  </p><p>I really hope to see some change in the industry. I spent some time in my career as a data engineer building data pipelines, and sometimes, working around application teams was a ridiculous process costing the company tens of thousands of dollars. For example, one time at Shopify, <a href="https://www.youtube.com/watch?v=tiGxEGPyqCg&amp;ab_channel=FlinkForward">we implemented a streaming join between nine (!) tables</a> because the application team couldn&#8217;t emit a single domain event containing all the relevant information<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>.  </p><h3>WarpStream Acquisition </h3><p>The acquisition <a href="https://www.warpstream.com/blog/warpstream-is-dead-long-live-warpstream">was announced</a> a week before, but I&#8217;d love to share a few things in this post since we heard its CEO, Richie Artoul, during the first day keynote. </p><p>First of all, as you may know, I&#8217;m a big fan of WarpStream.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e15e2980-c08c-44f9-8cd8-eb9b6075b6b2&quot;,&quot;caption&quot;:&quot;Please pledge your support if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Streaming Platforms in the Cloud Era&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5669707,&quot;name&quot;:&quot;Yaroslav Tkachenko&quot;,&quot;bio&quot;:&quot;Data Streaming Advocate.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-07-15T15:47:35.550Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f612531-8119-4b22-8cde-45654d65495a_400x320.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://streamingdata.substack.com/p/streaming-platforms-in-the-cloud-era&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:144958968,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:10,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Data Streaming Journey&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7327acf9-537c-46af-b976-cc28d07ae7e5_627x580.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>I think their architecture is <em>truly</em> novel and <em>truly</em> cloud-native, and it supports a few very interesting features (check the post above). </p><p>Somehow, they were insanely productive and, with just ten-ish people, built a great product that was able to compete with major vendors. I was so excited about their future!</p><p>However, they chose an exit. Confluent has made a great move, eliminating a competitor and getting a stellar team. </p><p>I know that the WarpStream team still has a lot of autonomy; Confluent also chose to keep the brand (it&#8217;s now &#8220;WarpStream by Confluent&#8221;), so I&#8217;m hopeful they&#8217;ll be able to innovate at the same pace or even faster (with more resources now). </p><p>Some people pointed out that WarpStream uses a different stack (Golang instead of JVM), but, in my opinion, nowadays, large companies are totally fine at integrating at the Kubernetes level. It&#8217;s not that important what&#8217;s running in a given container. </p><p>I&#8217;m slightly more concerned about additional services WarpStream is building, like the Schema Registry and the Iceberg support. They&#8217;re essentially duplicating Confluent&#8217;s existing (or incoming) products. I&#8217;d be very curious to see how they resolve this. For example, I was looking forward to using fully managed WarpStream&#8217;s Schema Registry; running the open-source version of the Confluent Schema Registry is not fun. </p><h3>Redpanda Announcements</h3><p>Similarly, Redpanda hasn&#8217;t announced anything at the event, but they did a few major announcements a week before (trying to steal the thunder), so I think it&#8217;s important to cover their updates as well. </p><p>First of all, they announced <a href="https://www.redpanda.com/blog/redpanda-one-multi-modal-streaming-data-engine">Redpanda One</a>: a single, multi-modal engine. It includes <a href="https://www.redpanda.com/blog/cloud-topics-streaming-data-object-storage">Cloud Topics</a>, which is Redpanda&#8217;s answer to WarpStream. </p><p>I must say, it&#8217;s quite impressive. An ability to choose the underlying topic storage (high-latency object storage vs regular on-disk vs ultra low-latency) on a per-topic basis is very powerful! It does mean a more complicated design, though.</p><p>The <a href="https://www.redpanda.com/blog/apache-iceberg-topics-streaming-data">Iceberg support</a> is finally coming to Redpanda. They were actually <em>the first vendor</em> to announce this capability (more than a year ago). I&#8217;ve seen the demo, and it looks slick!  </p><p>Redpanda also made &#8220;AI&#8221; capabilities its focus lately. But instead of just making it easier to call OpenAI API, <a href="https://www.redpanda.com/blog/ai-connectors-gpu-runtime-support">they actually integrated Redpanda Connect with LLMs</a>. This fits their <a href="https://ai.redpanda.com/">Sovereign AI</a> messaging quite well. </p><p>Overall, it feels like Redpanda is able to keep up with Confluent and, in some cases, innovate and advance further. I really hope that they&#8217;ll succeed, because we need more competion in this space.   </p><h3>Talks</h3><p>Here&#8217;s a selection of great talks I had a chance to attend: </p><ul><li><p><strong>Consistency and Streaming: Why You Care Should About It</strong>. If you&#8217;ve been following Materialize, you won&#8217;t learn anything new, but if the topic of data consistency in the streaming context is new to you, this is a great explainer. My advice to Materialize is to cover the use case of using payload-level timestamp fields as virtual timestamps when consuming Kafka topics - this is what 80% of people care about.  </p></li><li><p><strong>Scaling Data Ingestion: Overcoming Challenges with Cell Architecture</strong>. A pragmatic way to scale stream-processing via object storage. Showing a solid example of the cell architecture in the wild. And some real-world comparisons between Iceberg, Paimon and raw files.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kacy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kacy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kacy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kacy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kacy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kacy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg" width="1758" height="1017" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1017,&quot;width&quot;:1758,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:295050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kacy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kacy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kacy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kacy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f1f388b-372d-4840-adbc-02ed907c3c65_1758x1017.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">You&#8217;ll be surprised to learn who won in the end&#8230;</figcaption></figure></div></li><li><p><strong>Enabling Flink's Cloud-Native Future: Introducing Disaggregated State in Flink 2.0</strong>. Flink 2.0 will be getting a state backend that natively supports object storage. This comes with a lot of challenges. It seems like Async APIs will help with reducing the impact of increased latency. The current implementation performs at 40% of the baseline level (disk-based), which is considered pretty good. We&#8217;ll see what the final number will be.</p></li><li><p><strong>Events at the (API) Horizon: How to synthesize domain events &amp; changes from your HTTP/REST APIs.</strong> Very interesting talk comparing eventing and REST APIs. A demo of <a href="https://eventception.io/">Eventception</a>, which is worth checking if you use a service proxy like Enovy or Kong and care about events.</p></li><li><p><strong>Flinking Enrichment: Shouldn't This Be Easier?</strong> Legendary David Anderson talking about one of the most challenging problems in streaming: data enrichment. Lots of focus on SQL and join semantics, with many great learnings. It&#8217;d be great to see more low level examples in the future. </p></li><li><p><strong>Bridging the Kafka/Iceberg Divide.</strong> How do you represent a Kafka topic in the Avro format as an Iceberg table? What if it has incompatible versions? Folks from Confluent sharing their learnings from building Tableflow. </p></li><li><p><strong>Building a Scalable Flink Platform: A Tale of 15,000 Jobs at Netflix.</strong> Nice talk from Netflix showing the evolution of their Flink managed platform that works at scale. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TOwL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TOwL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 424w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 848w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TOwL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg" width="1456" height="878" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:878,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:478400,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TOwL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 424w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 848w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!TOwL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F543270bd-af5b-4d92-98fa-ba93203d47c6_1908x1151.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Flink&#8217;s Control Plane at Netflix</figcaption></figure></div></li></ul><p>Also in my watchlist: </p><ul><li><p><strong>Speed Wins: The Basics of How to Push More Queries Through Each CPU Core.</strong></p></li><li><p><strong>The SQL Ecosystem: Powering the Instant World with 40-Year-Old Legacy? </strong></p></li><li><p><strong>Streamlining Entry into Streaming Analytics with JupyterHub and Apache Flink.</strong></p></li><li><p><strong>Towards a Self-Tuning Flink Runtime: A Year in Flink&#8217;s Scheduling.</strong></p></li><li><p><strong>Change Data Capture &amp; Kafka: How Slack Transitioned to CDC with Debezium &amp; Kafka Connect.</strong></p></li></ul><p>Finally, please check the <strong>Streamlining History: ClickHouse &amp; Flink's Fast-Track for Data Backfills</strong> talk from my co-worker Rafael Aguiar! In the world where Iceberg is supported natively by Kafka brokers, we&#8217;ll be using something like Flink&#8217;s Hybrid Source to merge the two. Rafael explains how to do that but with ClickHouse.</p><h3>Cool Vendors</h3><p>I had a chance to talk to a few really cool companies I hadn&#8217;t heard of before:</p><ul><li><p><a href="https://www.dbos.dev/">DBOS</a>: a new durable execution engine. It reminds me of <a href="https://restate.dev/">Restate</a>. They made some interesting design choices, like relying on Postgres for journaling or heavily using annotations/decorators in their SDKs, but they&#8217;re quite comparable in terms of functionality. Overall, the product feels somewhat simpler, probably in a good way.</p></li><li><p><a href="https://www.thatdot.com/">thatDot</a>, the company behind <a href="https://github.com/thatdot/quine">Quine</a>:</p><blockquote><p>Quine is a streaming graph interpreter; a server-side program that consumes data, builds it into a stateful graph structure, and runs live computation on that graph to answer questions or compute results. Those results stream out in real-time.</p></blockquote><p>Let me expand on this.</p></li></ul><p>I haven&#8217;t heard about this approach for stateful stream-processing before. It seems like they try to leverage some properties you can get by representing relations as graphs. </p><p>They do make some very strong claims. They say that they can support &#8220;infinite joins&#8221; because they&#8217;re not limited by time windowing &#8220;like every other event processor&#8221;, which sounds a bit naive.</p><p>First of all, you actually <strong>don&#8217;t need windowing</strong> to implement stateful stream-processing with Apache Flink, for example. Windowing is very helpful at limiting the amount of state to maintain, but you might be ok with the additional cost and complexity. In the case of that large streaming pipeline with many joins we implemented at Shopify (which I described above), we didn&#8217;t use windowing for most of the joins. We were able to ingest <strong>all of Shopify&#8217;s sales/order data</strong> (via CDC) and keep it in state (which was ~13 TB at the time). The savepointing was somewhat challenging, but it was still doable. </p><p>Even though the graphs can help you with representing the data better, you&#8217;re still limited by basic resources like memory. And when you start spilling data to disk, you might not be faster than Flink with RocksDB. </p><p>Anyway, I&#8217;d love for someone to do a proper benchmark comparing Quine and a non-windowed Flink pipeline. Their approach looks very, very interesting.</p><h3>&#8220;That Is Not a Real SQL&#8221;</h3><p>I overheard one of the developer advocates from a well-known company say something like this: &#8220;Well, Flink SQL is not a real SQL, you know, like in databases&#8221;. This was so frustrating to hear that I decided to write my response here. And by the way, I&#8217;m not even a Flink SQL fan (it has its issues).</p><p>I acknowledge that modern databases can do amazing things. For example, DuckDB and Umbra/CedarDB really challenge what we think is possible. But there is nothing magical about them. In the end, every database just queries files in a <em>for</em> loop (more or less &#128578;). Pretty much every database does things like SQL to AST conversion, building logical and physical plans, and optimizing them. </p><p>Flink SQL is exactly the same. It relies on Apache Calcite quite a bit, which is also used by many other data frameworks and query engines. Flink SQL goes through the same stages like SQL to AST conversion, building logical and physical plans, and optimizing them. It just happens to usually work with batches of data received from data streams like Kafka topics, not files. </p><p>The world of databases and streaming systems is converging. Perhaps it&#8217;s advanced more than you realize. </p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I reject using &#8220;AI&#8221; without the quotes in the context of modern &#8220;AI&#8221; systems like ChatGPT and LLMs. Humanity hasn&#8217;t invented actual Artificial Intelligence yet. What we have is Machine Learning. </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Tim left Confluent to join StarTree as a VP of DevRel. He returned to Confluent a few months ago in the same capacity. </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>To be honest, this wasn&#8217;t completely that team&#8217;s fault. At the time, Shopify didn&#8217;t have a reliable way of sending domain events (e.g. with the Outbox pattern), and we couldn&#8217;t tolerate any data loss. </p></div></div>]]></content:encoded></item><item><title><![CDATA[Streaming-First Architecture]]></title><description><![CDATA[Will It Stream?]]></description><link>https://www.streamingdata.tech/p/streaming-first-archirecture</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-first-archirecture</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 02 Sep 2024 15:47:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/077e4280-258f-4dca-8881-f907c768a799_420x300.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><p>I started using &#8220;<strong>Streaming-First Architecture</strong>&#8221; term a while ago, but recently, many people started asking what I mean specifically. I&#8217;d love to explain! </p><p>There are several building blocks, and most of these shouldn&#8217;t be surprising:</p><ul><li><p>Kafka-compatible streaming platform (e.g. Apache Kafka, Confluent, Redpanda, WarpStream).</p></li><li><p>Stream-processing frameworks (e.g. Apache Flink, Kafka Streams, Materialize).</p></li><li><p>Connectors (e.g. Kafka Connect, Flink CDC).</p></li><li><p>Various databases and datastores that work well with real-time data (e.g. OLAP engines, LakeHouses).</p></li></ul><p>However, the key principle is treating streaming data as&nbsp;<strong>a source of truth</strong>. Historically, streaming has been used for data <em>transit</em>: ingesting and delivering data to a data lake/warehouse or a database. Topics in a streaming platform like Kafka could have a few hours or a few days of retention. When that time is over, the data gets deleted (and if you couldn&#8217;t persist it for any reason, then it&#8217;s&#8230; gone). </p><p>In the Streaming-First Architecture, we treat streaming data as <em>a source of truth</em>, which practically means: </p><ul><li><p>Modelling topics as changelogs (you can read more about this <a href="https://streamingdata.substack.com/p/changelog-vs-append-only-data-streams">here</a>). Ideally, enabling compaction. </p><ul><li><p>This allows us to treat Kafka a bit more like a database: we can use messages not just as inserts, but also updates and deletes. It makes it possible to correct / backfill data by just emitting new messages.</p></li></ul></li><li><p>Setting <em>infinite retention</em> for the topics. This usually requires using some form of Tiered Storage. </p></li></ul><p>All of these together allow us to keep the data in the streaming platform <em>forever</em>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!awDL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!awDL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!awDL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!awDL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!awDL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!awDL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg" width="728" height="495.23809523809524" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:500,&quot;width&quot;:735,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:72523,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!awDL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!awDL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!awDL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!awDL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8037e1cb-57cb-491e-8bc7-e16fd10f3d40_735x500.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>What are the benefits? </h3><p>I don&#8217;t think I need to tell you about the benefits of streaming data (otherwise, this newsletter has failed &#128512;). </p><p>However, it&#8217;s not very common to keep data in the streaming platform forever, so let me expand here. It was prohibitively expensive before the introduction of Tiered Storage. And it&#8217;s not just the cost. The operational complexity of archiving data from Kafka to long-term storage like HDFS, then object storage, and now LakeHouses is still fairly high. Sure, it might be fine for a handful of topics, but doing it at scale with schema evolution and versioning support is still non-trivial. And when using historical data, you either need to support a <em>hybrid source pattern</em> (reading historical data from the archive first, then switching to the &#8220;edge&#8221; in Kafka) or <em>re-hydration</em> of topics from historical data (which surely messes up the ordering).  </p><p>In the Streaming-First Architecture, you just set the consumer to read from the <em>earliest</em> offset and&#8230; that&#8217;s it. It may seem like a small detail, but it makes a huge difference when it comes to operational complexity. Kafka API also allows you to initialize consumers with a given timestamp, which is very handy in this case.</p><p>This approach also allows you to keep a lot of heavy transformation logic in the stream-processing layer. You can push the most demanding joins and other stateful computations to your database of choice, but many stateless computations, as well as aggregations, are straightforward to implement in the streaming world.</p><h3>Something is missing</h3><p>When you only have Kafka topics and consumers / stream-processors as building blocks, you quickly realize that you can&#8217;t perform many computations on the historical data very efficiently. Kafka doesn&#8217;t support any kind of lookup queries. So, very often, you&#8217;ll have to scan through the whole topic to find a handful of records. The throughput is limited by the number of partitions. This may seem like a terrible and wasteful approach. However, it can work sometimes: consumers in Kafka are fairly cheap; you just need to get the networking right. Waiting extra time for backfills may also be justified. </p><p>But just like with Tiered Storage, we&#8217;re expected to see a massive improvement in this area in the next ~6-9 months. Redpanda announced plans to introduce Iceberg support for Tiered Storage a while ago, Confluent is working on <a href="https://www.confluent.io/blog/introducing-tableflow/">Tableflow</a>, and WarpStream seems to be working on a query engine as well. </p><p>A query engine on top of the streaming platform is a game changer. We don&#8217;t need to archive our streaming data to a LakeHouse anymore; the streaming platform <em>has become</em> a LakeHouse! </p><p>This solves the lookup queries (as long as the query engines support predicate pushdown) and throughput when backfilling. </p><p>This may also solve the painful eventual consistency problem that you face when heavily relying on streaming. <a href="https://streamingdata.substack.com/p/do-you-really-need-exactly-once-delivery">Exactly-once is hard</a>. I imagine most of the query engines built on top of Kafka storage to support some form of snapshot isolation.  </p><p>Of course, some of it is still a speculation. But the direction is very clear!</p><h3>But does it scale? </h3><p>We&#8217;ll see. Personally, I worked with <em>hundreds of terabytes</em> stored in the streaming platform without any issues. </p><p>But a lot depends on the implementation of Tiered Storage. I&#8217;ve seen some implementations that don&#8217;t perform well with high concurrency; they only expect the historical data to be accessed infrequently. </p><p>I have a lot of faith in the new wave of projects that heavily rely on object storage. <a href="https://streamingdata.substack.com/p/streaming-platforms-in-the-cloud-era">Here</a> I wrote about WarpStream, which I see as a clear leader in this area right now.</p><h3>Isn&#8217;t it just Kappa Architecture? </h3><p>In my opinion, the original Kappa Architecture is more of a vision. It doesn&#8217;t answer many hard questions that immediately come up when you try to implement it. It doesn&#8217;t prescribe almost anything except using Kafka. </p><p>Using a different name makes it clear: I&#8217;m proposing something quite specific and opinionated. </p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Streaming Platforms in the Cloud Era]]></title><description><![CDATA[An ode to WarpStream.]]></description><link>https://www.streamingdata.tech/p/streaming-platforms-in-the-cloud-era</link><guid isPermaLink="false">https://www.streamingdata.tech/p/streaming-platforms-in-the-cloud-era</guid><dc:creator><![CDATA[Yaroslav Tkachenko]]></dc:creator><pubDate>Mon, 15 Jul 2024 15:47:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1f612531-8119-4b22-8cde-45654d65495a_400x320.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Please <a href="https://streamingdata.substack.com/subscribe">pledge your support</a> if you find this newsletter useful. I&#8217;m not planning to introduce paid-only posts anytime soon, but I&#8217;d appreciate some support from the readers. Thank you!</em></p><div><hr></div><p>WarpStream made a lot of noise with <a href="https://www.warpstream.com/blog/kafka-is-dead-long-live-kafka">its announcement</a> in July 2023. Kafka-compatible streaming platform based on object storage with no local disks! Some called it brilliant; some called it terrible. It made a huge impact nonetheless. </p><p>In July 2024, I&#8217;m confident to say that this is precisely where the industry is going. And instead of theorizing, I want to share <strong>my personal experience of running WarpStream in production at scale</strong>.</p><h3>Recap</h3><p>If you don&#8217;t breathe streaming platforms like some of us, let me summarize the architecture behind WarpStream. It&#8217;s quite simple and elegant:</p><ul><li><p>Separate data in the data plane (e.g. payloads) from the metadata in the control plane (e.g. topic/partition information). </p></li><li><p>Use object storage as your primary (and only) data storage. Use compaction. </p></li><li><p>Make the data plane (&#8220;agents&#8221;) completely stateless. </p></li><li><p>Implement smart routing that can leverage cloud economics (e.g. traffic within the availability zone is free). </p></li></ul><p>Finally, sprinkle everything with a bunch of intelligent optimizations like <a href="https://www.warpstream.com/blog/minimizing-s3-api-costs-with-distributed-mmap">this one</a>. As a result, you get a streaming platform with higher latency but superior in every other aspect. </p><h3>Not Just WarpStream</h3><p>Many people saw the clear benefits of a cloud-native architecture that WarpStream demonstrated. In the last 12 months:</p><ul><li><p>Confluent has announced <a href="https://www.confluent.io/blog/introducing-confluent-cloud-freight-clusters/">Freight Clusters</a>. </p></li><li><p>StreamNative has announced <a href="https://streamnative.io/blog/ursa-reimagine-apache-kafka-for-the-cost-conscious-data-streaming">Ursa</a> for Apache Pulsar.</p><ul><li><p>Perhaps it was <a href="https://twitter.com/richardartoul/status/1790453437861159280">too inspired</a> by WarpStream&#8230;</p></li></ul></li><li><p>AutoMQ, a cloud-native fork of Kafka, has made <a href="https://www.automq.com/blog/innovation-in-shared-storage-makes-kafka-great-again">a similar announcement</a> as well. </p></li></ul><p>And a few new projects came out of stealth:</p><ul><li><p><a href="https://tektitedb.com/">Tektite</a>, not just a streaming platform but a stream-processing engine as well.</p></li><li><p><a href="https://s2.dev/">S2</a>, tries to unify the ideas of object storage and data streaming even more. </p></li><li><p><a href="https://buf.build/blog/bufstream-kafka-lower-cost">Bufstream</a>, provides tighter integration with the Schema Registry and Protocol Buffers. </p></li></ul><p>It&#8217;s notable that some systems decided not to get rid of the disks completely. E.g., AutoMQ explained that low latency is still extremely important for the streaming workloads, so you should have an option of using EBS disk as a Write-Ahead-Log (more on this below).</p><p>I&#8217;m sure many other vendors are currently working on similar projects. But WarpStream was the first to use this architecture, so everyone will benefit from learning from its experience. </p><p>So here are some learnings. </p><h3>Simplicity</h3><p>I used to run and be on-call for Apache Kafka clusters. Large ones. In the cloud and on-prem. </p><p>I used Confluent Cloud and AWS MSK. I was a very early adopter of Redpanda Cloud.</p><p>I even used something called CloudKarafka (before the rename). </p><p>And after 7+ years of running and interacting with all these platforms, I can genuinely say that <em>WarpStream is the easiest platform to run</em>. No, I mean it. I even insisted on using the BYOC offering despite having a small team.</p><p>You just need to ensure that your WarpStream agents don&#8217;t go above 90% CPU. Ideally, with some autoscaling in place. That&#8217;s it. It&#8217;s nearly indestructible otherwise. You can casually <strong>20x</strong> the traffic, observe the auto-scaling kick in, and the traffic spike is soaked! </p><p>You also don&#8217;t need to think about data skew and data rebalancing: everything is written to object storage and compacted right away.</p><p><strong>The data/metadata separation and stateless agents make it that simple to run.</strong></p><p>Software engineers outside of the data infra community have been criticizing Kafka for its complexity. But what if operating Kafka can be no different from operating a web service?</p><p>WarpStream talks a lot about the absence of inter-AZ traffic and the cost implications. In my opinion, the perceived simplicity of their architecture (on the user side) is more important. </p><h3>Agent Roles</h3><p>Even though WarpStream architecture looks simple, it&#8217;s flexible enough to support different types of topologies, something that's impossible with a regular set of Apache Kafka brokers. </p><p>For example, in addition to your regular agents, you can deploy an extra set of agents (an agent group) that only has the <strong>proxy-consume</strong> role, so you can have a dedicated <em>read-only</em> Kafka endpoint. Or the opposite, agents with the <strong>proxy-produce</strong> role could be used to only support data ingestion. Or you can offload compaction and other background jobs to dedicated set of agents with the <strong>jobs</strong> role. </p><p>This may eliminate the need to have different types of clusters optimized for different workloads, something I had to do a few years ago with Apache Kafka:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VCTd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VCTd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 424w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 848w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 1272w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VCTd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp" width="1456" height="818" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:818,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25336,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VCTd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 424w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 848w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 1272w, https://substackcdn.com/image/fetch/$s_!VCTd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd6fd0d-9496-4d4b-b0dd-4c24efb60225_1456x818.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">We used to have different types of Apache Kafka clusters to support different workloads</figcaption></figure></div><p>To clarify, this separation of roles is not <em>really</em> needed to implement WarpStream-like architecture. Other vendors may choose not to do it. But having it gives a lot of control to the users and can eliminate even more operational complexity. </p><h3>Cost</h3><p>Yes, it seems to be cheaper than alternatives. </p><p>Autoscaling helps a lot to avoid provisioning additional infrastructure to handle traffic spikes. </p><p>S3 is extremely cheap as a primary storage. </p><p>WarpStream doesn&#8217;t care how many partitions, active TCP connections or compacted topics you have (yep, all these are <a href="https://docs.confluent.io/cloud/current/clusters/cluster-types.html#enterprise-limits-per-cluster">used by some vendors</a>). The pricing model just tracks the throughput and the number of object storage requests. </p><p>And then there is the no inter-AZ traffic guarantee. This requires some setup on the client side, but it&#8217;s a one-time, straightforward config change. And here&#8217;s how you can achieve paying $0 for inter-AZ networking <em>end-to-end</em>: </p><ul><li><p>Setup WarpStream BYOC and place at least one agent in each zone. </p></li><li><p>Configure <a href="https://docs.warpstream.com/warpstream/configuration/configure-clients-to-eliminate-az-networking-costs">the required client changes for your application</a>.</p></li><li><p>Ensure that each instance of a given stream-processing application (e.g. Apache Flink or Kafka Streams) is placed into the same AZ.</p></li></ul><p>As a result, <em>all</em> traffic between your streaming platform (e.g. WarpStream) and stream-processing applications is constrained to a single AZ! Of course, this may not be what you want from the reliability perspective, but if you can tolerate some downtime while reassigning workloads between AZs, this can be a very attractive option. Of course, WarpStream is designed to fallback to other AZs in this scenario; you just need to ensure your stream-processing application is moved.</p><p>Despite <a href="https://azure.microsoft.com/en-ca/updates/update-on-interavailability-zone-data-transfer-pricing/">the Azure announcement</a>, I don&#8217;t believe AWS or GCP will stop charging for inter-AZ traffic soon. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qzr6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qzr6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 424w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 848w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 1272w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qzr6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png" width="1142" height="406" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:406,&quot;width&quot;:1142,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30400,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qzr6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 424w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 848w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 1272w, https://substackcdn.com/image/fetch/$s_!Qzr6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1b598da-d659-4f80-bbb8-db24e2c0b454_1142x406.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">My new favourite game: balancing traffic across AZs</figcaption></figure></div><h3>&#8220;Free&#8221; Partitions </h3><p>Well, not completely free, but close to that. </p><p>Due to the way WarpStream handles batching (any agent can batch data from any topic/partition together) AND the fact the metadata is separated, having an <em>actively written</em> partition incurs very low overhead. And having an <em>inactive</em> partition is almost free: you just need to store the metadata (and return it in the metadata requests). </p><p>This means that you can generally create more topics and don&#8217;t think too much about hitting a partition limit. You&#8217;ll be fine with <em>tens of thousands</em> of partitions with a few agents, as long as you don&#8217;t write to all of them at once. In my opinion, that&#8217;s why WarpStream doesn&#8217;t use partition count for billing or throttling. </p><p>This might seem like a small detail, but it brings WarpStream closer to the vision of the streaming-first data architecture I&#8217;ve been trying to popularize in the last few years. A streaming platform can be a better source of truth for your data infra. It needs a few things, and the ability to have more topics and more partitions without massive clusters is one of those (I mention another at the end). </p><h3>What&#8217;s the Catch? </h3><p>You need to <a href="https://docs.warpstream.com/warpstream/configuration/configure-clients-to-eliminate-az-networking-costs">configure</a> and <a href="https://docs.warpstream.com/warpstream/configuration/configure-kafka-client/tuning-for-performance">tune</a> your clients certain way. This is a one-time investment, though.</p><p>Transactions are WIP (but <a href="https://streamingdata.substack.com/p/do-you-really-need-exactly-once-delivery">you may be fine without them</a>).</p><p>And then there is latency. By default, you get around <strong>a second</strong> of p99 end-to-end latency. You can easily shave off a few hundred milliseconds with a couple of simple config changes (like agent batching). It&#8217;s still going to be higher than what you get with Apache Kafka or Redpanda.</p><p>However, in my experience, this is perfectly fine for many data pipelines. Populating data lakes and/or data warehouses - totally fine. Change data capture for replicating data to search, cache or K/V database - fine. Ingesting observability data - probably fine. A lot of ML use cases like feature extraction are also fine. </p><p>Of course, there are some domains where you do need lower latency. Fraud detection, trading, online gaming, etc. Kafka-like platforms are also frequently used for messaging between microservices. And if you have several &#8220;hops&#8221; before triggering a user-facing action, for example, latency will add up quickly. </p><p>That&#8217;s why several vendors mentioned that you can&#8217;t just rely on object storage for low-latency use cases. AutoMQ, for example, mentions using EBS disks for low-latency Write-Ahead-Log.</p><p>In fact, I believe that WarpStream architecture already supports this use case. <a href="https://docs.warpstream.com/warpstream/configuration/low-latency-clusters">WarpStream can use the S3 Express One Zone</a> bucket for landing data with low latency to one place and then use a compaction mechanism for moving data to the standard bucket for permanent storage. This brings p99 for the end-to-end latency to <strong>~150ms</strong>. Even AutoMQ mentions S3 Express One Zone as an alternative to EBS.</p><p>I don&#8217;t think it&#8217;ll require much work (Richie, Ryan, forgive me for saying this &#128578;) to generalize this approach, so a regular disk or a NoSQL database can be used instead for landing data. This can probably bring latency to tens of milliseconds, which makes it comparable to a typical streaming platform. Of course, it increases cost. And this is exactly how you need to balance this: cost vs latency. </p><h3>Final Thoughts</h3><p>WarpStream is not perfect. There are some rough edges, some APIs are not yet implemented. The Schema Registry support is still WIP. </p><p>But the fundamentals are solid. I&#8217;m so excited about the future and what WarpStream-like architecture allows us to do. </p><p>WarpStream really moves us closer to what I call streaming-first data architecture. The only missing piece right now is querying the data with something other than the Kafka protocol: REST API, Apache Iceberg integration, Trino connector or something similar. WarpStream already handles the storage, metadata and compaction needed for building the query engine.</p>]]></content:encoded></item></channel></rss>