From ccf53e8d23d4b507db75fff44eb979c6d2d0824d Mon Sep 17 00:00:00 2001 From: Luca Date: Mon, 15 Jul 2024 17:28:35 +0200 Subject: [PATCH 1/3] feat: first incomplete draft of rabbit streams blogpost --- package-lock.json | 4 +-- public/posts/rabbit-streams/hero.png | Bin 0 -> 14317 bytes src/content/blog/rabbit-streams.md | 52 +++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 public/posts/rabbit-streams/hero.png create mode 100644 src/content/blog/rabbit-streams.md diff --git a/package-lock.json b/package-lock.json index 3033b7a..c7bad02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "asto-blog", + "name": "coders51-blog", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "asto-blog", + "name": "coders51-blog", "version": "0.0.1", "dependencies": { "@astrojs/check": "^0.5.10", diff --git a/public/posts/rabbit-streams/hero.png b/public/posts/rabbit-streams/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..5a82d04da35d7c632fe9a3cab8cee8a4c07f594e GIT binary patch literal 14317 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 literal 0 HcmV?d00001 diff --git a/src/content/blog/rabbit-streams.md b/src/content/blog/rabbit-streams.md new file mode 100644 index 0000000..d79333d --- /dev/null +++ b/src/content/blog/rabbit-streams.md @@ -0,0 +1,52 @@ +--- +title: 'Rabbit Streams' +description: 'An introduction to Rabbit Streams' +author: 'Luca Menghini' +keywords: ["rabbit", "stream", "streams", "rabbitmq"] +pubDate: '07-16-2024 10:00' +heroImage: 'rabbit-streams/hero.png' +timeRead: '20' +draft: true +--- + +## Introduction +So, we all know about RabbitMQ, the world's most loved message broker, right? We at coders51 use it, like, all the time: it's our go-to solution to asynchronous communication between different services. It's performant, reliable, battle-tested, and written in Erlang (which helps with the reliability and performance parts). What is not to love? +But, did you know about the good word? That RabbitMQ can basically substitute Kafka in your infrastructure? +This is a somewhat less known feature that has been around for about 3 years now, first as a plugin and then as a native feature (more on that later). +Basically, a stream is a persistent, append-only log of messages that allows for high-throughput publishing and consumption, where messages are retained and can be re-read multiple times by consumers, enabling use cases such as event sourcing, replay, and long-term storage of event data. Isn't that basically what a Kafka topic is? Not quite, but close. We'll revisit this point later. + +## Differences between Stream Plugin and native Streams +Just like we anticipated earlier, Streams were first introduced as a plugin and then implemented as a native feature: but the plugin still exists and is basically the standard way in which streams are used. How so? +This is due to the fact that in order to achieve the high throughput that one might expect and need from a stream, it's best to use a different protocol from AMQP0.9.1, a protocol especially developed for this specific use case. +So, while you could define a stream and interact with it using the usual AMQP0.9.1 protocol (and that's the "native" support of streams), if you wanted to leverage the power of streams fully you'd do best enabling the plugin and interacting with those streams using the Osiris protocol. +The catch? The usual AMQP clients do not support this protocol, and you'll have to add a new dependencies to your app. Stream clients are available for most of the mainstream languages - here's the list. Shameless plug: we at coders51 developed the one for node - let us know what you think. +Also there are a couple of features, namely SuperStreams and Sub Entry batching which are available only thru the plugin. More on the SuperStreams shortly. + +### Smart client, dumb broker +Now, if you have ever worked with RabbitMQ, you might recall that in RabbitMQ all the routing is done on the broker's side through the definition of queues, exchanges and bindings: this is usually surmised with the "dumb client / smart broker" dichotomy. With the streams protocol, the opposite actually applies: most of the logic is done client-wise. This is quite important, for example, in the context of SuperStreams, and is one of the reasons why that feature is not available without the plugin. + +### SuperStreams +So, earlier we mentioned that a RabbitMQ stream is similar in some regards to a Kafka topic, but not quite. That is because a stream is not partitioned: it's usually replicated in clusters just like a vanilla quorum queue, but there is no concept akin to a partition, i.e. the stream is not actually distributed, so having multiple applications consuming from a single stream in parallel might prove challenging. +No worries: SuperStreams are here, and they have partitions just like the one you might know from Kafka. +A SuperStream is basically a collection of "vanilla" streams, which are referred in this context as "partitions", and every time we publish to this SuperStream (which is seen by the end user of the client as a single entity) we extract a routing key which shall be used to decide on which actual partition we should publish. By providing a "routing key extractor" callback we can guarantee that multiple messages that share some property are published to the same partition, just like in Kafka. And just like in Kafka, we can either subscribe to a single partition (by creating a consumer for a stream) or we can subscribe to all partitions, by creating a SuperStream consumer. And just like in Kafka, ordering is not guaranteed cross-partitions. Looks pretty close to me. + +### Why you might want to use RabbitMQ streams instead of Kafka +Because you already got Rabbit and it can do both. Why have two services in your infrastructure that do basically the same thing when you can limit your complexity to one? +Kafka is still a little bit faster though in throughput, so if you really are challenging the boundaries of Kafka maybe it's better if you keep using that. + +## Performances and benchmarking +Now, the RabbitMQ site tells us this. But we want to double check and I've run the test on my machine. Here's what I've found + +### Stream plugin + +### Stream native + +### Now, let's compare it to Kafka, same machine + +## What is your use case? +### Event Sourcing + +### Logs + + + From 82673aa14a0a7ce809c5019c0d4c4f1a88b87c4a Mon Sep 17 00:00:00 2001 From: Luca Date: Mon, 15 Jul 2024 17:45:21 +0200 Subject: [PATCH 2/3] feat: second incomplete draft of rabbit streams blogpost --- src/content/blog/rabbit-streams.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/content/blog/rabbit-streams.md b/src/content/blog/rabbit-streams.md index d79333d..be29d35 100644 --- a/src/content/blog/rabbit-streams.md +++ b/src/content/blog/rabbit-streams.md @@ -13,7 +13,8 @@ draft: true So, we all know about RabbitMQ, the world's most loved message broker, right? We at coders51 use it, like, all the time: it's our go-to solution to asynchronous communication between different services. It's performant, reliable, battle-tested, and written in Erlang (which helps with the reliability and performance parts). What is not to love? But, did you know about the good word? That RabbitMQ can basically substitute Kafka in your infrastructure? This is a somewhat less known feature that has been around for about 3 years now, first as a plugin and then as a native feature (more on that later). -Basically, a stream is a persistent, append-only log of messages that allows for high-throughput publishing and consumption, where messages are retained and can be re-read multiple times by consumers, enabling use cases such as event sourcing, replay, and long-term storage of event data. Isn't that basically what a Kafka topic is? Not quite, but close. We'll revisit this point later. +Basically, a stream is a persistent, append-only log of messages that allows for high-throughput publishing and consumption, where messages are retained and can be re-read multiple times by consumers, enabling use cases such as event sourcing, replay, and long-term storage of event data. Obviously, messages in a stream do not need to stay in the stream indefinetely: we also have the tools to define a retention policy so that messages that are not considered relevant anymore can be archived or destroyed. +Isn't that basically what a Kafka topic is? Not quite, but close. We'll revisit this point later. ## Differences between Stream Plugin and native Streams Just like we anticipated earlier, Streams were first introduced as a plugin and then implemented as a native feature: but the plugin still exists and is basically the standard way in which streams are used. How so? @@ -35,18 +36,30 @@ Because you already got Rabbit and it can do both. Why have two services in your Kafka is still a little bit faster though in throughput, so if you really are challenging the boundaries of Kafka maybe it's better if you keep using that. ## Performances and benchmarking -Now, the RabbitMQ site tells us this. But we want to double check and I've run the test on my machine. Here's what I've found +Now, the RabbitMQ site tells us this. +But we want to double check and I've run the test on my machine, which is a three years old laptop with a bunch of crap running on. +Here's what I've found ### Stream plugin +==WIP== ### Stream native +==WIP== ### Now, let's compare it to Kafka, same machine +==WIP== ## What is your use case? +Now, you might be asking yourself: alright, what is all of this good for anyways? Here are some ideas. + ### Event Sourcing +If you are looking to do some EventSourcing, a RabbitMQ stream might be a low hanging fruit for an event store. Some more specific products, free or otherwise, are available but I find that what a stream offers is more than enough to cover most cases. + +### Log aggregation +Do you need a single place where every log produced by your stack eventually ends up in? A stream again might be the solution you are looking for. -### Logs +### Data pipeline +Maybe you have in place a multi-step procedure to transform data, and would like to connect each step to the next - this is also an issue in which RabbitMQ streams shine. From 772d378331270ecfac117bbc7ddce39b3734a5e6 Mon Sep 17 00:00:00 2001 From: Luca Date: Mon, 29 Jul 2024 20:51:57 +0200 Subject: [PATCH 3/3] fix: applies several of gpad's suggestions --- src/content/blog/rabbit-streams.md | 51 ++++++++++++------------------ 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/content/blog/rabbit-streams.md b/src/content/blog/rabbit-streams.md index be29d35..7211394 100644 --- a/src/content/blog/rabbit-streams.md +++ b/src/content/blog/rabbit-streams.md @@ -1,9 +1,9 @@ --- -title: 'Rabbit Streams' -description: 'An introduction to Rabbit Streams' +title: 'An introduction to Rabbit Streams' +description: 'A first approach to the newish streams feature, what they are and how to use them' author: 'Luca Menghini' keywords: ["rabbit", "stream", "streams", "rabbitmq"] -pubDate: '07-16-2024 10:00' +pubDate: '07-30-2024 10:00' heroImage: 'rabbit-streams/hero.png' timeRead: '20' draft: true @@ -11,49 +11,38 @@ draft: true ## Introduction So, we all know about RabbitMQ, the world's most loved message broker, right? We at coders51 use it, like, all the time: it's our go-to solution to asynchronous communication between different services. It's performant, reliable, battle-tested, and written in Erlang (which helps with the reliability and performance parts). What is not to love? -But, did you know about the good word? That RabbitMQ can basically substitute Kafka in your infrastructure? +But, did you know about the good word? That Rabbit has introduced Streams? This is a somewhat less known feature that has been around for about 3 years now, first as a plugin and then as a native feature (more on that later). -Basically, a stream is a persistent, append-only log of messages that allows for high-throughput publishing and consumption, where messages are retained and can be re-read multiple times by consumers, enabling use cases such as event sourcing, replay, and long-term storage of event data. Obviously, messages in a stream do not need to stay in the stream indefinetely: we also have the tools to define a retention policy so that messages that are not considered relevant anymore can be archived or destroyed. +Basically, a stream is a persistent, append-only log of messages that allows for high-throughput publishing and consumption, where messages are retained and can be re-read multiple times by consumers, enabling use cases such as event sourcing, replay, and long-term storage of event data. Obviously, messages in a stream do not need to stay in the stream indefinetely: we can also define retention policies so that messages that are not considered relevant anymore can be archived or destroyed. Isn't that basically what a Kafka topic is? Not quite, but close. We'll revisit this point later. ## Differences between Stream Plugin and native Streams -Just like we anticipated earlier, Streams were first introduced as a plugin and then implemented as a native feature: but the plugin still exists and is basically the standard way in which streams are used. How so? -This is due to the fact that in order to achieve the high throughput that one might expect and need from a stream, it's best to use a different protocol from AMQP0.9.1, a protocol especially developed for this specific use case. -So, while you could define a stream and interact with it using the usual AMQP0.9.1 protocol (and that's the "native" support of streams), if you wanted to leverage the power of streams fully you'd do best enabling the plugin and interacting with those streams using the Osiris protocol. -The catch? The usual AMQP clients do not support this protocol, and you'll have to add a new dependencies to your app. Stream clients are available for most of the mainstream languages - here's the list. Shameless plug: we at coders51 developed the one for node - let us know what you think. -Also there are a couple of features, namely SuperStreams and Sub Entry batching which are available only thru the plugin. More on the SuperStreams shortly. +Just like we anticipated earlier, Streams were first introduced as a plugin and then implemented as a native feature: but the plugin still exists and is basically the standard way in which streams are used. +This is due to the fact that in order to achieve the high throughput that one might expect and need from a stream, it's best to use a different protocol from AMQP0.9.1, one especially developed for this specific use case. +So, while you could define a stream and interact with it using the usual AMQP0.9.1 protocol (and that's the "native" support of streams), if you wanted to fully leverage the power of streams you'd do best enabling the plugin and interacting with those streams using the dedicated binary protocol. +The catch? The usual AMQP clients do not support this protocol, so in order to use it you'll have to add a new dependencies to your app. Stream clients are available for most of the mainstream languages - you can find the full list [here](https://www.rabbitmq.com/docs/stream). +Shameless plug: we at coders51 developed the one for node - let us know what you think. +It is also important to mention that there are a couple of features, namely SuperStreams and Sub Entry batching which are available only through the plugin. More on the SuperStreams shortly. ### Smart client, dumb broker -Now, if you have ever worked with RabbitMQ, you might recall that in RabbitMQ all the routing is done on the broker's side through the definition of queues, exchanges and bindings: this is usually surmised with the "dumb client / smart broker" dichotomy. With the streams protocol, the opposite actually applies: most of the logic is done client-wise. This is quite important, for example, in the context of SuperStreams, and is one of the reasons why that feature is not available without the plugin. +Now, if you have ever worked with RabbitMQ, you might recall that in RabbitMQ all the routing is done on the broker's side through the definition of queues, exchanges and bindings: this is usually summed up through the "dumb client / smart broker" dichotomy. With the streams protocol, the opposite actually applies: most of the logic is done on the client. This is quite important, for example, in the context of SuperStreams, and is one of the reasons why that feature is not available without the plugin. ### SuperStreams -So, earlier we mentioned that a RabbitMQ stream is similar in some regards to a Kafka topic, but not quite. That is because a stream is not partitioned: it's usually replicated in clusters just like a vanilla quorum queue, but there is no concept akin to a partition, i.e. the stream is not actually distributed, so having multiple applications consuming from a single stream in parallel might prove challenging. +So, earlier we mentioned that a RabbitMQ stream is similar in some regards to a Kafka topic, but not quite. That is because a stream is not partitioned: it's usually replicated in clusters just like a vanilla `quorum` queue, but there is no concept akin to a partition, i.e. the stream is not actually distributed, so having multiple applications consuming from a single stream in parallel might prove challenging. No worries: SuperStreams are here, and they have partitions just like the one you might know from Kafka. A SuperStream is basically a collection of "vanilla" streams, which are referred in this context as "partitions", and every time we publish to this SuperStream (which is seen by the end user of the client as a single entity) we extract a routing key which shall be used to decide on which actual partition we should publish. By providing a "routing key extractor" callback we can guarantee that multiple messages that share some property are published to the same partition, just like in Kafka. And just like in Kafka, we can either subscribe to a single partition (by creating a consumer for a stream) or we can subscribe to all partitions, by creating a SuperStream consumer. And just like in Kafka, ordering is not guaranteed cross-partitions. Looks pretty close to me. -### Why you might want to use RabbitMQ streams instead of Kafka -Because you already got Rabbit and it can do both. Why have two services in your infrastructure that do basically the same thing when you can limit your complexity to one? -Kafka is still a little bit faster though in throughput, so if you really are challenging the boundaries of Kafka maybe it's better if you keep using that. - -## Performances and benchmarking -Now, the RabbitMQ site tells us this. -But we want to double check and I've run the test on my machine, which is a three years old laptop with a bunch of crap running on. -Here's what I've found - -### Stream plugin -==WIP== - -### Stream native -==WIP== - -### Now, let's compare it to Kafka, same machine -==WIP== +## Performances +The [official site](https://www.rabbitmq.com/docs/stream-core-plugin-comparison) mantains that, using the binary protocol, a client can consume several millions of messages per second. This obviously is very dependent on the performances of the client: both in terms of code, which library/language we are using, and by the machine the client is running on. My own experience is that you don't always break the million messages per second threshold, but the performance is always at least one or two orders of magnitude greater than by using the AMQP protocol. ## What is your use case? Now, you might be asking yourself: alright, what is all of this good for anyways? Here are some ideas. -### Event Sourcing -If you are looking to do some EventSourcing, a RabbitMQ stream might be a low hanging fruit for an event store. Some more specific products, free or otherwise, are available but I find that what a stream offers is more than enough to cover most cases. +### Large fan-outs +Here the streams really shine, since with streams there is no need for routing done server side through the exchanges: every subscriber can consume from the same stream without interfering with the others. + +### Replay / time traveling +With streams nothing is destroyed unless we explicitly instruct the broker to do so through strict retention policies. This mitigates the risk of losing data - we can always recover from a previous snapshot and replay all the messages after a specific offset. ### Log aggregation Do you need a single place where every log produced by your stack eventually ends up in? A stream again might be the solution you are looking for.