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
NATS_URL="nats://localhost:4222"
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg1-az1
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg1-az2
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg1-az3
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg2-az1
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg2-az2
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg2-az3
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg3-az1
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg3-az2
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg3-az3
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg1-az1-x
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg2-az2-x
}
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
}
jetstream: {
store_dir: /tmp/nats/storage/rg3-az3-x
}
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
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 (NCYRXWEEZTZVL76ACBYAX6GGSFWCKGO7RX6U5EI6CLAJ2YVHDMPSPEPV)
Process Details:
Version: 2.10.1
Git Commit:
Go Version: go1.21.3
Start Time: 2023-10-23 19:31:26
Config Load Time: 2023-10-23 19:31:26
Uptime: 11s
Connection Details:
Auth Required: true
TLS Required: false
Host: 0.0.0.0:4225
Client URLs: 172.29.0.2:4225
172.29.0.2:4226
172.29.0.2:4227
JetStream:
Domain:
Storage Directory: /tmp/nats/storage/rg2-az1/jetstream
Max Memory: 5.8 GiB
Max File: 20 GiB
Active Accounts: 1
Memory In Use: 0 B
File In Use: 0 B
API Requests: 0
API Errors: 0
Always sync writes to disk: false
Write sync Frequency: 2m0s
Limits:
Max Conn: 65,536
Max Subs: 0
Max Payload: 1.0 MiB
TLS Timeout: 2.00s
Write Deadline: 10.00s
Statistics:
CPU Cores: 8 0.50%
Memory: 17 MiB
Connections: 0
Subscriptions: 174
Messages: 145 in 247 out
Bytes: 212 KiB in 324 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 │ Host │ Version │ JS │ Conns │ Subs │ Routes │ GWs │ Mem │ CPU % │ Cores │ Slow │ Uptime │ RTT │
├───────────┼─────────┼──────┼─────────┼─────┼───────┼───────┼────────┼─────┼─────────┼───────┼───────┼──────┼────────┼─────┤
│ rg1-az1 │ rg1 │ 0 │ 2.10.1 │ yes │ 1 │ 184 │ 8 │ 3 │ 17 MiB │ 2 │ 8 │ 0 │ 14.14s │ 1ms │
│ rg1-az1-x │ xr │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 17 MiB │ 0 │ 8 │ 0 │ 15.14s │ 1ms │
│ rg3-az1 │ rg3 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 17 MiB │ 2 │ 8 │ 0 │ 7.10s │ 1ms │
│ rg1-az3 │ rg1 │ 0 │ 2.10.1 │ yes │ 0 │ 184 │ 8 │ 3 │ 17 MiB │ 1 │ 8 │ 0 │ 12.12s │ 1ms │
│ rg1-az2 │ rg1 │ 0 │ 2.10.1 │ yes │ 0 │ 184 │ 8 │ 3 │ 17 MiB │ 2 │ 8 │ 0 │ 13.12s │ 1ms │
│ rg2-az2-x │ xr │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 16 MiB │ 0 │ 8 │ 0 │ 10.11s │ 1ms │
│ rg3-az3-x │ xr │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 15 MiB │ 0 │ 8 │ 0 │ 5.09s │ 1ms │
│ rg2-az1 │ rg2 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 17 MiB │ 0 │ 8 │ 0 │ 11.11s │ 1ms │
│ rg2-az3 │ rg2 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 16 MiB │ 1 │ 8 │ 0 │ 8.10s │ 1ms │
│ rg2-az2 │ rg2 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 16 MiB │ 2 │ 8 │ 0 │ 9.11s │ 2ms │
│ rg3-az2 │ rg3 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 16 MiB │ 1 │ 8 │ 0 │ 6.09s │ 2ms │
│ rg3-az3 │ rg3 │ 0 │ 2.10.1 │ yes │ 0 │ 174 │ 8 │ 3 │ 16 MiB │ 0 │ 8 │ 0 │ 4.08s │ 2ms │
├───────────┼─────────┼──────┼─────────┼─────┼───────┼───────┼────────┼─────┼─────────┼───────┼───────┼──────┼────────┼─────┤
│ │ 4 │ 12 │ │ 12 │ 1 │ 2,118 │ │ │ 198 MIB │ │ │ 0 │ │ │
╰───────────┴─────────┴──────┴─────────┴─────┴───────┴───────┴────────┴─────┴─────────┴───────┴───────┴──────┴────────┴─────╯
╭────────────────────────────────────────────────────────────────────────────╮
│ Cluster Overview │
├─────────┬────────────┬───────────────────┬───────────────────┬─────────────┤
│ Cluster │ Node Count │ Outgoing Gateways │ Incoming Gateways │ Connections │
├─────────┼────────────┼───────────────────┼───────────────────┼─────────────┤
│ xr │ 3 │ 9 │ 9 │ 0 │
│ rg3 │ 3 │ 9 │ 9 │ 0 │
│ rg2 │ 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-az2 │ 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 │
│ 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 │
│ rg2-az2-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 │
├───────────┼─────────┼─────────┼───────────┼──────────┼───────┼────────┼──────┼─────────┼─────────┤
│ │ │ 0 │ 0 │ 0 │ 0 B │ 0 B │ 0 B │ 0 │ 0 │
╰───────────┴─────────┴─────────┴───────────┴──────────┴───────┴────────┴──────┴─────────┴─────────╯
╭─────────────────────────────────────────────────────────────────╮
│ RAFT Meta Group Information │
├───────────┬──────────┬────────┬─────────┬────────┬────────┬─────┤
│ Name │ ID │ Leader │ Current │ Online │ Active │ Lag │
├───────────┼──────────┼────────┼─────────┼────────┼────────┼─────┤
│ rg1-az1 │ 6s4h5MOv │ yes │ true │ true │ 0s │ 0 │
│ rg1-az1-x │ PMcvOJvm │ │ true │ true │ 656ms │ 0 │
│ rg1-az2 │ X8wPeL6S │ │ true │ true │ 656ms │ 0 │
│ rg1-az3 │ FozYtzby │ │ true │ true │ 656ms │ 0 │
│ rg2-az1 │ 8ShHFKtZ │ │ true │ true │ 656ms │ 0 │
│ rg2-az2 │ Kx5WF0Q6 │ │ true │ true │ 656ms │ 0 │
│ rg2-az2-x │ UEoET1zo │ │ true │ true │ 656ms │ 0 │
│ rg2-az3 │ NSUWzTzT │ │ true │ true │ 656ms │ 0 │
│ rg3-az1 │ OEQTh4pP │ │ true │ true │ 656ms │ 0 │
│ rg3-az2 │ LJVb57VO │ │ true │ true │ 656ms │ 0 │
│ rg3-az3 │ uEtIi639 │ │ true │ true │ 655ms │ 0 │
│ rg3-az3-x │ cwYBGolT │ │ true │ true │ 656ms │ 0 │
╰───────────┴──────────┴────────┴─────────┴────────┴────────┴─────╯
Stream EVENTS was created
Information for Stream EVENTS created 2023-10-23 19:31:38
Subjects: events.*
Replicas: 3
Storage: File
Placement Cluster: xr
Options:
Retention: Limits
Acknowledgments: true
Discard Policy: Old
Duplicate Window: 2m0s
Direct Get: true
Allows Msg Delete: true
Allows Purge: true
Allows Rollups: true
Limits:
Maximum Messages: unlimited
Maximum Per Subject: unlimited
Maximum Bytes: unlimited
Maximum Age: unlimited
Maximum Message Size: unlimited
Maximum Consumers: unlimited
Cluster Information:
Name: xr
Leader: rg3-az3-x
Replica: rg1-az1-x, current, seen 753µs ago
Replica: rg2-az2-x, current, seen 1ms ago
State:
Messages: 0
Bytes: 0 B
First Sequence: 0
Last Sequence: 0
Active Consumers: 0
Stream ORDERS was created
Information for Stream ORDERS created 2023-10-23 19:31:38
Subjects: orders.*
Replicas: 3
Storage: File
Placement Cluster: rg2
Options:
Retention: Limits
Acknowledgments: true
Discard Policy: Old
Duplicate Window: 2m0s
Direct Get: true
Allows Msg Delete: true
Allows Purge: true
Allows Rollups: true
Limits:
Maximum Messages: unlimited
Maximum Per Subject: unlimited
Maximum Bytes: unlimited
Maximum Age: unlimited
Maximum Message Size: unlimited
Maximum Consumers: unlimited
Cluster Information:
Name: rg2
Leader: rg2-az1
Replica: rg2-az2, current, seen 448µs ago
Replica: rg2-az3, current, seen 46µs ago
State:
Messages: 0
Bytes: 0 B
First Sequence: 0
Last Sequence: 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 │
╰────────┴─────────┴───────────────┴───────────┴──────────┴───────┴──────┴─────────┴──────────────────────────────────╯