Apache Kafka Beyond the Basics: Windowing
confluent.io
confluent.io
The justification is usually a sort of handwave about scaling, but I tend to be skeptical of that argument.
I remember in the early 2000's writing a system that handled all of the consumer equipment orders and returns for Verizon, pick pack and ship and advanced billing integration with the ILEC phone bill, credit systems, IVR, etc... On a PII class server running SQL server stored procedures and a .net UI.
In 2009, I was processing a TB per month of 837 claims on even worse hardware.
Not that long ago, I saw a post on HN where a Casio calculator was handling the front page traffic.
My point is that even modest hardware has the capability to handle massive loads when the software is designed properly.
Kafka and it's ilk are great for certain use cases, but it's normally a mistake to start out with it unless you're really sure you know what you're doing.
CQRS and data-bus/event sourced systems can be tricky to get right, and you lose a lot when you go to async processing, especially when submitting transactions from a user-facing app.
Inevitably you have to create some sort of polling or server push mechanism to update the UI, and the number of edge cases that can bite you are vast.
The main advantage of Kafka is that you can:
1. Write a shitload of data to it fast
2. Experience a cluster failure or degradation with low risk of data loss
3. Retain absolute ordering, with caveats, if you're careful.
4. Run large numbers of concurrent consumers without imposing significant overhead on the cluster
That's pretty much it. I've made a good career the last few years out of Kafka, but there are _so_ many companies using it that don't need it, and what strikes me as passing odd is when I've been consulting on their Kafka adoption and tell them that, they don't want to hear it.
Which is really weird IMO because I stand to make far more money by encouraging them to use it unnecessarily because...
...Kafka is a complex solution to a complicated problem, and often people using it don't have the sheer scale of data that would necessitate taking on that complexity.
> In 2009, I was processing a TB per month of 837 claims on even worse hardware.
Kafka starts to shine when you're creating X TiB of data a day, and would like not to lose it.
It's best mentally modelled as a series of rather resilient tubes, that way people can stop thinking it's just a super duper scalable message queue, and they can just drop it in as a black box and get all the semantics they're used to from ActiveMQ / RabbitMQ etc.
Even Pulsar, which tries to emulate MQ semantics, isn't a drop-in replacement, at all. And it has even more moving parts than Kafka.
Company after company has spent years trying to just classify and normalize all of their data. These big data warehouse style environments always end up so brittle and take so much longer to get anything useful out of compared to the sort of immediate and incremental improvement you can get with a Kafka style migration away from these older systems. You're right that it's overkill for so many companies though. I'm curious to know where you've seen success with Kafka.
Much the same as you, as a replacement for brittle data pipelines where multiple services are generating data, and then a cron moves it across a network file system, or the apps are pushing to something like ES directly, which has caused data loss when their ES wasn't configured correctly, etc. etc.
The nice thing about Kafka is that it decouples those dependencies, which gives you room to scale the ingestion side, and also allows for failures without data loss.
The one caveat though, is that Kafka becomes the dependency, but in my years of using Kafka in anger (since 0.8), I've only ever encountered full cluster unavailability a few times.
Memorable ones: * a sysop who decided that the FD limit for processes on the boxes running their self-managed Kafka should be a nice low number, which prevented Kafka from opening sufficient sockets
* a 3 node cluster, where to "prevent data loss", they were using acks=all and had configured replicas to be 3, and min insync replicas to be 3, and then a broker had gone down. Yeah, not great that.
* A 2.5 stretch cluster (brokers and ZKs in two AZs, tie-breaker ZK in a 3rd) suffered a gradual network partition when an AWS DC in Frankfurt overheated, and they ended up with two leaders for the same topic partition in each of their main AZs, that were still accepting writes as they could hit minISR within their own DCs. There was some other weirdness in how they interacted with the tie-breaker ZK. And when the network partition was ended, neither of them could be elected leader. Had to dump the records from both brokers from the time the partition began, roll the brokers to allow an unclean leader election, then roll them again to turn it off once the election had succeeded, and then the client got to sift through the data and figure out what to do with it - as they weren't relying on absolute ordering, it was reasonably trivial for them to just write it again IIRC.
So for absolutely essential do not lose data, if Kafka connectivity was lost, the app should make itself unready, and then fail over to writing any uncommitted data to disk for a side-car to upload to S3 or similar.
Kafka's great, but you have to code deliberately for it, which is where I saw the biggest mistakes occur - strapping Kafka to ActiveMQ with Camel and expecting Kafka to work the same as ActiveMQ...
Is it in the same area as Graylog? How is it compared?
NATS is much more lightweight than the alternatives, and has a much simpler operation story and can run on low resource hardware very easily.
Kafka fits a very specific use case, and NATS tries to solve a much larger set of distributed computing use cases, including micro-services, distributed KV, streaming, pub/sub, object store and more.
It’s a very different philosophy, but can be very powerful when it’s deployed as a utility inside an organization.
We’ve seen so many success stories, especially companies moving to the edge, we continue to see NATS used as a common transport for all kinds of use cases in finance, IoT, edge, Industry 4.0, and Retail
It is robust and performant, with subject-based querying, HA, scalability, streams, key-value store, mirrors and at-least-once and exactly-once semantics.
Used in production on a large scale by companies across many industries.
If we break our application into small enough chunks then we start running into internal consistency issues, so we will introduce Kafka to resolve this. I'm dealing with it at the moment where my customer decided to break their crud application to CUD and R because "best practice". Now they have Kafka synchronising the two applications because it's a terrible design.
https://martinfowler.com/bliki/CQRS.html
It falls into the "you are not Google" problem solving hole.
I'm dealing with a financial institution doing this. CQRS should be an evolution if you find it complex to model, use, and scale not the initial implementation. Now we have another location to lose data.
My thinking was to use something like Kafka, leaning towards NATS, as a big pub sub pipe.
I'm not looking for scaling. We are slow and don't need real time. What I need is uniformity. I don't want this connection to interface through FTP while that one is over a REST API. I'd prefer one connection for our main system and little interfaces to connect everything to the same pipe.
NATS definitely tries to solve for that end to end experience, where you can have NATS simultaneously driving websocket connections as well as backend connections in a secure and performant way. I’ve personally had a ton of fun making interactive applications with NATS, it scales reliably and is really fun to work with
Kafka is a distributed log. A sibling comment to this mentions this as well, but I'm repeating it because I actually think that's were most people using kafka go wrong. You _can_ use kafka as a queue, but it'll would feel like using a drill to hammer a nail, would kind of work but would make you think the tool just sucks.
> The justification is usually a sort of handwave about scaling, but I tend to be skeptical of that argument.
Kafka does help with scaling in so far as you can independently scale the number of producers and consumers but I find kafka the most useful in its ability to allow multiple consumers to process the same message(s) at different rates.
For example let's say you have an app that's producing messages like "{foo: 1, bar: 2 }" and you need to count how many foos there are and how many bars there are. You could queue the messages, then have 1 service that does both, or you could use kafka and have a FooCounter and BarCounter service. They each process the same message(s) but ignore the part of the payload they don't care about.
While this is really trivial example, I've used, and have seen this pattern used for processing actual logs for example.
Kafka does what a datastore should and nothing more. It's what databases should have been. High performance is a consequence of that good design, but the good design is valuable in itself.
I would always start with Kafka. There are so many ways to shoot yourself in the foot with an SQL database that will bite you later, sometimes in a way that may corrupt your data permanently (e.g. read-modify-write logic), and you'll almost certainly end up having to change your data architecture to the one you'd've started with if you were using Kafka. Or you can just throw it in Kafka from day 1 and a lot of bad ideas just become impossible because the system gives you no way to do them.
I was also working on phone systems in the 2000's that ran at "web scale". We used MySQL, but we essentially built Kafka on top of MySQL - tables for every intermediate step in the process, and a way for the next step in the processing pipeline to mark which rows it had started/finished consuming.
> The justification is usually a sort of handwave about scaling, but I tend to be skeptical of that argument.
actually this sort of solution is a great fit to GPGPU, where each thread has some kind of a "window" and will perform N aligned accesses in a stepwise fashion to compute its particular data. Aligned/coalesced accesses and "re-computation" are very cheap in GPGPU and that often means you lean on re-computation rather than notarization or other "stateful" approaches.
I think something like this would be a great fit to AVX-512 probably.
It all just sort of works, what am I missing beyond this ? Is this the basics ? :)
I saw consumer groups and whatnot.. but didn't bother. FWIW this is actually running a lot of processes.. and it all just works.. also using Sentry to send errors/exceptions so I know when the consumers or the producer are not working
Having different consumer groups let's you have multiple different consumers for different purposes that DO process the same records.
Say you have a topic with 10 partitions. Consumer group A has 10 consumers and Consumer group B has 1 consumer.
Each consumer in group A will be assigned to a single partition,thus processing different messages.
The single consumer in group B will be assigned to all 10 partitions, processing the same messages as group A.
Kafka is a distributed log, so this pattern is useful for replicating data across downstream applications.
Not sure 'why of it'. If it were me doing that sort of behavior I would think the idea was short lived processes that do a small amount of work then disappear. For that idea, consumer group would not make sense as you would just want to start at the front or end of the topic and blast thru it anyway. Once you add the idea of two different things happening or gangs of processes working from the same events with partitions then consumer groups makes a lot more sense to add in. But retro fitting it back in would be awful? So default is 'random' groupid? Probably in the pip's somewhere what the rational is.
The other things in kafka world are stateful transformations, which you would normally do using Java's Flink. The closest in python is Faust (the fork) [0]. What are stateful aggregations? something like doing SQL on top of a topic: group_by, count, reduce, and joins. So similar to SQL that you have kSQL [1].
Consumer groups IMO falls under basic usage, if you need to scale, take a look at it, and what are partitions and replicas, with that in mind, you'll be ok.
[0]: https://github.com/faust-streaming/faust
[1]: https://www.confluent.io/blog/ksql-streaming-sql-for-apache-...
If not, then you'll have to manually commit the offsets and your consumer will have "at least once" semantics, meaning that you'll have to deal with duplicate messages (you should be designing idempotent pipelines, anyway)
Coz even Yelp says to „just in case schedule a maintenance window”
Besides this, operating Kafka never required much effort a part when we needed to re-balance partitions across brokers. Earlier versions of Kafka required to handle it with some external tools to avoid network congestions, but I think this is part of the past now.
On the other hand, Kafka still needs to be used carefully, especially you need to plan topics/partitions/replications/retention but that really depends by the application needs.
The crash happens 10–15 minutes into the downtime window of the first broker. Absolutely no one has been able to figure out why, or even to reproduce the issue.
Running out of things to try, we resorted to randomly changing all sorts of different combinations of consumer group timeouts, which are imho poorly documented so no one really understands which means which anyway. Of course all that tweaking didn’t help either (gunshot debugging never does).
This has been going on for the last two years. As far as I know, the issue still persists. Everyone in that project is dreading Amazon’s monthly patch event.
https://flink.apache.org/news/2015/12/04/Introducing-windows...
https://www.ververica.com/blog/session-windowing-in-flink
https://flink.apache.org/news/2020/07/30/demo-fraud-detectio...
I'm pretty sure Timescaledb is a very good product, but columnar vs row-based reactive streaming systems tend to very different needs.
human-centered developer experience
When I describe myself as interested in a human-centered developer experience, I'm making a reference to Don Norman (google Nielsen-Norman Group, or The Design of Everyday Things), who believed in human-centered design. I believe in not belittling the user/developer when they misuse an interface (website, CLI, API, what have you) but instead trying to understand what kind of internal motivation caused their behavior when it's unexpected to me. Making changes based on that leads to a good developer experience.