As far as ideal use cases, we use NATS for https://plane.dev in two ways:
- As a message bus, it is a layer of abstraction on top of the network. Instead of each node needing to establish a connection to every node it needs to connect to, it just connects to a NATS cluster and messages are routed by subject. This is great for debugging because we can "wiretap" messages on a given subject pattern and verify what's being sent. We even have a service that listens on NATS subjects and conditionally turns events into Slack messages.
- It has a built-in RAFT implementation (via JetStream), which we piggyback on when we need to create consensus among nodes.
NATS certainly has its quirks, but I can't recommend it highly enough if you need any sort of pub/sub or stream processing. It even has built-in key-value and object storage for when you need to store larger messages or content. I definitely prefer Jetstream to Kafka in pretty much every use case I can think of. At my current employer (https://cosmonic.com) we use NATS not only for wasmCloud, but we also stream log data and metrics and it keeps up with everything we throw at it with a very low footprint. Auth is kind of counterintuitive until you've spent some time with it, but NATS provides you with a ton of flexibility (docs here: https://docs.nats.io/running-a-nats-service/configuration/se...).
https://natsbyexample.com/ is a great resource, and can do a better job than I can in illustrating the various ways NATS can be used along with different deployment topologies.
... the protocol is text-based like HTTP with CR LF for field both for the client, https://docs.nats.io/reference/reference-protocols/nats-prot..., and cluster protocols, https://docs.nats.io/reference/reference-protocols/nats-serv... -- which means encoding overhead if your payloads are binary. So depending on your definition of performance, ymmv.
I really do not see how implementing an API across multiple languages is easier by making a new linefeed-based protocol, https://github.com/nats-io/nats-server/blob/0421c65c888bf381..., than just using code-generated JSON or gRPC (Protobuf or Flatbuffers). One could then write subscriptions/clustering algorithms in a protocol-neutral library.
What's great is that NATS is written in go and we can easily embed it for testing and dev purposes. Furthermore, Synadia makes it super easy to run NATS across multiple regions.
But yes, to be able to replay without side effects you’ll want to make sure you’re setting up the consumers correctly. That may need some custom logic, but isn’t that necessary with any message queue?
[1]: https://docs.nats.io/using-nats/developer/develop_jetstream
https://nightlies.apache.org/flink/flink-docs-master/docs/de...
Besides that I'm also working on a UI solution, that will help to get better overview of your cluster: https://qaze.app/
IMO it is a real waste of developer time to code up a new transport protocol without determining that the existing ones don't work or don't perform as well as needed. Multiply that by all the programming languages that need to be supported... when instead the client APIs could have been mostly code generated.
Although may only apply to the "client-side" API, what is going in the message payload? JSON probably, or some other serialization format. I don't think a lot of developers are hand writing parsers for their own payloads. The overhead of the JSON or Protobuf parser is already in there.
Derek seems like the kind of person who might know a thing or two about messaging systems.
I really like what NATS has become, and I do appreciate the simplicity of the protocol.
Pull does have advantages over push (e.g. one-to-one flow control since the transfer of the messages is initiated by the client (pull requests)), and they are basically functionally equivalent (only thing push can do that pull can not is send a copy of all the message to all the subscribers, should you ever need it). They both exists because historically push came first and then pull later).
As a developper using NATS JetStream you should really not have to worry about push or pull, you should just care whether you want to consume the messages via call back or via an iterator or via fetching batches, after that whether pull or push is being used underneath the covers is irrelevant to you.
And this is exactly how it is in the new JetStream API (https://github.com/nats-io/nats.go/tree/main/jetstream#readm...) you don't have to worry about push/pull anymore and you can consume in any of the 3 ways described above (callback, iterator, fetch batch) it's all a lot simpler and easier to use.