Why NATS Could Be Better for You!

Nolan
7 min readFeb 26, 2024

--

NATS logo

Hi everyone! šŸ‘‹ Iā€™m Nolan, and this is my first article. Iā€™m going to talk about NATS, a dedicated, fast, and scalable broker. Before diving into the article, please feel free to share your thoughts in the comments. Letā€™s get started!

ā€œThe purpose of this article is to give you the opportunity to understand NATS and decide when or where to use it.ā€

What is NATS?

Basically NATS is a broker that provides Publish/Subscribe and Request/Replay messaging paradigm, but also supports streams as well. Designed to be fast, lightweight and scalable and used in distributed systems.

šŸ”øKey Features:

  • Subject-based: Subject is like a phone number! meaning that you need a channel or something like that in order to send your message(s) or listen to it to receive messages.
  • Publish-Subscribe pattern: By default there is no persistent layer and NATS uses fire-and-forget pattern. That means you donā€™t need to wait for confirmation or acknowledgement and you just keep publishing!
  • Queuing group: A powerful feature comes in handy when you prefer not to fan out messages to all subscribers. In this approach, subscribers need to be registered in the same queue, allowing NATS to load balance messages among them.
  • Request-Reply pattern: The core NATS is built for pub/sub mechanism and this is a one-way street! because you cannot publish a message and wait for a respond. So you need a request/reply messaging that NATS supports!
  • JetStream: If you need a higher quality of service, JetStream is going to help you! provides a persistent layer on the top of core NATS, so published messages are going to be kept and even when clients are offline they are not going to lose them.

Donā€™t worry, I will dive into each one in the rest of the articlešŸ™ƒ.

1. subject-based

Publishers and Subscribers both need to a subject in order to send and consume a message. Subject is just a set of ASCII characters usually separated with a dot.

time.us.east
podcast.12312

Each dot separated string in a subject is called a token. So for example subject podcast.12312 has two tokens in total.

But how separating is going to help us? Well the power of subjects in NATS come in when you know about wildcards. Two wildcards are provided by NATS (* and >) and make subscribing more flexible.

If a consumer for example subscribes to the subject time.*, each of these subjects are valid:


time.us
time.de

So you see the start symbol matches exactly one token.

Now If you want to match more that one tokens, you can use > . Letā€™s say you subscribe to time.> , then all the bellow subjects are valid:

time.us
time.us.east
time.us.east.local

So you see the symbol > matches one or more tokens.

Having a schema for your subjects is a best practice and you feel it in large systems when you have dozens of subjects. It also helps you organize your subjects and make smarter subjects based on your needs.

Documentation: subject-based messaging

2. Publish-Subscribe Pattern

Publish/Subscribe messaging is a simple one-to-many or 1:n communication implemented by NATS in the core. You publish a message to a subject and one or more listener will receive the message in the same time.

one to many relation

The point here is you donā€™t have to wait for receiver(s) to process or acknowledge message(s) so there is no guarantee of delivery and messages are not going to be kept even if there is no receiver.

ā€œMaximum size of each message is 1MB by default but you can change it to 64MBĀ at least. NATS recommends to keep the size up to 8MB.ā€

Documentation: Publish-Subscribe Messaging

3. Queuing Group

When you fan-out messages between multiple listeners, so client A is going to receive the same messages as client B is receiving. But sometimes the cost of processing one message is expensive but how is it possible to distribute the traffic between multiple consumers?

NATS has a built-in mechanism to solve this problem by using queuing groups. When Subscribers are registered with the same queue name, NATS is going to distribute messages among them.

Load balancer

So two clients are not going to process a same message any more!

Fortunately NATS gives this feature without any extra configuration and its awesome.

Documentation: Queuing group

4. Request-Reply Pattern

Publish/Subscribe is not useful forever specially when you need a response for your published messages. If you be familiar with HTTP protocol, you have a simple logic ā€” make a request and wait for the response.

NATS supports request/reply messaging in the core using publish and subscribe behind the hood.

Request/Reply

The logic is quite a lot similar with RPC in RabbitMQ:

  • client publishes a message with a unique reply subject (an extra field in the message).
  • server then processes the request and publishes the response to the reply subject.

When you request to a subject that has no subscriber, NATS will immediately reply with 503 status code.

Documentation: Request-Reply

5. JetStream

Have you thought about persisting crucial messages to ensure that all the published messages are going to consume? In scenarios when no subscriber exists for a subject, NATS will drop (forget) published messages. So we need something more reliable like JetStreamšŸ¤“.

JetStream is a built-in persistence system that enables a higher quality of service (comparing to pub/sub mechanism) and supports horizontal scaling as well. JetStream in contrast with a simple Pub/Sub messaging is going to save data somewhere to be able to consume them later.

šŸ”øConsumer

When you iterate on an array of items, you usually have a pointer to track your current position and after each iteration you go to the next item with help of that pointer.

Actually consumers are some pointers that are responsible to track your current position so whenever the client disconnects or fails to process, the consumer knows where to start consuming.

How to tell a consumer to go forward? After successful processing, you should send a confirmation (acknowledgement) to tell the consumer to go to the next message. If you fail to confirm a message (for example app crashes) consumer is going to redeliver the message again.

Acknowledgment can be achieved through various methods. You have the option to either individually acknowledge each message or instruct the NATS server to consider the message acknowledged upon delivery. Additionally, acknowledging a series of messages is also possible.

Ultimately, NATS hosts two types of consumers: Durable and Ephemeral. The distinction lies in their behavior; an Ephemeral consumer, for instance, is automatically cleaned up by NATS when no subscriptions are bound to it.

šŸ”øLimitations

A set of limitations are provided by JetStream that are really useful because you probably donā€™t want to keep growing your stream forever!

  • Maximum message age
  • Maximum message size (in bytes)
  • Maximum stream size (in bytes)
  • Maximum number of messages in a stream
  • Maximum consumers

šŸ”øDiscard policy

What will happen when for example maximum number of messages reaches the limit? Discard policy is about this question and the answer is you have two options:

  • Discard old messages
  • Reject new messages

Discard old messages is the default behavior and you can change it depending on your case.

šŸ”øRetention Policy

After consuming a message, nothing happens by default but you can change the behavior.

Limits policy is the default behavior and is based on limitations so messages are going to be kept till a limit is hit. At this point respective message(s) will delete or the request will reject (based on the discard policy youā€™ve set).

Interest policy is based on the interest of consumers! This policy will automatically delete the messages that are consumed by all the consumers.

WrokQueue policy makes your stream just like a FIFO queue. Messages will be deleted after once consumed. Obviously only one consumer is allowed to be created for this type of streams.

ā€œNote that when retention policy is set to Interest , messages will be deleted immediately when the stream has no consumer.ā€

šŸ”øStorage

Because JetStream provides a persistent layer you might think about where NATS is going to store data? Well you can either set Memory or File as the storage and depending on your needs both of them has their own benefits.

ā€œPlease note that when you choose Memory as the storage, whenever NATS server restarts or crashes for some reason, data will be lost as well.ā€

Documentation: JetStream

Conclusion

I think we walked through all the important things about messaging and Iā€™m going to leave you alone with this powerful messaging system šŸ™ƒ. The decision is by yourself whether NATS is suit for your system or not. But let me be honest; Nothing is supposed to be perfectā€¦

Thanks to read my article! šŸ™‚

Resources:

Official NATS Documentation

--

--

Nolan
Nolan

Written by Nolan

0 Followers

Let me drink my coffee first! ā˜•šŸ˜Ž