Regional and Cross Region Streams (Supercluster) in Use Cases
This example demonstrates the configuration required to setup a three regional clusters and a cross-region cluster that form a supercluster.
The use case is for streams that are resilient to regional failures by having replicas spread out across three different regions. This of course comes at a cost of latency, but this trade-off may be appropriate for streams that are critical for availability, but can tolerate slightly higher latencies.
$ nbe run use-cases/cross-region-streams-supercluster/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 > regional-shared.conf
jetstream: {
unique_tag: "az:"
}
accounts: {
'\$SYS': {
users: [{user: sys, password: sys}]
}
APP: {
jetstream: true
users: [{user: user, password: user}]
}
}
EOF
The cross-region cluster defines a unique_tag on the cluster. Any AZ can be chosen as long as the region is unique.
cat <<- EOF > cross-region-shared.conf
jetstream: {
unique_tag: "rg:"
}
accounts: {
'\$SYS': {
users: [{user: sys, password: sys}]
}
APP: {
jetstream: true
users: [{user: user, password: user}]
}
}
EOF
cat <<- EOF > gateway-routes.conf
gateways: [
{name: rg1, urls: [
nats://localhost:7222,
nats://localhost:7223,
nats://localhost:7224,
]},
{name: rg2, urls: [
nats://localhost:7225,
nats://localhost:7226,
nats://localhost:7227,
]},
{name: rg3, urls: [
nats://localhost:7228,
nats://localhost:7229,
nats://localhost:7230,
]},
{name: xr, urls: [
nats://localhost:7231,
nats://localhost:7232,
nats://localhost:7233,
]},
]
EOF
Define the server configs for region 1 cluster.
cat <<- EOF > "rg1-az1.conf"
server_name: rg1-az1
server_tags: [az:1]
port: 4222
http_port: 8222
include regional-shared.conf
cluster: {
name: rg1
port: 6222
routes: [
nats-route://127.0.0.1:6222,
nats-route://127.0.0.1:6223,
nats-route://127.0.0.1:6224,
]
}
gateway {
name: rg1
port: 7222
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg1-az2.conf"
server_name: rg1-az2
server_tags: [az:2]
port: 4223
include regional-shared.conf
cluster: {
name: rg1
port: 6223
routes: [
nats-route://127.0.0.1:6222,
nats-route://127.0.0.1:6223,
nats-route://127.0.0.1:6224,
]
}
gateway {
name: rg1
port: 7223
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg1-az3.conf"
server_name: rg1-az3
server_tags: [az:3]
port: 4224
include regional-shared.conf
cluster: {
name: rg1
port: 6224
routes: [
nats-route://127.0.0.1:6222,
nats-route://127.0.0.1:6223,
nats-route://127.0.0.1:6224,
]
}
gateway {
name: rg1
port: 7224
include gateway-routes.conf
}
EOF
Server configs for region 2 cluster.
cat <<- EOF > "rg2-az1.conf"
server_name: rg2-az1
server_tags: [az:1]
port: 4225
http_port: 8223
include regional-shared.conf
cluster: {
name: rg2
port: 6225
routes: [
nats-route://127.0.0.1:6225,
nats-route://127.0.0.1:6226,
nats-route://127.0.0.1:6227,
]
}
gateway {
name: rg2
port: 7225
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg2-az2.conf"
server_name: rg2-az2
server_tags: [az:2]
port: 4226
include regional-shared.conf
cluster: {
name: rg2
port: 6226
routes: [
nats-route://127.0.0.1:6225,
nats-route://127.0.0.1:6226,
nats-route://127.0.0.1:6227,
]
}
gateway {
name: rg2
port: 7226
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg2-az3.conf"
server_name: rg2-az3
server_tags: [az:3]
port: 4227
include regional-shared.conf
cluster: {
name: rg2
port: 6227
routes: [
nats-route://127.0.0.1:6225,
nats-route://127.0.0.1:6226,
nats-route://127.0.0.1:6227,
]
}
gateway {
name: rg2
port: 7227
include gateway-routes.conf
}
EOF
Server configs for region 3 cluster.
cat <<- EOF > "rg3-az1.conf"
server_name: rg3-az1
server_tags: [az:1]
port: 4228
http_port: 8224
include regional-shared.conf
cluster: {
name: rg3
port: 6228
routes: [
nats-route://127.0.0.1:6228,
nats-route://127.0.0.1:6229,
nats-route://127.0.0.1:6230,
]
}
gateway {
name: rg3
port: 7228
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg3-az2.conf"
server_name: rg3-az2
server_tags: [az:2]
port: 4229
include regional-shared.conf
cluster: {
name: rg3
port: 6229
routes: [
nats-route://127.0.0.1:6228,
nats-route://127.0.0.1:6229,
nats-route://127.0.0.1:6230,
]
}
gateway {
name: rg3
port: 7229
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg3-az3.conf"
server_name: rg3-az3
server_tags: [az:3]
port: 4230
include regional-shared.conf
cluster: {
name: rg3
port: 6230
routes: [
nats-route://127.0.0.1:6228,
nats-route://127.0.0.1:6229,
nats-route://127.0.0.1:6230,
]
}
gateway {
name: rg3
port: 7230
include gateway-routes.conf
}
EOF
Server configs for cross-region cluster. In this case, an arbitrary AZ is chosen per region. If may be desirable to have a six or nine node cross-region cluster if more AZs per region are desired.
cat <<- EOF > "rg1-az1-x.conf"
server_name: rg1-az1-x
server_tags: [rg:1, az:1]
port: 4231
http_port: 8225
include cross-region-shared.conf
cluster: {
name: xr
port: 6231
routes: [
nats-route://127.0.0.1:6231,
nats-route://127.0.0.1:6232,
nats-route://127.0.0.1:6233,
]
}
gateway {
name: xr
port: 7231
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg2-az2-x.conf"
server_name: rg2-az2-x
server_tags: [rg:2, az:2]
port: 4232
include cross-region-shared.conf
cluster: {
name: xr
port: 6232
routes: [
nats-route://127.0.0.1:6231,
nats-route://127.0.0.1:6232,
nats-route://127.0.0.1:6233,
]
}
gateway {
name: xr
port: 7232
include gateway-routes.conf
}
EOF
cat <<- EOF > "rg3-az3-x.conf"
server_name: rg3-az3-x
server_tags: [rg:3, az:3]
port: 4233
include cross-region-shared.conf
cluster: {
name: xr
port: 6233
routes: [
nats-route://127.0.0.1:6231,
nats-route://127.0.0.1:6232,
nats-route://127.0.0.1:6233,
]
}
gateway {
name: xr
port: 7233
include gateway-routes.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 -l "${c%.*}.log" > /dev/null 2>&1 &
sleep 1
done
Wait until the servers up and healthy.
echo 'Cluster 1 healthy?'
curl --fail --silent \
--retry 5 \
--retry-delay 1 \
http://localhost:8222/healthz; echo
echo 'Cluster 2 healthy?'
curl --fail --silent \
--retry 5 \
--retry-delay 1 \
http://localhost:8223/healthz; echo
echo 'Cluster 3 healthy?'
curl --fail --silent \
--retry 5 \
--retry-delay 1 \
http://localhost:8224/healthz; echo
echo 'Cluster 4 healthy?'
curl --fail --silent \
--retry 5 \
--retry-delay 1 \
http://localhost:8225/healthz; echo
Show the server lit and JetStream report.
nats --user sys --password sys server info rg2-az1
nats --user sys --password sys server list
nats --user sys --password sys server report jetstream
Create a cross-region stream specifying the xr
cluster.
nats --user user --password user stream add \
--cluster=xr \
--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 specifying one of the regional clusters, e.g.
rg2
.
nats --user user --password user stream add \
--cluster=rg2 \
--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 75dd2e22_default Creating Network 75dd2e22_default Created Starting server rg1-az1-x Starting server rg1-az1 Starting server rg1-az2 Starting server rg1-az3 Starting server rg2-az1 Starting server rg2-az2-x Starting server rg2-az2 Starting server rg2-az3 Starting server rg3-az1 Starting server rg3-az2 Starting server rg3-az3-x Starting server rg3-az3 Cluster 1 healthy? {"status":"ok"} Cluster 2 healthy? {"status":"ok"} Cluster 3 healthy? {"status":"ok"} Cluster 4 healthy? {"status":"ok"} Server information for rg2-az1 (NAK5EJMZ7JWSZV22HSITOTGMIZOL6JW47RIDPUX2XTJMSFP3YSN7E7DG) Process Details: Version: 2.9.0-RC.11 Git Commit: 97bba60b Go Version: go1.19 Start Time: 2022-08-29 14:50:32.236121629 +0000 UTC Uptime: 10s Connection Details: Auth Required: true TLS Required: false Host: 0.0.0.0:4225 Client URLs: 172.20.0.2:4225 172.20.0.2:4226 172.20.0.2:4227 JetStream: Domain: Storage Directory: /tmp/nats/jetstream Max Memory: 23 GiB Max File: 258 GiB Active Acconts: 1 Memory In Use: 0 B File In Use: 0 B API Requests: 0 API Errors: 0 Limits: Max Conn: 65536 Max Subs: 0 Max Payload: 1.0 MiB TLS Timeout: 2s Write Deadline: 10s Statistics: CPU Cores: 8 0.00% Memory: 16 MiB Connections: 0 Subscriptions: 144 Msgs: 155 in 203 out Bytes: 150 KiB in 175 KiB out Slow Consumers: 0 Cluster: Name: rg2 Tags: az:1 Host: 0.0.0.0:6225 URLs: 127.0.0.1:6225 127.0.0.1:6226 127.0.0.1:6227 Super Cluster: Name: rg2 Host: 0.0.0.0:7225 Clusters: rg1 rg2 rg3 xr ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Server Overview │ ├───────────┬────────────┬────────────┬─────────────┬─────┬───────┬───────┬────────┬─────┬─────────┬─────┬──────┬────────┬─────┤ │ Name │ Cluster │ IP │ Version │ JS │ Conns │ Subs │ Routes │ GWs │ Mem │ CPU │ Slow │ Uptime │ RTT │ ├───────────┼────────────┼────────────┼─────────────┼─────┼───────┼───────┼────────┼─────┼─────────┼─────┼──────┼────────┼─────┤ │ rg1-az1 │ rg1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 1 │ 154 │ 2 │ 3 │ 17 MiB │ 2.0 │ 0 │ 13.13s │ 1ms │ │ rg1-az2 │ rg1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 154 │ 2 │ 3 │ 17 MiB │ 1.0 │ 0 │ 12.12s │ 1ms │ │ rg1-az1-x │ xr │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 16 MiB │ 0.0 │ 0 │ 14.11s │ 1ms │ │ rg1-az3 │ rg1 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 154 │ 2 │ 3 │ 16 MiB │ 1.0 │ 0 │ 11.12s │ 1ms │ │ rg3-az3-x │ xr │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 17 MiB │ 0.0 │ 0 │ 4.11s │ 1ms │ │ rg2-az3 │ rg2 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 16 MiB │ 1.0 │ 0 │ 7.12s │ 1ms │ │ rg2-az1 │ rg2 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 16 MiB │ 0.0 │ 0 │ 10.12s │ 1ms │ │ rg3-az1 │ rg3 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 15 MiB │ 0.0 │ 0 │ 6.11s │ 1ms │ │ rg3-az3 │ rg3 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 16 MiB │ 0.0 │ 0 │ 3.11s │ 1ms │ │ rg2-az2-x │ xr │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 17 MiB │ 1.0 │ 0 │ 9.12s │ 1ms │ │ rg2-az2 │ rg2 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 17 MiB │ 0.0 │ 0 │ 8.12s │ 1ms │ │ rg3-az2 │ rg3 │ 0.0.0.0 │ 2.9.0-RC.11 │ yes │ 0 │ 144 │ 2 │ 3 │ 15 MiB │ 0.0 │ 0 │ 5.12s │ 1ms │ ├───────────┼────────────┼────────────┼─────────────┼─────┼───────┼───────┼────────┼─────┼─────────┼─────┼──────┼────────┼─────┤ │ │ 4 Clusters │ 12 Servers │ │ 12 │ 1 │ 1,758 │ │ │ 195 MiB │ │ 0 │ │ │ ╰───────────┴────────────┴────────────┴─────────────┴─────┴───────┴───────┴────────┴─────┴─────────┴─────┴──────┴────────┴─────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │ Cluster Overview │ ├─────────┬────────────┬───────────────────┬───────────────────┬─────────────┤ │ Cluster │ Node Count │ Outgoing Gateways │ Incoming Gateways │ Connections │ ├─────────┼────────────┼───────────────────┼───────────────────┼─────────────┤ │ xr │ 3 │ 9 │ 9 │ 0 │ │ rg2 │ 3 │ 9 │ 9 │ 0 │ │ rg3 │ 3 │ 9 │ 9 │ 0 │ │ rg1 │ 3 │ 9 │ 9 │ 1 │ ├─────────┼────────────┼───────────────────┼───────────────────┼─────────────┤ │ │ 12 │ 36 │ 36 │ 1 │ ╰─────────┴────────────┴───────────────────┴───────────────────┴─────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ JetStream Summary │ ├───────────┬─────────┬─────────┬───────────┬──────────┬───────┬────────┬──────┬─────────┬─────────┤ │ Server │ Cluster │ Streams │ Consumers │ Messages │ Bytes │ Memory │ File │ API Req │ API Err │ ├───────────┼─────────┼─────────┼───────────┼──────────┼───────┼────────┼──────┼─────────┼─────────┤ │ rg1-az1* │ rg1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg1-az3 │ rg1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg1-az2 │ rg1 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az1 │ rg2 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az2 │ rg2 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az3 │ rg2 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az1 │ rg3 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az2 │ rg3 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az3 │ rg3 │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg1-az1-x │ xr │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg3-az3-x │ xr │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │ │ rg2-az2-x │ xr │ 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-az1-x │ │ true │ true │ 0.58s │ 0 │ │ rg1-az2 │ │ true │ true │ 0.58s │ 0 │ │ rg1-az3 │ │ true │ true │ 0.58s │ 0 │ │ rg2-az1 │ │ true │ true │ 0.58s │ 0 │ │ rg2-az2 │ │ true │ true │ 0.58s │ 0 │ │ rg2-az2-x │ │ true │ true │ 0.58s │ 0 │ │ rg2-az3 │ │ true │ true │ 0.58s │ 0 │ │ rg3-az1 │ │ true │ true │ 0.58s │ 0 │ │ rg3-az2 │ │ true │ true │ 0.58s │ 0 │ │ rg3-az3 │ │ true │ true │ 0.58s │ 0 │ │ rg3-az3-x │ │ true │ true │ 0.58s │ 0 │ ╰───────────┴────────┴─────────┴────────┴────────┴─────╯ Stream EVENTS was created Information for Stream EVENTS created 2022-08-29T14:50:43Z 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 Cluster: xr Cluster Information: Name: xr Leader: rg3-az3-x Replica: rg1-az1-x, current, seen 0.00s ago Replica: rg2-az2-x, 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-29T14:50:43Z 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 Cluster: rg2 Cluster Information: Name: rg2 Leader: rg2-az3 Replica: rg2-az1, current, seen 0.00s ago Replica: rg2-az2, outdated, seen 0.00s ago, 1 operation behind 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 │ cluster: xr │ 0 │ 0 │ 0 B │ 0 │ 0 │ rg1-az1-x, rg2-az2-x, rg3-az3-x* │ │ ORDERS │ File │ cluster: rg2 │ 0 │ 0 │ 0 B │ 0 │ 0 │ rg2-az1, rg2-az2, rg2-az3* │ ╰────────┴─────────┴───────────────┴───────────┴──────────┴───────┴──────┴─────────┴──────────────────────────────────╯