Regional and Cross Region Streams (Cluster) in Use Cases
This example shows and alternative to the [supercluster][1] version. Rather than a supercluster, this relies on a nine node cluster spread out across three regions and three availability zones each.
$ nbe run use-cases/cross-region-streams-cluster/cliView the source code or learn how to run this example yourself
Code
#!/bin/bash
set -euo pipefail
Create a shared configuration which enables JetStream and defines the
unique_tag
option which enforces all replicas for a given stream or
consumer to be placed on nodes with different availability zones (AZ).
cat <<- EOF > shared.conf
jetstream: {
unique_tag: "az:"
}
accounts: {
'\$SYS': {
users: [{user: sys, password: sys}]
}
APP: {
jetstream: true
users: [{user: user, password: user}]
}
}
EOF
Create the shared clustered config defining the seed routes.
cat <<- EOF > cluster.conf
name: c1
routes: [
nats-route://127.0.0.1:6222,
nats-route://127.0.0.1:6223,
nats-route://127.0.0.1:6224,
]
EOF
Define nine server configurations modeling a cluster with three nodes
in each region across three AZs. NATS does not currently support
declaring tags with logical OR (or exclusive OR), so valid combinations
can be precomputed as tags and then used when creating streams. In this
case, the xr:
tag encodes the cluster/AZ combination while still adhering
to the unique_tag
requirement.
Each index corresponds to a region (e.g us-east) and the value at the
index corresponds to an AZ, e.g. us-east4.
Thus a tag xr:231
can be read as a cross-region stream where one replica
is placed in region 1 in AZ 2, another in region 2 in AZ 3, and the third
replica in region 3 in AZ 1.
In addition to the xr:
tags, the standard rg:
(region) and az:
(AZ)
tags are set to support regional streams which is demonstrated below.
cat <<- EOF > "rg1-az1.conf"
server_name: rg1-az1
server_tags: [rg:1, az:1, xr:123, xr:132]
port: 4222
http_port: 8222
include shared.conf
cluster: {
port: 6222
include cluster.conf
}
EOF
cat <<- EOF > "rg1-az2.conf"
server_name: rg1-az2
server_tags: [rg:1, az:2, xr:213, xr:231]
port: 4223
include shared.conf
cluster: {
port: 6223
include cluster.conf
}
EOF
cat <<- EOF > "rg1-az3.conf"
server_name: rg1-az3
server_tags: [rg:1, az:3, xr:312, xr:321]
port: 4224
include shared.conf
cluster: {
port: 6224
include cluster.conf
}
EOF
cat <<- EOF > "rg2-az1.conf"
server_name: rg2-az1
server_tags: [rg:2, az:1, xr:213, xr:312]
port: 4225
include shared.conf
cluster: {
port: 6225
include cluster.conf
}
EOF
cat <<- EOF > "rg2-az2.conf"
server_name: rg2-az2
server_tags: [rg:2, az:2, xr:123, xr:321]
port: 4226
include shared.conf
cluster: {
port: 6226
include cluster.conf
}
EOF
cat <<- EOF > "rg2-az3.conf"
server_name: rg2-az3
server_tags: [rg:2, az:3, xr:132, xr:231]
port: 4227
include shared.conf
cluster: {
port: 6227
include cluster.conf
}
EOF
cat <<- EOF > "rg3-az1.conf"
server_name: rg3-az1
server_tags: [rg:3, az:1, xr:231, xr:321]
port: 4228
include shared.conf
cluster: {
port: 6228
include cluster.conf
}
EOF
cat <<- EOF > "rg3-az2.conf"
server_name: rg3-az2
server_tags: [rg:3, az:2, xr:132, xr:312]
port: 4229
include shared.conf
cluster: {
port: 6229
include cluster.conf
}
EOF
cat <<- EOF > "rg3-az3.conf"
server_name: rg3-az3
server_tags: [rg:3, az:3, xr:123, xr:213]
port: 4230
include shared.conf
cluster: {
port: 6230
include cluster.conf
}
EOF
Start a server for each configuration and sleep a second in between so the seeds can startup and get healthy.
for c in $(ls rg*.conf); do
echo "Starting server ${c%.*}"
nats-server -c $c > /dev/null 2>&1 &
sleep 1
done
Wait until the servers up and healthy.
echo 'Healthy?'
curl --fail --silent \
--retry 5 \
--retry-delay 1 \
http://localhost:8222/healthz; echo
Show the server lit and JetStream report.
nats --user sys --password sys server list
nats --user sys --password sys server report jetstream
Create a cross-region stream using one of the pre-defined xr:
tags.
nats --user user --password user stream add \
--tag=xr:123 \
--retention=limits \
--storage=file \
--replicas=3 \
--discard=old \
--dupe-window=2m \
--max-age=-1 \
--max-msgs=-1 \
--max-bytes=-1 \
--max-msg-size=-1 \
--max-msgs-per-subject=-1 \
--max-consumers=-1 \
--allow-rollup \
--no-deny-delete \
--no-deny-purge \
--subjects="events.*" \
EVENTS
Create a regional stream which relies on the unique_tag
to ensure
each replicas in a different AZ. This will create a stream in region 2
due to the rg:2
tag
nats --user user --password user stream add \
--tag=rg:2 \
--retention=limits \
--storage=file \
--replicas=3 \
--discard=old \
--dupe-window=2m \
--max-age=-1 \
--max-msgs=-1 \
--max-bytes=-1 \
--max-msg-size=-1 \
--max-msgs-per-subject=-1 \
--max-consumers=-1 \
--allow-rollup \
--no-deny-delete \
--no-deny-purge \
--subjects="orders.*" \
ORDERS
Report out the streams.
nats --user user --password user stream report
Output
Network 1d3d8cca_default Creating Network 1d3d8cca_default Created Starting server rg1-az1 Starting server rg1-az2 Starting server rg1-az3 Starting server rg2-az1 Starting server rg2-az2 Starting server rg2-az3 Starting server rg3-az1 Starting server rg3-az2 Starting server rg3-az3 Healthy? {"status":"ok"} ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Server Overview │ ├─────────┬────────────┬───────────┬─────────────┬─────┬───────┬───────┬────────┬─────┬─────────┬─────┬──────┬────────┬─────┤ │ Name │ Cluster │ IP │ Version │ JS │ Conns │ Subs │ Routes │ GWs │ Mem │ CPU │ Slow │ Uptime │ RTT │ ├─────────┼────────────┼───────────┼─────────────┼─────┼───────┼───────┼────────┼─────┼─────────┼─────┼──────┼────────┼─────┤ │ rg1-az1 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 1 │ 424 │ 8 │ 0 │ 15 MiB │ 0.0 │ 0 │ 9.07s │ 6ms │ │ rg3-az3 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 14 MiB │ 2.0 │ 0 │ 1.06s │ 7ms │ │ rg2-az1 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 14 MiB │ 2.0 │ 0 │ 6.07s │ 7ms │ │ rg2-az2 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 12 MiB │ 0.0 │ 0 │ 5.07s │ 7ms │ │ rg1-az2 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 11 MiB │ 1.0 │ 0 │ 8.07s │ 7ms │ │ rg1-az3 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 14 MiB │ 2.0 │ 0 │ 7.07s │ 7ms │ │ rg2-az3 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 15 MiB │ 0.0 │ 0 │ 4.07s │ 7ms │ │ rg3-az2 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 12 MiB │ 1.0 │ 0 │ 2.06s │ 8ms │ │ rg3-az1 │ c1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 424 │ 8 │ 0 │ 12 MiB │ 1.0 │ 0 │ 3.06s │ 8ms │ ├─────────┼────────────┼───────────┼─────────────┼─────┼───────┼───────┼────────┼─────┼─────────┼─────┼──────┼────────┼─────┤ │ │ 1 Clusters │ 9 Servers │ │ 9 │ 1 │ 3,816 │ │ │ 121 MiB │ │ 0 │ │ │ ╰─────────┴────────────┴───────────┴─────────────┴─────┴───────┴───────┴────────┴─────┴─────────┴─────┴──────┴────────┴─────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │ Cluster Overview │ ├─────────┬────────────┬───────────────────┬───────────────────┬─────────────┤ │ Cluster │ Node Count │ Outgoing Gateways │ Incoming Gateways │ Connections │ ├─────────┼────────────┼───────────────────┼───────────────────┼─────────────┤ │ c1 │ 9 │ 0 │ 0 │ 1 │ ├─────────┼────────────┼───────────────────┼───────────────────┼─────────────┤ │ │ 9 │ 0 │ 0 │ 1 │ ╰─────────┴────────────┴───────────────────┴───────────────────┴─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │ JetStream Summary │ ├──────────┬─────────┬─────────┬───────────┬──────────┬───────┬────────┬──────┬─────────┬─────────┤ │ Server │ Cluster │ Streams │ Consumers │ Messages │ Bytes │ Memory │ File │ API Req │ API Err │ ├──────────┼─────────┼─────────┼───────────┼──────────┼───────┼────────┼──────┼─────────┼─────────┤ │ rg1-az1* │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az2 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az1 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az2 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az3 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az1 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az3 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg1-az3 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg1-az2 │ c1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ ├──────────┼─────────┼─────────┼───────────┼──────────┼───────┼────────┼──────┼─────────┼─────────┤ │ │ │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ ╰──────────┴─────────┴─────────┴───────────┴──────────┴───────┴────────┴──────┴─────────┴─────────╯ ╭────────────────────────────────────────────────────╮ │ RAFT Meta Group Information │ ├─────────┬────────┬─────────┬────────┬────────┬─────┤ │ Name │ Leader │ Current │ Online │ Active │ Lag │ ├─────────┼────────┼─────────┼────────┼────────┼─────┤ │ rg1-az1 │ yes │ true │ true │ 0.00s │ 0 │ │ rg1-az2 │ │ true │ true │ 0.33s │ 0 │ │ rg1-az3 │ │ true │ true │ 0.33s │ 0 │ │ rg2-az1 │ │ true │ true │ 0.33s │ 0 │ │ rg2-az2 │ │ true │ true │ 0.33s │ 0 │ │ rg2-az3 │ │ true │ true │ 0.33s │ 0 │ │ rg3-az1 │ │ true │ true │ 0.33s │ 0 │ │ rg3-az2 │ │ true │ true │ 0.33s │ 0 │ │ rg3-az3 │ │ true │ true │ 0.33s │ 0 │ ╰─────────┴────────┴─────────┴────────┴────────┴─────╯ Stream EVENTS was created Information for Stream EVENTS created 2022-08-27T09:59:28Z Configuration: Subjects: events.* Acknowledgements: true Retention: File - Limits Replicas: 3 Discard Policy: Old Duplicate Window: 2m0s Allows Msg Delete: true Allows Purge: true Allows Rollups: true Maximum Messages: unlimited Maximum Bytes: unlimited Maximum Age: unlimited Maximum Message Size: unlimited Maximum Consumers: unlimited Placement Tags: xr:123 Cluster Information: Name: c1 Leader: rg1-az1 Replica: rg2-az2, current, seen 0.00s ago Replica: rg3-az3, current, seen 0.00s ago State: Messages: 0 Bytes: 0 B FirstSeq: 0 LastSeq: 0 Active Consumers: 0 Stream ORDERS was created Information for Stream ORDERS created 2022-08-27T09:59:29Z Configuration: Subjects: orders.* Acknowledgements: true Retention: File - Limits Replicas: 3 Discard Policy: Old Duplicate Window: 2m0s Allows Msg Delete: true Allows Purge: true Allows Rollups: true Maximum Messages: unlimited Maximum Bytes: unlimited Maximum Age: unlimited Maximum Message Size: unlimited Maximum Consumers: unlimited Placement Tags: rg:2 Cluster Information: Name: c1 Leader: rg2-az1 Replica: rg2-az2, current, seen 0.00s ago Replica: rg2-az3, current, not seen State: Messages: 0 Bytes: 0 B FirstSeq: 0 LastSeq: 0 Active Consumers: 0 Obtaining Stream stats ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Stream Report │ ├────────┬─────────┬──────────────┬───────────┬──────────┬───────┬──────┬─────────┬────────────────────────────┤ │ Stream │ Storage │ Placement │ Consumers │ Messages │ Bytes │ Lost │ Deleted │ Replicas │ ├────────┼─────────┼──────────────┼───────────┼──────────┼───────┼──────┼─────────┼────────────────────────────┤ │ EVENTS │ File │ tags: xr:123 │ 0 │ 0 │ 0 B │ 0 │ 0 │ rg1-az1*, rg2-az2, rg3-az3 │ │ ORDERS │ File │ tags: rg:2 │ 0 │ 0 │ 0 B │ 0 │ 0 │ rg2-az1*, rg2-az2, rg2-az3 │ ╰────────┴─────────┴──────────────┴───────────┴──────────┴───────┴──────┴─────────┴────────────────────────────╯