Internet Engineering
Introduction
Fall 2026 ·
Amirkabir University of Technology
@1995parham
foosubject
fooreceive the message
INFO {"server_id":"NCNS32OEKOMMHTBVUYC7QWASFAP3BPEKGZG3QDIYRCBUL23WE3OVVBBO","server_name":"NCNS32OEKOMMHTBVUYC7QWASFAP3BPEKGZG3QDIYRCBUL23WE3OVVBBO","version":"2.1.7","proto":1,"git_commit":"bf0930e","go":"go1.13.10","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":1,"client_ip":"172.17.0.1"}
SUB greetings 1
+OK
PUB greetings 12
Hello World!
+OK
MSG greetings 1 12
Hello World!
A request is a publish with a reply subject: a unique
_INBOX
subject that only the requester listens on. A wildcard audit
subscriber sees both the request and the reply.
Workers that subscribe to help
with the same queue name form a group:
each message goes to one random member of it.
The server will not buffer without limit for a client that does not read: it disconnects it instead.
The server PINGs every client on an interval; a client that stops answering PONG is closed as stale.
| Subject | Matches |
|---|---|
| foo.*.bar | foo.hello.bar ✅, foo.hi.bar ✅ |
| foo.* | foo.hello ✅, foo.hi.bar ❌ |
| foo.> | foo.hello.bar ✅, foo.hi.bar ✅, foo.hello ✅ |
requests, with the
same queue group
telnet localhost 4222
SUB requests workers 5
INFO {"server_id":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","server_name":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","version":"2.1.8","proto":1,"git_commit":"c0b574f","go":"go1.14.8","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":4,"client_ip":"172.22.0.1"}
SUB requests workers 5
+OK
MSG requests 5 6
second
INFO {"server_id":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","server_name":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","version":"2.1.8","proto":1,"git_commit":"c0b574f","go":"go1.14.8","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":5,"client_ip":"172.22.0.1"}
SUB requests workers 55
+OK
MSG requests 55 5
first
INFO {"server_id":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","server_name":"NARXYLU3XEZSFYCFRV5WJ63GQS5WDV3WC4WAKCYDYY2IBGIETWJADZVS","version":"2.1.8","proto":1,"git_commit":"c0b574f","go":"go1.14.8","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":6,"client_ip":"172.22.0.1"}
PUB requests 5
first
+OK
PUB requests 6
second
+OK
Subscribers only receive the messages that are published when they are actively connected to the messaging system (i.e. they do not receive messages that are published while they are not subscribing or not running or disconnected).
However, nowadays a new way to provide this temporal de-coupling has been devised and has become 'mainstream': streaming.
Streams capture and store messages published on one (or more) subject and allow client applications to create subscribers (i.e. JetStream consumers) at any time to replay (or consume) all or some of the messages stored in the stream
JetStream consumers support multiple replay policies.
Practically speaking, streams cannot always just keep growing forever and therefore JetStream supports multiple retention policies as well as the ability to impose size limits on streams.
You can impose the following limits on a stream
What happens once the stream has reached one of its limits and a new message is published.
You choose one per stream; limits is the default.
Regardless of the retention policy selected, the limits (and the discard policy) always apply.
You can choose the durability as well as the resilience of the message store according to your needs.
JetStream uses a NATS optimized Raft consensus algorithm to distribute the persistence service between nats servers in a cluster while maintaining immediate consistency even when servers crash or the network drops messages.
Raft tolerates crash and omission faults. It is not Byzantine fault tolerant — it assumes that a server which does answer, answers honestly.
In JetStream the configuration for storing messages is defined separately from how they are consumed.
Storage is defined in a Stream and consuming messages is defined by multiple Consumers.
A stream's replication factor (R, often referred to as the number Replicas) determines how many places it is stored allowing you to tune to balance risk with resource usage and performance.
A stream that is easily rebuilt or temporary might be memory based with a R=1. A stream you cannot afford to lose should be file based with R=3, which survives losing one server.
| Replicas | Description |
|---|---|
| 1 | Cannot operate during an outage of the server servicing the stream. Highly performant. |
| 2 | No significant benefit at this time. We recommend using Replicas=3 instead. |
| 3 | Can tolerate loss of one server servicing the stream. An ideal balance between risk and performance. |
| 4 | No significant benefit over Replicas=3 except marginally in a 5 node cluster. |
| 5 | Can tolerate simultaneous loss of two servers servicing the stream. Mitigates risk at the expense of performance. |
JetStream also allows server administrators to easily mirror streams, for example between different JetStream domains in order to offer disaster recovery.
You can also define a stream as one of the sources for another stream.
JetStream provides de-coupled flow control over streams, the flow control is not 'end to end' where the publisher(s) are limited to publish no faster than the slowest of all the consumers (i.e. the lowest common denominator) can receive, but is instead happening individually between each client application (publishers or consumers) and the nats server.
Because publications to streams using the JetStream publish calls are acknowledged by the server, the base quality of service offered by streams is at least once.
Meaning that while reliable and normally duplicate free there are some specific failure scenarios:
Therefore, JetStream also offers exactly once semantics.
A consumer is a view on a stream, with its own position in it.
Client applications can choose to use fast un-acknowledged push (ordered) consumers to receive messages as fast as possible (for the selected replay policy) on a specific delivery subject or to an inbox.
Client applications can also use and share pull consumers that are demand-driven, support batching and must explicitly acknowledge message reception and processing which means that they can be used to consume (i.e. use the stream as a distributed queue) as well as process the messages in a stream.
Pull consumers can and are meant to be shared between applications (just like queue groups) in order to provide easy and transparent horizontal scalability of the processing or consumption of messages in a stream without having (for example) to worry about having to define partitions or worry about fault-tolerance.
