RFC-012: Prism Network Gateway (prism-netgw) - Multi-Region Control Plane
Abstract
This RFC proposes prism-netgw, a distributed control plane for managing collections of Prism data gateway clusters across multiple cloud providers, regions, and on-premises environments. prism-netgw handles cluster registration, configuration synchronization, health monitoring, and cross-region routing while tolerating high latency and network partitions.
Motivation
Problem Statement
Organizations deploying Prism at scale face several challenges:
- Multi-Region Deployments: Prism gateways deployed across AWS, GCP, Azure, and on-prem
- Configuration Management: Keeping namespace configs, backend definitions, and policies synchronized
- Cross-Region Discovery: Applications need to discover nearest Prism gateway
- Health Monitoring: Centralized visibility into all Prism instances
- High Latency Tolerance: Cross-region communication experiences 100-500ms latency
- Network Partitions: Cloud VPCs, on-prem networks may have intermittent connectivity
Goals
- Cluster Management: Register, configure, and monitor Prism gateway clusters
- Configuration Sync: Distribute namespace and backend configs across regions
- Service Discovery: Enable clients to discover nearest healthy Prism gateway
- Health Aggregation: Collect health and metrics from all clusters
- Latency Tolerance: Operate correctly with 100-500ms cross-region latency
- Partition Tolerance: Handle network partitions gracefully
- Multi-Cloud: Support AWS, GCP, Azure, on-prem deployments
Non-Goals
- Not a data plane: prism-netgw does NOT proxy data requests (Prism gateways handle that)
- Not a service mesh: Use dedicated service mesh (Istio, Linkerd) for data plane networking
- Not a config database: Uses etcd/Consul for distributed storage
Architecture
High-Level Design
┌─────────────────────────────────────────────────────────────────┐ │ prism-netgw Control Plane │ │ (Raft consensus, multi-region) │ └─────────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ │ │ │ ┌───────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐ │ AWS Region │ │ GCP Zone │ │ On-Prem DC │ │ us-east-1 │ │ us-cent1 │ │ Seattle │ └──────────────┘ └──────────┘ └─────────────┘ │ │ │ ┌───────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐ │ Prism Cluster│ │ Prism │ │ Prism │ │ (3 nodes) │ │ Cluster │ │ Cluster │ └──────────────┘ └──────────┘ └─────────────┘ │ │ │ ┌───────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐ │ Backends │ │ Backends │ │ Backends │ │ (Postgres, │ │ (Kafka, │ │ (SQLite, │ │ Redis) │ │ NATS) │ │ Postgres) │ └──────────────┘ └──────────┘ └─────────────┘
### Components
graph TB
subgraph "prism-netgw Control Plane"
API[Control Plane API
:9980]
Raft[Raft Consensus
Multi-region]
Store[Distributed Store
etcd/Consul]
Monitor[Health Monitor
Polling]
Sync[Config Sync
Push/Pull]
Discovery[Service Discovery
DNS/gRPC]
end
subgraph "Prism Gateway Cluster (us-east-1)"
Agent1[prism-agent<br/>:9981]
Prism1[Prism Gateway 1]
Prism2[Prism Gateway 2]
Prism3[Prism Gateway 3]
end
subgraph "Prism Gateway Cluster (eu-west-1)"
Agent2[prism-agent<br/>:9981]
Prism4[Prism Gateway 4]
Prism5[Prism Gateway 5]
end
API --> Raft
Raft --> Store
Monitor --> Agent1
Monitor --> Agent2
Sync --> Agent1
Sync --> Agent2
Agent1 --> Prism1
Agent1 --> Prism2
Agent1 --> Prism3
Agent2 --> Prism4
Agent2 --> Prism5
Discovery -.->|Returns nearest| Prism1
Discovery -.->|Returns nearest| Prism4
### Deployment Model
┌─────────────────────────────────────────────────────────────────┐
│ Global Control Plane │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ netgw-leader │───▶│ netgw-node2 │◀──▶│ netgw-node3 │ │
│ │ (us-east-1) │ │ (eu-west-1) │ │ (ap-south-1) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ │ Raft consensus │ │ │
│ └────────────────────┴────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Deployment Options:
- Multi-Region Active-Standby: 1 leader, N followers in different regions
- Multi-Region Active-Active: Raft quorum across regions (requires low latency between control plane nodes)
- Federated: Independent control planes per region, manual config sync
Core Concepts
1. Cluster Registration
Prism gateway clusters register with prism-netgw:
syntax = "proto3";
package prism.netgw.v1;
message RegisterClusterRequest {
string cluster_id = 1; // Unique cluster identifier (e.g., "aws-us-east-1-prod")
string region = 2; // Cloud region (e.g., "us-east-1")
string cloud_provider = 3; // "aws", "gcp", "azure", "on-prem"
string vpc_id = 4; // VPC or network identifier
repeated string endpoints = 5; // gRPC endpoints for Prism gateways
map<string, string> labels = 6; // Arbitrary labels (e.g., "env": "prod")
}
message RegisterClusterResponse {
string cluster_id = 1;
int64 registration_version = 2; // Version for optimistic concurrency
google.protobuf.Timestamp expires_at = 3; // TTL for heartbeat
}
service ControlPlaneService {
rpc RegisterCluster(RegisterClusterRequest) returns (RegisterClusterResponse);
rpc UnregisterCluster(UnregisterClusterRequest) returns (UnregisterClusterResponse);
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
}
2. Configuration Synchronization
Problem: Namespace and backend configs must be consistent across all clusters.
Solution: Version-controlled config distribution with eventual consistency.
message SyncConfigRequest {
string cluster_id = 1;
int64 current_version = 2; // Cluster's current config version
}
message SyncConfigResponse {
int64 latest_version = 1;
repeated NamespaceConfig namespaces = 2;
repeated BackendConfig backends = 3;
repeated Policy policies = 4;
// Incremental updates if current_version is recent
bool is_incremental = 10;
repeated ConfigChange changes = 11; // Only deltas since current_version
}
message ConfigChange {
enum ChangeType {
ADDED = 0;
MODIFIED = 1;
DELETED = 2;
}
ChangeType type = 1;
string resource_type = 2; // "namespace", "backend", "policy"
string resource_id = 3;
bytes resource_data = 4; // Protobuf-encoded resource
}
Push Model (preferred): prism-netgw → Watch(config_version) → prism-agent ← ConfigUpdate stream ←
**Pull Model** (fallback for high latency):
prism-agent → SyncConfig(current_version) → prism-netgw
← SyncConfigResponse ←
3. Health Monitoring
Hierarchical Health Model:
Global Health (prism-netgw) ├── Cluster Health (per region) │ ├── Gateway Health (per Prism instance) │ │ ├── Process Health (alive, responsive) │ │ ├── Backend Health (Postgres, Kafka, etc.) │ │ └── Namespace Health (operational state) │ └── Network Health (connectivity, latency) └── Control Plane Health (netgw nodes)
message ReportHealthRequest { string cluster_id = 1; google.protobuf.Timestamp timestamp = 2;
repeated GatewayHealth gateways = 3; repeated BackendHealth backends = 4; repeated NamespaceHealth namespaces = 5;
NetworkMetrics network = 6; // Latency, packet loss, etc. }
message GatewayHealth { string gateway_id = 1; HealthStatus status = 2; // HEALTHY, DEGRADED, UNHEALTHY int64 active_sessions = 3; int64 requests_per_second = 4; double cpu_percent = 5; double memory_mb = 6; }
message BackendHealth { string backend_type = 1; // "postgres", "kafka", etc. HealthStatus status = 2; double latency_ms = 3; string error_message = 4; }
### 4. Service Discovery
**Goal**: Clients discover nearest healthy Prism gateway.
message DiscoverGatewaysRequest { string namespace = 1; // Filter by namespace support string client_location = 2; // "us-east-1", "eu-west-1", etc. int32 max_results = 3; // Limit number of results }
message DiscoverGatewaysResponse { repeated Gateway gateways = 1; }
message Gateway { string gateway_id = 1; string cluster_id = 2; repeated string endpoints = 3; string region = 4; double latency_ms = 5; // Estimated latency from client_location HealthStatus health = 6; int32 load_score = 7; // 0-100 (lower is better) }
**DNS-based discovery** (alternative):
Round-robin DNS for Prism gateways
dig prism.example.com
→ 10.0.1.10 (us-east-1)
→ 10.0.2.20 (eu-west-1)
Geo-DNS for nearest gateway
dig prism.example.com
→ 10.0.1.10 (us-east-1) [if client in North America]
→ 10.0.2.20 (eu-west-1) [if client in Europe]
### 5. Cross-Region Routing
**Use Case**: Application in `us-east-1` needs to access namespace hosted in `eu-west-1`.
**Options**:
1. **Direct Routing**: Client connects to remote gateway (simple, higher latency)
2. **Gateway-to-Gateway Forwarding**: Local gateway proxies to remote gateway (transparent)
3. **Data Replication**: Namespace replicated across regions (lowest latency, eventual consistency)
message RouteRequest { string namespace = 1; string client_region = 2; }
message RouteResponse { enum RoutingStrategy { DIRECT = 0; // Client connects directly to remote gateway PROXY = 1; // Local gateway proxies to remote LOCAL_REPLICA = 2; // Use local replica }
RoutingStrategy strategy = 1; string target_gateway = 2; repeated string fallback_gateways = 3; }
## Latency and Partition Tolerance
### Handling High Latency (100-500ms)
**Strategies**:
1. **Async Configuration Push**: Don't block on config sync
prism-netgw: Config updated (version 123) → Async push to all clusters (fire-and-forget) → Eventually consistent (all clusters converge to version 123)
2. **Heartbeat with Jitter**: Randomize heartbeat intervals to avoid thundering herd
let heartbeat_interval = Duration::from_secs(30); let jitter = Duration::from_secs(rand::thread_rng().gen_range(0..10)); sleep(heartbeat_interval + jitter).await;
3. **Batch Updates**: Accumulate config changes and push in batches
Instead of: 10 individual namespace updates (10 round trips) Do: 1 batch with 10 namespace updates (1 round trip)
4. **Caching**: Prism clusters cache config locally (survive netgw downtime)
prism-agent: - Fetches config from netgw periodically - Caches config on disk - Uses cached config if netgw unavailable
### Handling Network Partitions
**CAP Theorem**: prism-netgw favors **Availability + Partition Tolerance** over **Consistency**.
**Scenario**: `eu-west-1` cluster loses connectivity to control plane.
**Behavior**:
1. **Local Operation**: Cluster continues serving requests using cached config
2. **Config Staleness**: Config may be stale (eventual consistency acceptable)
3. **Heartbeat Failure**: Cluster marked as "Unknown" in control plane
4. **Reconnection**: When partition heals, cluster syncs latest config
┌──────────────┐ ┌──────────────┐
│ prism-netgw │ ─── X ────────▶│ eu-west-1 │
│ (leader) │ │ (isolated) │
└──────────────┘ └──────────────┘
│ │
│ Config version: 150 │ Config version: 147 (cached)
│ Cluster status: UNKNOWN │ Status: OPERATIONAL (degraded)
│ │
│ ──────────────────────────────▶│ (partition heals)
│ SyncConfig(current_version=147)│
│ ◀──────────────────────────────│ Incremental updates: 148-150
Split-Brain Prevention
Problem: Network partition causes two control plane nodes to both claim leadership.
Solution: Raft consensus with quorum.
Cluster: 5 netgw nodes (us-east-1, us-west-2, eu-west-1, ap-south-1, ap-northeast-1) Quorum: 3 nodes
Partition scenario: Group A: us-east-1, us-west-2, eu-west-1 (3 nodes, HAS QUORUM) → continues as leader Group B: ap-south-1, ap-northeast-1 (2 nodes, NO QUORUM) → becomes followers
Result: Only Group A can make config changes (split-brain prevented)
## API Specification
### gRPC Service Definition
syntax = "proto3";
package prism.netgw.v1;
import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto";
service ControlPlaneService { // Cluster Management rpc RegisterCluster(RegisterClusterRequest) returns (RegisterClusterResponse); rpc UnregisterCluster(UnregisterClusterRequest) returns (UnregisterClusterResponse); rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse); rpc ListClusters(ListClustersRequest) returns (ListClustersResponse);
// Configuration Sync rpc SyncConfig(SyncConfigRequest) returns (SyncConfigResponse); rpc WatchConfig(WatchConfigRequest) returns (stream ConfigUpdate); // Server streaming
// Health Monitoring rpc ReportHealth(ReportHealthRequest) returns (ReportHealthResponse); rpc GetClusterHealth(GetClusterHealthRequest) returns (GetClusterHealthResponse); rpc GetGlobalHealth(GetGlobalHealthRequest) returns (GetGlobalHealthResponse);
// Service Discovery rpc DiscoverGateways(DiscoverGatewaysRequest) returns (DiscoverGatewaysResponse);
// Cross-Region Routing rpc RouteRequest(RouteRequest) returns (RouteResponse);
// Metrics rpc GetMetrics(GetMetricsRequest) returns (GetMetricsResponse); }
## Deployment
### Kubernetes Deployment (Multi-Region)
Deploy netgw control plane in multiple regions
apiVersion: apps/v1 kind: StatefulSet metadata: name: prism-netgw namespace: prism-system spec: replicas: 3 # Raft quorum template: spec: containers: - name: netgw image: prism/netgw:latest ports: - containerPort: 9980 name: grpc - containerPort: 9981 name: raft env: - name: NETGW_REGION value: "us-east-1" - name: NETGW_PEERS value: "netgw-0.netgw.prism-system.svc.cluster.local:9981,netgw-1.netgw.prism-system.svc.cluster.local:9981,netgw-2.netgw.prism-system.svc.cluster.local:9981" - name: NETGW_CLUSTER_ID value: "global-control-plane" volumeMounts: - name: data mountPath: /var/lib/netgw volumeClaimTemplates:
- metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi
### Agent Deployment (Per Cluster)
Deploy prism-agent on each Prism gateway cluster
apiVersion: apps/v1 kind: DaemonSet metadata: name: prism-agent namespace: prism spec: template: spec: containers: - name: agent image: prism/agent:latest env: - name: NETGW_ENDPOINT value: "prism-netgw.prism-system.svc.cluster.local:9980" - name: CLUSTER_ID value: "aws-us-east-1-prod" - name: REGION value: "us-east-1" - name: CLOUD_PROVIDER value: "aws" volumeMounts: - name: config-cache mountPath: /var/cache/prism volumes: - name: config-cache emptyDir: {}
## Security Considerations
### 1. Mutual TLS
All communication between netgw and agents uses mTLS:
tls: server_cert: /etc/netgw/tls/server.crt server_key: /etc/netgw/tls/server.key client_ca: /etc/netgw/tls/ca.crt client_cert_required: true
### 2. Authentication
Agents authenticate via client certificates:
CN=prism-agent,O=aws-us-east-1-prod,OU=prism-cluster
3. Authorization
RBAC policies for cluster operations:
policies:
- cluster_id: aws-us-east-1-prod
allowed_operations:
- RegisterCluster
- Heartbeat
- SyncConfig
- ReportHealth
forbidden_operations:
- UnregisterCluster # Only control plane admin
- ListClusters # Only control plane admin
4. Audit Logging
All control plane operations logged:
{
"timestamp": "2025-10-09T10:15:23Z",
"operation": "RegisterCluster",
"cluster_id": "aws-us-east-1-prod",
"region": "us-east-1",
"cloud_provider": "aws",
"success": true,
"latency_ms": 45
}
Observability
Metrics
Cluster metrics
prism_netgw_clusters_total{region="us-east-1",cloud_provider="aws"} 5 prism_netgw_cluster_health{cluster_id="...",status="healthy"} 1
Config sync metrics
prism_netgw_config_version{cluster_id="..."} 150 prism_netgw_config_sync_latency_ms{cluster_id="..."} 234
Heartbeat metrics
prism_netgw_heartbeat_success_total{cluster_id="..."} 12345 prism_netgw_heartbeat_failure_total{cluster_id="..."} 3 prism_netgw_heartbeat_latency_ms{cluster_id="..."} 156
### Distributed Tracing
Trace: RegisterCluster
├─ netgw: ValidateRequest (2ms)
├─ netgw: StoreCluster → etcd (45ms)
├─ netgw: PublishEvent → NATS (12ms)
└─ netgw: SendResponse (1ms)
Total: 60ms
Migration Path
Phase 1: Single-Region Deployment (Week 1)
- Deploy netgw control plane in one region
- Register Prism clusters in that region
- Basic config sync and health monitoring
Phase 2: Multi-Region Expansion (Week 2-3)
- Deploy netgw nodes in 3 regions (Raft quorum)
- Enable cross-region config sync
- Implement service discovery
Phase 3: Production Hardening (Week 4-5)
- Add latency tolerance mechanisms
- Implement partition handling
- Add comprehensive observability
Phase 4: Advanced Features (Future)
- Gateway-to-gateway routing
- Data replication across regions
- Multi-cloud VPC peering
Open Questions
- Control Plane Sizing: How many netgw nodes for global deployment?
- Config Storage: etcd vs Consul vs custom Raft?
- DNS vs gRPC Discovery: Which is more reliable for clients?
- Cross-Region Bandwidth: Cost implications of config sync?
- Failover Time: Acceptable latency for cluster failover?
References
- Raft Consensus Algorithm
- etcd Architecture
- Consul Multi-Datacenter
- Kubernetes Federation
- Google Spanner (global consistency)
- ADR-027: Admin API via gRPC
- RFC-010: Admin Protocol with OIDC
Revision History
- 2025-10-09: Initial draft for prism-netgw multi-region control plane