You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|`AllowDirect` disabled. |`$JS.API.STREAM.MSG.GET.<stream>`| An API meant only for management outside of the hot path. The request goes to every server, but is normally only answered by the stream leader. | Current highest level of read consistency. Only the stream leader answers, but stale reads are technically possible after leader changes or during network partitions since an old leader could still answer before the current leader does. |
62
-
|`AllowDirect` enabled. |`$JS.API.DIRECT.GET.<stream>`| If the stream is replicated, the followers will also answer read requests. | Higher availability read responses but with lower consistency. A read request will be randomly served by a server hosting the stream. Recently written data is not guaranteed to be returned on a subsequent read request. |
63
-
|`MirrorDirect` enabled on mirror stream. |`$JS.API.DIRECT.GET.<stream>`| If the stream is mirrored, the mirror can also answer read requests. For example a mirror stream in a different cluster or on a leaf node. | Higher availability with potential of fast local read responses but with lowest consistency. Mirrors can be in any relative state to the source. |
60
+
| Stream configuration | JetStream API | Description | Level of consistency |
|`AllowDirect` disabled. |`$JS.API.STREAM.MSG.GET.<stream>`| An API meant only for management outside of the hot path. The request goes to every server, but is normally only answered by the stream leader. | Current highest level of read consistency. Only the stream leader answers, but stale reads are technically possible after leader changes or during network partitions since an old leader could still answer before the current leader does. |
63
+
|`AllowDirect` enabled. |`$JS.API.DIRECT.GET.<stream>`| If the stream is replicated, the followers will also answer read requests. | Higher availability read responses but with lower consistency. A read request will be randomly served by a server hosting the stream. Recently written data is not guaranteed to be returned on a subsequent read request. |
64
+
|`MirrorDirect` enabled on mirror stream. |`$JS.API.DIRECT.GET.<stream>`| If the stream is mirrored, the mirror can also answer read requests. For example a mirror stream in a different cluster or on a leaf node. | Higher availability with potential of fast local read responses but with lowest consistency. Mirrors can be in any relative state to the source. Although mirrors will initially wait with responding to read requests until they're _largely_ up-to-date, they don't offer a way to stop responding to reads if contact with the upstream was lost for a long period.|
64
65
65
66
Additionally, if a stream is replicated and a consumer is created, there is no guarantee that the consumer can
66
67
immediately observe all the written messages at that time. For example, if a R1 consumer is created on a follower not up
@@ -69,10 +70,10 @@ they come in.
69
70
70
71
## Proposal to add linearizability
71
72
72
-
Newer server versions, like for 2.14+, should support more configurability or in general higher levels of consistency as
73
-
opt-in. For example, higher read consistency for consumers can be achieved by having consumer CRUD operations go through
74
-
the stream's Raft log instead of the Meta Raft log, which ensures that a consumer created at time X in the stream log
75
-
can observe all the stream writes up to time X.
73
+
Newer server versionsshould support more configurability or in general higher levels of consistency as opt-in. For
74
+
example, higher read consistency for consumers can be achieved by having consumer CRUD operations go through the
75
+
stream's Raft log instead of the Meta Raft log, which ensures that a consumer created at time X in the stream log can
76
+
observe all the stream writes up to time X.
76
77
77
78
Specifically, higher level consistency for message read requests would roughly require:
78
79
@@ -150,3 +151,96 @@ consider:
150
151
151
152
> etcd ensures linearizability for all other operations by default. Linearizability comes with a cost, however, because linearized requests must go through the Raft consensus process. To obtain lower latencies and higher throughput for read requests, clients can configure a request’s consistency mode to serializable, which may access stale data with respect to quorum, but removes the performance penalty of linearized accesses’ reliance on live consensus.
|`default`| Used when the consistency is not explicitly specified. Used for backward-compatibility, can be used to allow manually specifying `AllowDirect` and `MirrorDirect`. |
175
+
|`weak`| Weak read consistency valuing availability and fast responses over consistency. If the stream is replicated, followers can answer read requests. If the stream is mirrored, mirrors can also answer read requests. |
176
+
|`strong`| Strong read consistency valuing consistency over availability. The stream will guarantee linearizable consistency. If set on a stream that's acting as a mirror, it will guarantee sequential consistency. |
177
+
178
+
The addition of `ReadConsistency` allows for various levels of read consistencies (from weakest to strongest):
179
+
180
+
- Leader/Follower/Mirror reads, high availability with potential of fast local read responses by a mirror with no
181
+
cross-request/session consistency guarantees, weakest consistency: `ReadConsistency: weak` on both the stream and the
182
+
mirror.
183
+
- Leader/Follower reads, high availability with no cross-request/session consistency guarantees: `ReadConsistency: weak`
184
+
with no mirrors.
185
+
- Leader/Mirror reads, higher consistency with potential of fast local read responses by a replicated mirror with
186
+
cross-request/session consistency guarantees (when using a connection to the cluster/server hosting either the stream
187
+
or mirror, but not both). Both the stream and mirror are set to `ReadConsistency: strong`. The stream itself will
188
+
guarantee linearizable consistency as specified below, the mirror will guarantee sequential consistency.
189
+
- Linearizable reads, highest level of consistency: `ReadConsistency: strong` with no mirrors. A read request which is
190
+
only answered by the stream leader if it can guarantee linearizability.
191
+
192
+
A note of caution when using `ReadConsistency: strong` for a mirrored stream; the mirror's consistency level will not be
193
+
linearizable, it will be sequential. This can be a desirable guarantee when mirroring a stream on a local leaf node. The
194
+
difference of consistency will be clear since the leaf node is likely meant to be "loosely" connected to the cluster,
195
+
and the client will be guaranteed to always connect to the leaf node and not the cluster. However, if a mirror is
196
+
created in a cluster part of a super cluster setup, this could be problematic depending on the use case. If clients are
197
+
allowed to reconnect between clusters, this could result in the consistency levels changing between linearizable to
198
+
sequential. For example, if the client was first connected to the cluster containing the stream and then reconnected to
199
+
the cluster containing the mirror. This will depend on how the client is configured and what the desired use case is.
200
+
Please keep this in mind when designing your topology.
201
+
202
+
Additionally, if the `ReadConsistency` setting is set to anything other than `default`, the 'Linearizable reads API'
203
+
specified in the next section will be enabled. This can be used to guarantee linearizable reads even if the stream is
204
+
configured to `ReadConsistency: weak`, as well as guaranteeing linearizable reads if a read would otherwise be served by
205
+
a local mirror.
206
+
207
+
#### Linearizable reads API
208
+
209
+
This linearizable reads API allows location transparent access; it doesn't matter if a client is connected via a leaf
210
+
node and several hops to the stream leader, if it requires linearizable reads, it can use this new API to get this
211
+
guarantee. Additionally, this API is enabled through setting a non-default value for `ReadConsistency`. If enabled, the
212
+
leader will also respond to `$JS.API.DIRECT.GET.<stream>`, not requiring `AllowDirect`. This allows clients to migrate
213
+
away from using the `$JS.API.STREAM.MSG.GET.<stream>` API, since it's primarily meant for management purposes only.
214
+
215
+
- Introduce a new API for linearizable reads: `$JS.API.DIRECT_LEADER.GET.<stream>`.
216
+
- The new API will be similar to `$JS.API.DIRECT.GET.<stream>` but will go to the stream leader only. If it's a
217
+
replicated stream, the read will need to "go through Raft" to ensure linearizability.
218
+
- The new API will be enabled by the `ReadConsistency` setting on the stream. Once enabled, the new API will be active,
219
+
and the leader will also respond to `$JS.API.DIRECT.GET.<stream>`, not requiring `AllowDirect`. This allows clients to
220
+
use the DirectGet API instead of the MsgGet API:
221
+
- If the user specifies requiring linearizable reads:
222
+
- If `ReadConsistency` is NOT set, then the client should return an error that 'linearizable reads are not
223
+
enabled for this stream'.
224
+
- If `ReadConsistency` is set, then the client should use the new `$JS.API.DIRECT_LEADER.GET.<stream>` API.
225
+
- If the client does not know the current value of `ReadConsistency` (since it might not have access to the
226
+
stream info), then the client should use the new `$JS.API.DIRECT_LEADER.GET.<stream>` API anyway. A '503 No
227
+
Responders' error will be returned to the user, which will either mean there's temporarily no leader
228
+
available, or the stream is not configured to allow linearizable reads, but the client can't differentiate
229
+
between these two cases.
230
+
- If `AllowDirect` is set, or if `ReadConsistency` is non-`default`, the client should use
231
+
`$JS.API.DIRECT.GET.<stream>`.
232
+
- If none are specified, the client falls back to the `$JS.API.STREAM.MSG.GET.<stream>` API.
233
+
234
+
This design makes linearizability an opt-in and a conscious choice by a user. The server provides all the tools required
235
+
for various consistency levels. Clients can ease the user experience by offering:
236
+
237
+
- Per-request linearizable read opt-in. For example: `js.GetMsg("my-stream", 1, nats.Linearizable()` and
238
+
`js.GetLastMsg("stream", "subject", nats.Linearizable())`. This allows the user to value availability by default, but
239
+
opt in to linearizable reads for the requests that need it.
240
+
- Per-object linearizable read opt-in. Opt-in to linearizable reads for a specific stream, KV or Object Store. All reads
241
+
to that 'object' will use linearizable read requests by default, without needing the user to specify this on a
0 commit comments