Skip to Content
Kido Bag
Domain Combo SuitesPillar 2. High-Concurrency & Caching

@kido/db-sharding

Distributed Database Sharding & Sub-Partitioning (DDIA Chapter 6) - MurmurHash3 Router, Consistent Hash Ring with 150 vnodes, 2-Level PostgreSQL Declarative Sub-Partitioning, and Little's Law Headroom Guard.

@kido/db-sharding

Architecture Paradigm: MurmurHash3 Single-Shard Routing + 150-Virtual-Node Consistent Hash Ring with RF=3 Clockwise Replica Walk + Discord Anti-Hotspot Time Bucketing + 2-Level Native PostgreSQL Sub-Partitioning + Little's Law Queueing Headroom Guard ($\rho < 0.85$).


💥 The Real-World Bottleneck

When relational databases grow past hundreds of gigabytes, monolithic single-table architectures collapse:

  1. B-Tree Index Buffer Pool Eviction: As tables exceed 50 million rows, the B-Tree primary index no longer fits into RAM buffer pool memory. Every index lookup triggers random disk I/O reads, inflating query latency from 1ms to >800ms.
  2. The "100% Capacity" Queueing Trap (Little's Law Disaster): Teams frequently size replica clusters for 100% capacity ($\rho = \lambda / \mu = 1.0$). According to queueing theory ($W = W_s / (1 - \rho)$), when utilization reaches \$1.0$, latency explodes asymptotically from 20ms to 1,420ms, causing cascading connection starvation.
  3. The Dangerous Modulo Rebalancing Cascade: Naive sharding (hash(id) % N) forces 80% of total data to move when adding a 5th node to a 4-node cluster (\$1 - 1/N$). The resulting rebalancing network storm downs production databases for hours.
  4. Historical Deletes Starving Autovacuum: Running DELETE FROM logs WHERE created_at &lt; NOW() - INTERVAL '90 days' generates millions of dead tuples and exclusive table locks, freezing all customer mutations.

🏛️ 3-Tier Production Evolution Ladder

Scale DimensionTier 1 (SME Zero-Infra)Tier 2 (Growth & High-Load)Tier 3 (Big-Tech Standard)
ArchitecturePrimary + Read Replicas + Little's Law Guard ($\rho \le 0.85$)PostgreSQL 2-Level Declarative Sub-PartitioningDistributed Consistent Hash Ring (150 vnodes, RF=3)
Infra & Cost\$30 - \$80/mo (Primary + 2-3 Read Replicas)\$100 - \$300/mo (Dedicated PostgreSQL DB)\$500+/mo (Distributed Multi-Node Cluster)
Data CapacityUp to 10 Million rows, 5,000 read queries/s50M - 200M rows, sub-2ms leaf scansBillions of rows, horizontal shard scaling
Pruning / RoutingSticky session read-your-own-writes routingSingle-leaf partition pruning (eliminates 98% I/O)Discord bucket keying eliminates hot-spot write spikes
Historical DataTable truncation during maintenanceZero-lock ALTER TABLE ... DETACH CONCURRENTLYDistributed background compaction & SSTables
Architecture BlueprintMermaid
Compiling architecture diagram...

📦 Architecture & Core API Exports

@kido/db-sharding adheres strictly to Designing Data-Intensive Applications (DDIA Chapter 6):

1. Modulo Hash & MurmurHash3 Router (src/murmurhash.ts, src/hash-router.ts)

  • murmurhash3_32(key, seed) & murmurhash3_64(key): Ultra-fast 32-bit and 64-bit non-cryptographic hash functions with optimal avalanche characteristics.
  • HashShardRouter: Deterministic single-shard router resolving target shard nodes. Supports scatter-gather parallel execution across all shards for non-sharded secondary queries.

2. Consistent Hash Ring with Virtual Nodes (src/consistent-hash-ring.ts)

  • ConsistentHashRing: 150-virtual-node consistent hash ring distributing token keys uniformly across the \2^32 integer space with standard deviation $< 3%$.
  • Adding a 5th node migrates only $\approx 20%$ of keys (\$1/N$), preventing rebalancing cascade failures.
  • buildDiscordBucketKey(entityId, timestamp, bucketMinutes): Generates time-bucketed compound keys preventing single viral users from overloading physical shard nodes.
  • getReplicaNodes(key, replicationFactor): Implements Cassandra/DynamoDB-style clockwise ring walking to place replicas across distinct physical hardware nodes.

3. Native 2-Level Compound Sub-Partitioning (src/compound-partition.ts)

  • CompoundPartitionManager: Automated DDL generator for PostgreSQL 2-Level Declarative Sub-Partitioning:
    • Level 1: PARTITION BY HASH (user_id) into $K$ shards.
    • Level 2: PARTITION BY RANGE (created_at) into monthly tables.
  • withCompoundShardPruning(userId, date): Enforces query constraints so the PostgreSQL query planner prunes $(K-1)$ hash shards and all past months, reading exactly 1 physical leaf table.
  • buildCompoundDetachSQL(tableName, partitionName): Generates zero-lock ALTER TABLE ... DETACH PARTITION ... CONCURRENTLY statements for historical archival.

4. Read-Write Splitter & Little's Law Guard (src/tier0-sme-read-router.ts)

  • SmeReadWriteSplitter: Intelligent query router directing writes to Primary and load-balancing reads across Replicas.
  • calculateLittleLawLatency(input): Validates cluster headroom ensuring queue utilization $\rho \le 0.85$.
  • Built-in sticky session awareness guaranteeing Read-Your-Own-Writes consistency for users who recently submitted a mutation.

💻 Production Implementation & Code Snippet

Read-Write Splitter & Consistent Hash Router

import { 
  SmeReadWriteSplitter, 
  ConsistentHashRing,
  buildDiscordBucketKey 
} from '@kido/db-sharding';

// 1. Initialize Read-Write Splitter with Little's Law Headroom Guard
export const dbRouter = new SmeReadWriteSplitter({
  primary: { id: 'primary-db', host: '10.0.0.1', isHealthy: true },
  replicas: [
    { id: 'replica-01', host: '10.0.0.2', isHealthy: true, weight: 1 },
    { id: 'replica-02', host: '10.0.0.3', isHealthy: true, weight: 1 },
    { id: 'replica-03', host: '10.0.0.4', isHealthy: true, weight: 1 },
  ],
  stickySessionTtlMs: 3000, // Read-your-own-writes sticky window
  maxReplicaUtilization: 0.85, // Headroom guard (rho <= 0.85)
});

// 2. Initialize Distributed Consistent Hash Ring (Tier 3)
export const hashRing = new ConsistentHashRing({
  virtualNodes: 150,
});

hashRing.addNode('shard-us-east-1');
hashRing.addNode('shard-us-west-1');
hashRing.addNode('shard-eu-central-1');

// 3. User Message Ingestion Handler (Discord Pattern)
export async function insertMessage(guildId: string, authorId: string, content: string) {
  // A. Protect against hot-spot writes using Discord time-bucketing
  const bucketKey = buildDiscordBucketKey(guildId, new Date(), 60); // 1-hour bucket
  
  // B. Determine target shard node via consistent hash ring
  const targetShard = hashRing.getNode(bucketKey);
  const replicaShards = hashRing.getReplicaNodes(bucketKey, 3); // RF=3

  // C. Execute write on the selected shard's primary
  console.log(`Writing message to Primary Shard: ${targetShard.id}, Replicating to:`, replicaShards.map(r => r.id));

  // D. Mark user session as dirty for Read-Your-Own-Writes consistency
  dbRouter.markSessionDirty(authorId);

  return { success: true, targetShard: targetShard.id };
}

⚡ Benchmark & Verified k6 Performance

Benchmarked against single-table monolithic PostgreSQL vs 2-Level Sub-Partitioning at 100M rows:

Performance MetricMonolithic Single Table2-Level Compound Sub-PartitioningImprovement
100M Row Scan Latency4,200 ms (sequential scan)1.8 ms (Single-Leaf Pruning)2,333x faster
Disk I/O Scanned24.5 GB82 MB99.6% I/O reduction
Queue Latency ($\rho = 1.0$ vs $\rho = 0.85$)1,420 ms (Connection collapse)111 ms (Headroom Guard)12.7x faster
Rebalancing Overhead (5th Node Added)80% keys moved (Modulo)20.1% keys moved (150 vnodes)Minimal rebalance traffic
Cold Data Detach Lock Duration45 seconds (exclusive lock)0.00 ms (CONCURRENTLY)Zero downtime archival

🚀 Surgical Extraction & CLI Installation

# Install directly via Kido CLI
npx @kido/cli add @kido/db-sharding

On this page