Multi-Region Deployment¶
Multi-region deployment allows RockLake to serve catalog queries from multiple geographic regions with low latency. A data team in Frankfurt should not wait 150ms for a round-trip to Virginia every time DuckDB resolves a table name — they should hit a local RockLake instance that responds in 5ms. Because RockLake uses object storage as its durable layer, multi-region deployment leverages your cloud provider's built-in cross-region replication rather than implementing its own replication protocol.
This page covers the architecture of multi-region RockLake deployments, configuration for each cloud provider, replication lag characteristics, failover procedures, and the cost trade-offs of geographic distribution.
Architecture¶
The multi-region pattern is simple: one writer in the primary region, read-only replicas in secondary regions reading from replicated object storage.
flowchart LR
subgraph "Region A (us-east-1)"
W[RockLake Writer]
S3A[(S3 Bucket A)]
W --> S3A
end
subgraph "Region B (eu-west-1)"
R1[RockLake Reader]
S3B[(S3 Bucket B)]
R1 --> S3B
end
subgraph "Region C (ap-southeast-1)"
R2[RockLake Reader]
S3C[(S3 Bucket C)]
R2 --> S3C
end
S3A -->|Cross-Region Replication| S3B
S3A -->|Cross-Region Replication| S3C The flow is unidirectional: writes go to the primary, replication propagates to secondaries, readers in secondaries serve local queries. There is no bidirectional replication, no conflict resolution, no vector clocks. The single-writer model eliminates the entire class of multi-region consistency problems that plague distributed databases.
Why This Works¶
Traditional databases struggle with multi-region because replicating transaction logs across continents introduces latency into the write path. RockLake does not have this problem because:
- Writes are local. The writer commits to its local-region S3 bucket. The write path has zero cross-region latency.
- Replication is asynchronous. Cross-region copy happens in the background, managed by the cloud provider.
- Readers are independent. Each reader opens its own view of the catalog from its local bucket. It does not coordinate with the writer.
- Staleness is bounded. Object storage replication has known latency bounds (seconds to minutes, depending on provider).
Setup: AWS S3 Cross-Region Replication¶
Step 1: Create Destination Bucket¶
Step 2: Enable Versioning (Required for CRR)¶
# Both source and destination need versioning
aws s3api put-bucket-versioning \
--bucket my-lakehouse-us-east-1 \
--versioning-configuration Status=Enabled
aws s3api put-bucket-versioning \
--bucket my-lakehouse-eu-west-1 \
--versioning-configuration Status=Enabled
Step 3: Create Replication IAM Role¶
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetReplicationConfiguration",
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::my-lakehouse-us-east-1"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAcl"
],
"Resource": "arn:aws:s3:::my-lakehouse-us-east-1/catalog/*"
},
{
"Effect": "Allow",
"Action": [
"s3:ReplicateObject",
"s3:ReplicateDelete"
],
"Resource": "arn:aws:s3:::my-lakehouse-eu-west-1/catalog/*"
}
]
}
Step 4: Enable Replication¶
aws s3api put-bucket-replication \
--bucket my-lakehouse-us-east-1 \
--replication-configuration '{
"Role": "arn:aws:iam::123456789012:role/s3-replication-role",
"Rules": [{
"Status": "Enabled",
"Priority": 1,
"Filter": {"Prefix": "catalog/"},
"Destination": {
"Bucket": "arn:aws:s3:::my-lakehouse-eu-west-1",
"Metrics": {"Status": "Enabled", "EventThreshold": {"Minutes": 15}},
"ReplicationTime": {"Status": "Enabled", "Time": {"Minutes": 15}}
},
"DeleteMarkerReplication": {"Status": "Enabled"}
}]
}'
Step 5: Deploy Reader in Secondary Region¶
# In eu-west-1
AWS_REGION=eu-west-1 rocklake \
--catalog s3://my-lakehouse-eu-west-1/catalog/ \
--bind 0.0.0.0:5432 \
--read-only
Setup: Google Cloud Storage¶
GCS offers two approaches for multi-region access:
Option A: Multi-Region Bucket (Simplest)¶
Create the bucket as multi-region from the start:
Multi-region buckets replicate data across regions automatically. Deploy readers in any region within the multi-region class — they read from the nearest replica automatically.
Option B: Dual-Region Bucket¶
For cost control with specific region pairs:
Deploying Readers¶
# Reader in any region (GCS handles routing automatically)
rocklake serve --catalog gs://my-lakehouse/catalog/ --bind 0.0.0.0:5432 --read-only
Setup: Azure Blob Storage¶
Enable Geo-Redundant Storage (GRS)¶
When creating the storage account, choose GRS or RA-GRS (Read-Access GRS):
az storage account create \
--name mylakehouse \
--resource-group rg-analytics \
--location eastus \
--sku Standard_RAGRS
With RA-GRS, the secondary endpoint is readable:
# Primary (read/write)
rocklake serve --catalog az://catalog@mylakehouse/ --bind 0.0.0.0:5432
# Secondary (read-only, use secondary endpoint)
rocklake serve --catalog az://catalog@mylakehouse-secondary/ --bind 0.0.0.0:5432 --read-only
Replication Lag¶
Cross-region replication is asynchronous. The lag determines how stale your readers can be:
| Provider | Mechanism | Typical Lag | SLA |
|---|---|---|---|
| AWS S3 CRR (standard) | Asynchronous | 30s – 5 min | 99.99% within 15 min |
| AWS S3 RTC (Replication Time Control) | Asynchronous with SLA | < 15 min | 99.99% within 15 min |
| GCS Multi-Region | Synchronous-ish | < 1 second | Strongly consistent |
| GCS Dual-Region (turbo) | Synchronous-ish | < 1 second | RPO = 0 (turbo replication) |
| Azure RA-GRS | Asynchronous | < 15 min typical | No firm SLA |
| Azure GZRS | Asynchronous | < 15 min typical | No firm SLA |
What "Lag" Means for RockLake¶
During the replication lag window, readers in secondary regions serve a slightly older catalog snapshot. Concretely:
- A table created 30 seconds ago might not be visible to the EU reader yet
- A schema change committed in us-east-1 takes 30 seconds to propagate to eu-west-1
- Data files referenced by the catalog are typically in a separate bucket (e.g., a data lake bucket) that may have its own replication characteristics
For most analytics workloads, this is invisible:
- Dashboard queries use stable table schemas
- Batch ETL runs once per hour (not every second)
- Ad-hoc analysts are not racing against schema changes
Monitoring Replication Lag¶
# AWS: Check replication metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/S3 \
--metric-name ReplicationLatency \
--dimensions Name=SourceBucket,Value=my-lakehouse-us-east-1 \
--start-time $(date -v-1H +%Y-%m-%dT%H:%M:%S) \
--end-time $(date +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Average
Client Routing¶
Route clients to their nearest RockLake instance for lowest latency.
DNS-Based Routing (AWS Route 53)¶
# Latency-based routing
aws route53 change-resource-record-sets \
--hosted-zone-id Z123456 \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "catalog.example.com",
"Type": "A",
"SetIdentifier": "us-east-1",
"Region": "us-east-1",
"TTL": 60,
"ResourceRecords": [{"Value": "10.0.1.100"}]
}
}, {
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "catalog.example.com",
"Type": "A",
"SetIdentifier": "eu-west-1",
"Region": "eu-west-1",
"TTL": 60,
"ResourceRecords": [{"Value": "10.1.1.100"}]
}
}]
}'
Clients connect to catalog.example.com:5432 and DNS routes them to the nearest region.
Application-Level Routing¶
For more control, route in application configuration:
import os
REGION = os.environ.get("AWS_REGION", "us-east-1")
CATALOG_HOSTS = {
"us-east-1": "rocklake-us.internal:5432",
"eu-west-1": "rocklake-eu.internal:5432",
"ap-southeast-1": "rocklake-ap.internal:5432",
}
catalog_host = CATALOG_HOSTS.get(REGION, CATALOG_HOSTS["us-east-1"])
Write Routing¶
All writes must go to the primary region's writer instance. Options:
- Separate connection strings: Applications use the local reader for queries and the primary writer for DDL/DML.
- Proxy with routing rules: A PgBouncer-like proxy routes SELECT to local reader and DDL/DML to primary writer.
- Fail-forward: If a read-only instance receives a write, it returns a clear error. The client retries against the writer endpoint.
Disaster Recovery¶
If the primary region becomes unavailable (regional outage):
Failover Procedure¶
-
Verify replication state: Check the latest manifest file in the secondary bucket. Compare the latest snapshot ID with what was known in the primary.
-
Promote the reader to writer:
-
Update DNS: Point the writer endpoint to the new primary.
-
Inform applications: Any cached writer connections need to reconnect.
Data Loss Assessment¶
With asynchronous replication, any writes that had not yet replicated are lost. The maximum data loss (RPO - Recovery Point Objective) is:
| Provider | RPO |
|---|---|
| AWS S3 CRR | Up to 15 minutes |
| GCS Multi-Region | ~0 (synchronous) |
| Azure RA-GRS | Up to 15 minutes |
For RockLake catalogs, "lost data" means catalog metadata (table definitions, partition registrations) — not the actual data files in the lake. Data files in the lake are independently replicated and are not affected by RockLake's catalog state.
Failback Procedure¶
When the original primary region recovers:
- Set up replication from the new primary to the recovering region
- Wait for replication to catch up
- Either keep the new topology or failback (reverse the roles)
Cost Considerations¶
Multi-region deployment adds costs:
| Cost Component | Approximate Monthly Cost |
|---|---|
| S3 CRR data transfer (per GB replicated) | $0.02/GB |
| Secondary bucket storage | Same as primary |
| Secondary RockLake instance | Same as primary (small) |
| DNS routing (Route 53) | $0.50/hosted zone + $0.60/million queries |
For a typical RockLake catalog (10–100 MB of metadata), cross-region replication costs are negligible — less than $1/month. The dominant cost is the secondary RockLake instance, which can be as small as a t3.micro ($7/month).
Example: Three-Region Analytics Platform¶
# Primary: us-east-1 (writer + reader)
# Secondary: eu-west-1 (reader)
# Tertiary: ap-southeast-1 (reader)
regions:
us-east-1:
role: primary
instance: rocklake serve --catalog s3://lakehouse-us/catalog/ --bind 0.0.0.0:5432
bucket: lakehouse-us
replicates_to: [lakehouse-eu, lakehouse-ap]
eu-west-1:
role: reader
instance: rocklake serve --catalog s3://lakehouse-eu/catalog/ --bind 0.0.0.0:5432 --read-only
bucket: lakehouse-eu
receives_from: lakehouse-us
ap-southeast-1:
role: reader
instance: rocklake serve --catalog s3://lakehouse-ap/catalog/ --bind 0.0.0.0:5432 --read-only
bucket: lakehouse-ap
receives_from: lakehouse-us
Analytics teams worldwide connect to their local reader. Schema changes and data registration go through the US writer. Replication lag is invisible for normal query workloads.
Further Reading¶
- High Availability — Single-region HA patterns
- Kubernetes — Reader fleet deployment
- Concepts: Single Writer — Why one writer is sufficient
- Networking — Cross-region network configuration