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* │
╰────────┴─────────┴───────────────┴───────────┴──────────┴───────┴──────┴─────────┴──────────────────────────────────╯