database-sharding
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesedatabase-sharding
数据库分片
Comprehensive database sharding patterns for horizontal scaling with hash, range, and directory-based strategies.
支持哈希、范围、目录三种策略的全量数据库分片模式,用于实现水平扩展。
Quick Start (10 Minutes)
快速入门(10分钟)
Step 1: Choose sharding strategy from templates:
bash
undefined步骤1:从模板中选择分片策略:
bash
undefinedHash-based (even distribution)
基于哈希(分布均匀)
cat templates/hash-router.ts
cat templates/hash-router.ts
Range-based (time-series data)
基于范围(适用于时序数据)
cat templates/range-router.ts
cat templates/range-router.ts
Directory-based (multi-tenancy)
基于目录(适用于多租户场景)
cat templates/directory-router.ts
**Step 2**: Select shard key criteria:
- ✅ **High cardinality** (millions of unique values)
- ✅ **Even distribution** (no single value > 5%)
- ✅ **Immutable** (never changes)
- ✅ **Query alignment** (in 80%+ of WHERE clauses)
**Step 3**: Implement router:
```typescript
import { HashRouter } from './hash-router';
const router = new HashRouter([
{ id: 'shard_0', connection: { host: 'db0.example.com' } },
{ id: 'shard_1', connection: { host: 'db1.example.com' } },
{ id: 'shard_2', connection: { host: 'db2.example.com' } },
{ id: 'shard_3', connection: { host: 'db3.example.com' } },
]);
// Query single shard
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);cat templates/directory-router.ts
**步骤2**:遵循分片键选择标准:
- ✅ **高基数**(数百万个唯一值)
- ✅ **分布均匀**(无单个值占比超过5%)
- ✅ **不可变更**(永远不会修改)
- ✅ **查询对齐**(出现在80%以上的WHERE子句中)
**步骤3**:实现路由逻辑:
```typescript
import { HashRouter } from './hash-router';
const router = new HashRouter([
{ id: 'shard_0', connection: { host: 'db0.example.com' } },
{ id: 'shard_1', connection: { host: 'db1.example.com' } },
{ id: 'shard_2', connection: { host: 'db2.example.com' } },
{ id: 'shard_3', connection: { host: 'db3.example.com' } },
]);
// 查询单个分片
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);Critical Rules
核心规则
✓ Always Do
✓ 必须遵守
| Rule | Reason |
|---|---|
| Include shard key in queries | Avoid scanning all shards (100x slower) |
| Monitor shard distribution | Detect hotspots before they cause outages |
| Plan for rebalancing upfront | Cannot easily add shards later |
| Choose immutable shard key | Changing key = data migration nightmare |
| Test distribution with production data | Synthetic data hides real hotspots |
| Denormalize for data locality | Keep related data on same shard |
| 规则 | 原因 |
|---|---|
| 查询中携带分片键 | 避免全分片扫描(速度慢100倍) |
| 监控分片分布情况 | 在热点引发故障前提前发现问题 |
| 提前规划重平衡方案 | 后续新增分片难度极高 |
| 选择不可变更的分片键 | 修改分片键会引发数据迁移灾难 |
| 用生产数据测试分布情况 | 模拟数据会掩盖真实热点问题 |
| 通过非规范化保证数据局部性 | 将关联数据存储在同一个分片 |
✗ Never Do
✗ 禁止操作
| Anti-Pattern | Why It's Bad |
|---|---|
| Sequential ID with range sharding | Latest shard gets all writes (hotspot) |
| Timestamp as shard key | Recent shard overwhelmed |
| Cross-shard transactions without 2PC | Data corruption, inconsistency |
| Simple modulo without consistent hashing | Cannot add shards without full re-shard |
| Nullable shard key | Special NULL handling creates hotspots |
| No shard routing layer | Hardcoded shards = cannot rebalance |
| 反模式 | 危害 |
|---|---|
| 范围分片搭配顺序ID | 最新分片承接所有写入请求(热点) |
| 用时间戳作为分片键 | 近期数据所在分片会被压垮 |
| 不使用2PC执行跨分片事务 | 会导致数据损坏、不一致 |
| 不使用一致性哈希的简单取模 | 新增分片时需要全量重新分片 |
| 分片键允许为空 | NULL值的特殊处理会引发热点 |
| 没有分片路由层 | 硬编码分片规则导致无法重平衡 |
Top 7 Critical Errors
7个最常见的严重错误
Error 1: Wrong Shard Key Choice (Hotspots)
错误1:分片键选择错误(热点问题)
Symptom: One shard receives 80%+ of traffic
Fix:
typescript
// ❌ Bad: Low cardinality (status field)
shard_key = order.status; // 90% are 'pending' → shard_0 overloaded
// ✅ Good: High cardinality (user_id)
shard_key = order.user_id; // Millions of users, even distribution症状:单个分片承接80%以上的流量
修复方案:
typescript
// ❌ 错误:低基数(状态字段)
shard_key = order.status; // 90%的记录都是'pending' → shard_0过载
// ✅ 正确:高基数(user_id)
shard_key = order.user_id; // 数百万用户,分布均匀Error 2: Missing Shard Key in Queries
错误2:查询中未携带分片键
Symptom: Queries scan ALL shards (extremely slow)
Fix:
typescript
// ❌ Bad: No shard key
SELECT * FROM orders WHERE status = 'shipped'; // Scans all 100 shards!
// ✅ Good: Include shard key
SELECT * FROM orders WHERE user_id = ? AND status = 'shipped'; // Targets 1 shard症状:查询扫描全部分片(速度极慢)
修复方案:
typescript
// ❌ 错误:无分片键
SELECT * FROM orders WHERE status = 'shipped'; // 扫描全部100个分片!
// ✅ 正确:携带分片键
SELECT * FROM orders WHERE user_id = ? AND status = 'shipped'; // 仅访问1个分片Error 3: Sequential IDs with Range Sharding
错误3:范围分片搭配顺序ID
Symptom: Latest shard gets all writes
Fix:
typescript
// ❌ Bad: Range sharding with auto-increment
// Shard 0: 1-1M, Shard 1: 1M-2M, Shard 2: 2M+ → All new writes to Shard 2!
// ✅ Good: Hash-based sharding
const shardId = hash(id) % shardCount; // Even distribution症状:最新分片承接所有写入请求
修复方案:
typescript
// ❌ 错误:自增ID搭配范围分片
// 分片0: 1-1M, 分片1: 1M-2M, 分片2: 2M+ → 所有新写入都进入分片2!
// ✅ 正确:基于哈希的分片
const shardId = hash(id) % shardCount; // 分布均匀Error 4: No Rebalancing Strategy
错误4:没有重平衡策略
Symptom: Stuck with initial shard count, cannot scale
Fix:
typescript
// ❌ Bad: Simple modulo
const shardId = hash(key) % shardCount; // Adding 5th shard breaks ALL keys
// ✅ Good: Consistent hashing
const ring = new ConsistentHashRing(shards);
const shardId = ring.getNode(key); // Only ~25% of keys move when adding shard症状:只能使用初始分片数量,无法扩展
修复方案:
typescript
// ❌ 错误:简单取模
const shardId = hash(key) % shardCount; // 新增第5个分片会导致所有键映射失效
// ✅ 正确:一致性哈希
const ring = new ConsistentHashRing(shards);
const shardId = ring.getNode(key); // 新增分片时仅约25%的键需要迁移Error 5: Cross-Shard Transactions
错误5:跨分片事务问题
Symptom: Data inconsistency, partial writes
Fix:
typescript
// ❌ Bad: Cross-shard transaction (will corrupt)
BEGIN;
UPDATE shard_1.accounts SET balance = balance - 100 WHERE id = 'A';
UPDATE shard_2.accounts SET balance = balance + 100 WHERE id = 'B';
COMMIT; // If shard_2 fails, shard_1 already committed!
// ✅ Good: Two-Phase Commit or Saga pattern
const txn = new TwoPhaseCommitTransaction();
txn.addOperation(shard_1, 'UPDATE accounts SET balance = balance - 100 WHERE id = ?', ['A']);
txn.addOperation(shard_2, 'UPDATE accounts SET balance = balance + 100 WHERE id = ?', ['B']);
await txn.execute(); // Atomic across shards症状:数据不一致、部分写入成功
修复方案:
typescript
// ❌ 错误:跨分片事务(会导致数据损坏)
BEGIN;
UPDATE shard_1.accounts SET balance = balance - 100 WHERE id = 'A';
UPDATE shard_2.accounts SET balance = balance + 100 WHERE id = 'B';
COMMIT; // 如果分片2执行失败,分片1已经提交!
// ✅ 正确:两阶段提交或Saga模式
const txn = new TwoPhaseCommitTransaction();
txn.addOperation(shard_1, 'UPDATE accounts SET balance = balance - 100 WHERE id = ?', ['A']);
txn.addOperation(shard_2, 'UPDATE accounts SET balance = balance + 100 WHERE id = ?', ['B']);
await txn.execute(); // 跨分片原子操作Error 6: Mutable Shard Key
错误6:分片键可修改
Symptom: Records move shards, causing duplicates
Fix:
typescript
// ❌ Bad: Shard by country (user relocates)
shard_key = user.country; // User moves US → CA, now in different shard!
// ✅ Good: Shard by immutable user_id
shard_key = user.id; // Never changes症状:记录在分片间迁移,导致重复数据
修复方案:
typescript
// ❌ 错误:按国家分片(用户可能搬迁)
shard_key = user.country; // 用户从美国搬到加拿大,现在属于不同分片!
// ✅ 正确:用不可变更的user_id分片
shard_key = user.id; // 永远不会修改Error 7: No Monitoring
错误7:缺乏监控
Symptom: Silent hotspots, sudden performance degradation
Fix:
typescript
// ✅ Required metrics
- Per-shard record counts (should be within 20%)
- Query distribution (no shard > 40% of queries)
- Storage per shard (alert at 80%)
- Latency p99 per shardLoad for all 10 errors with detailed fixes.
references/error-catalog.md症状:静默热点、性能突然下降
修复方案:
typescript
// ✅ 必须监控的指标
- 每个分片的记录数(差值应在20%以内)
- 查询分布(无分片承接超过40%的查询)
- 每个分片的存储用量(使用率达80%时告警)
- 每个分片的p99延迟加载 查看全部10个错误的详细修复方案。
references/error-catalog.mdSharding Strategies
分片策略
| Strategy | Best For | Pros | Cons |
|---|---|---|---|
| Hash | User data, even load critical | No hotspots, predictable | Range queries scatter |
| Range | Time-series, logs, append-only | Range queries efficient, archival | Recent shard hotspot |
| Directory | Multi-tenancy, complex routing | Flexible, easy rebalancing | Lookup overhead, SPOF |
Load for detailed comparisons with production examples (Instagram, Discord, Salesforce).
references/sharding-strategies.md| 策略 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| 哈希 | 用户数据、对负载均衡要求高的场景 | 无热点、可预测 | 范围查询需要分散到多个分片 |
| 范围 | 时序数据、日志、仅追加写入的场景 | 范围查询效率高、易于归档 | 近期分片易出现热点 |
| 目录 | 多租户、复杂路由场景 | 灵活、易于重平衡 | 存在查询开销、单点故障风险 |
加载 查看包含Instagram、Discord、Salesforce等生产案例的详细对比。
references/sharding-strategies.mdShard Key Selection Criteria
分片键选择标准
| Criterion | Importance | Check Method |
|---|---|---|
| High cardinality | Critical | |
| Even distribution | Critical | No value > 5% of total |
| Immutable | Critical | Value never changes |
| Query alignment | High | 80%+ queries include it |
| Data locality | Medium | Related records together |
Decision Tree:
- User-focused app →
user_id - Multi-tenant SaaS →
tenant_id - Time-series/logs → (range sharding)
timestamp - Product catalog →
product_id
Load for comprehensive decision trees and testing strategies.
references/shard-key-selection.md| 标准 | 重要性 | 校验方法 |
|---|---|---|
| 高基数 | 核心 | |
| 分布均匀 | 核心 | 无单个值占总量的5%以上 |
| 不可变更 | 核心 | 值永远不会修改 |
| 查询对齐 | 高 | 80%以上的查询会携带该字段 |
| 数据局部性 | 中 | 关联记录可以放在一起 |
决策树:
- 面向用户的应用 →
user_id - 多租户SaaS →
tenant_id - 时序/日志数据 → (范围分片)
timestamp - 商品目录 →
product_id
加载 查看完整决策树和测试策略。
references/shard-key-selection.mdConfiguration Summary
配置汇总
Hash-Based Router
哈希路由
typescript
import { HashRouter } from './templates/hash-router';
const router = new HashRouter([
{ id: 'shard_0', connection: { /* PostgreSQL config */ } },
{ id: 'shard_1', connection: { /* PostgreSQL config */ } },
]);
// Automatically routes to correct shard
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);typescript
import { HashRouter } from './templates/hash-router';
const router = new HashRouter([
{ id: 'shard_0', connection: { /* PostgreSQL config */ } },
{ id: 'shard_1', connection: { /* PostgreSQL config */ } },
]);
// 自动路由到正确的分片
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);Range-Based Router
范围路由
typescript
import { RangeRouter } from './templates/range-router';
const router = new RangeRouter(shardConfigs, [
{ start: Date.parse('2024-01-01'), end: Date.parse('2024-04-01'), shardId: 'shard_q1' },
{ start: Date.parse('2024-04-01'), end: Date.parse('2024-07-01'), shardId: 'shard_q2' },
{ start: Date.parse('2024-07-01'), end: Infinity, shardId: 'shard_q3' },
]);
// Range queries target specific shards
const janEvents = await router.queryRange(
Date.parse('2024-01-01'),
Date.parse('2024-02-01'),
'SELECT * FROM events WHERE created_at BETWEEN $1 AND $2'
);typescript
import { RangeRouter } from './templates/range-router';
const router = new RangeRouter(shardConfigs, [
{ start: Date.parse('2024-01-01'), end: Date.parse('2024-04-01'), shardId: 'shard_q1' },
{ start: Date.parse('2024-04-01'), end: Date.parse('2024-07-01'), shardId: 'shard_q2' },
{ start: Date.parse('2024-07-01'), end: Infinity, shardId: 'shard_q3' },
]);
// 范围查询仅访问指定分片
const janEvents = await router.queryRange(
Date.parse('2024-01-01'),
Date.parse('2024-02-01'),
'SELECT * FROM events WHERE created_at BETWEEN $1 AND $2'
);Directory-Based Router
目录路由
typescript
import { DirectoryRouter } from './templates/directory-router';
const router = new DirectoryRouter(directoryDBConfig, shardConfigs);
// Assign tenant to specific shard
await router.assignShard('tenant_acme', 'shard_enterprise');
// Route automatically
const users = await router.query('tenant_acme', 'SELECT * FROM users');typescript
import { DirectoryRouter } from './templates/directory-router';
const router = new DirectoryRouter(directoryDBConfig, shardConfigs);
// 将租户分配到指定分片
await router.assignShard('tenant_acme', 'shard_enterprise');
// 自动路由
const users = await router.query('tenant_acme', 'SELECT * FROM users');When to Load References
何时需要查阅参考文档
Choosing Strategy
选择分片策略时
Load when:
references/sharding-strategies.md- Deciding between hash, range, directory
- Need production examples (Instagram, Discord)
- Planning hybrid approaches
加载 ,当你需要:
references/sharding-strategies.md- 在哈希、范围、目录策略中做选择
- 参考生产案例(Instagram、Discord)
- 规划混合分片方案
Selecting Shard Key
选择分片键时
Load when:
references/shard-key-selection.md- Choosing shard key for new project
- Evaluating existing shard key
- Testing distribution with production data
加载 ,当你需要:
references/shard-key-selection.md- 为新项目选择分片键
- 评估现有分片键的合理性
- 用生产数据测试分片分布
Implementation
实现阶段
Load when:
references/implementation-patterns.md- Building shard router from scratch
- Implementing consistent hashing
- Need transaction handling (2PC, Saga)
- Setting up monitoring/metrics
加载 ,当你需要:
references/implementation-patterns.md- 从零搭建分片路由
- 实现一致性哈希
- 处理事务(2PC、Saga)
- 搭建监控/指标体系
Cross-Shard Operations
跨分片操作场景
Load when:
references/cross-shard-queries.md- Need to aggregate across shards (COUNT, SUM, AVG)
- Implementing cross-shard joins
- Building pagination across shards
- Optimizing scatter-gather patterns
加载 ,当你需要:
references/cross-shard-queries.md- 跨分片聚合(COUNT、SUM、AVG)
- 实现跨分片关联
- 实现跨分片分页
- 优化 scatter-gather 模式
Rebalancing
重平衡场景
Load when:
references/rebalancing-guide.md- Adding new shards
- Migrating data between shards
- Planning zero-downtime migrations
- Balancing uneven load
加载 ,当你需要:
references/rebalancing-guide.md- 新增分片
- 在分片间迁移数据
- 规划零停机迁移
- 平衡不均衡的负载
Error Prevention
错误预防场景
Load when:
references/error-catalog.md- Troubleshooting performance issues
- Reviewing shard architecture
- All 10 documented errors with fixes
加载 ,当你需要:
references/error-catalog.md- 排查性能问题
- 评审分片架构
- 查看全部10个已记录的错误及修复方案
Complete Setup Checklist
完整部署检查清单
Before Sharding:
- Tested shard key distribution with production data
- Shard key in 80%+ of queries
- Monitoring infrastructure ready
- Rebalancing strategy planned
Router Implementation:
- Shard routing layer (not hardcoded shards)
- Connection pooling per shard
- Error handling and retries
- Metrics collection (queries/shard, latency)
Shard Configuration:
- 4-8 shards initially (room to grow)
- Consistent hashing or virtual shards
- Replicas per shard (HA)
- Backup strategy per shard
Application Changes:
- All queries include shard key
- Cross-shard joins eliminated (denormalized)
- Transaction boundaries respected
- Connection pooling configured
分片前:
- 已用生产数据测试分片键分布
- 80%以上的查询携带分片键
- 监控基础设施已就绪
- 已规划重平衡策略
路由实现:
- 实现分片路由层(不硬编码分片)
- 每个分片配置连接池
- 实现错误处理和重试逻辑
- 实现指标采集(每个分片的查询量、延迟)
分片配置:
- 初始配置4-8个分片(预留扩展空间)
- 使用一致性哈希或虚拟分片
- 每个分片配置副本(高可用)
- 每个分片配置备份策略
应用改造:
- 所有查询携带分片键
- 消除跨分片关联(非规范化)
- 遵守事务边界
- 配置连接池
Production Example
生产环境示例
Before (Single database overwhelmed):
typescript
// Single PostgreSQL instance
const db = new Pool({ host: 'db.example.com' });
// All 10M users on one server
const users = await db.query('SELECT * FROM users WHERE status = $1', ['active']);
// Query time: 5000ms (slow!)
// DB CPU: 95%
// Disk: 500GB, growingAfter (Sharded across 8 servers):
typescript
// Hash-based sharding with 8 shards
const router = new HashRouter([
{ id: 'shard_0', connection: { host: 'db0.example.com' } },
{ id: 'shard_1', connection: { host: 'db1.example.com' } },
// ... 6 more shards
]);
// Query single user (targets 1 shard)
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);
// Query time: 10ms (500x faster!)
// Query all shards (scatter-gather)
const allActive = await router.queryAll('SELECT * FROM users WHERE status = $1', ['active']);
// Query time: 800ms (parallelized across 8 shards, 6x faster than single)
// Result: Each shard handles ~1.25M users
// DB CPU per shard: 20%
// Disk per shard: 65GB
// Can scale to 16 shards easily (consistent hashing)改造前(单库过载):
typescript
// 单PostgreSQL实例
const db = new Pool({ host: 'db.example.com' });
// 全部1000万用户都在同一台服务器
const users = await db.query('SELECT * FROM users WHERE status = $1', ['active']);
// 查询耗时: 5000ms(非常慢!)
// 数据库CPU使用率: 95%
// 磁盘用量: 500GB,持续增长改造后(8台服务器分片部署):
typescript
// 8分片的哈希分片方案
const router = new HashRouter([
{ id: 'shard_0', connection: { host: 'db0.example.com' } },
{ id: 'shard_1', connection: { host: 'db1.example.com' } },
// ... 其余6个分片
]);
// 查询单个用户(仅访问1个分片)
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);
// 查询耗时: 10ms(快了500倍!)
// 查询全部分片(scatter-gather模式)
const allActive = await router.queryAll('SELECT * FROM users WHERE status = $1', ['active']);
// 查询耗时: 800ms(8个分片并行执行,比单库快6倍)
// 效果: 每个分片承载约125万用户
// 每个分片的CPU使用率: 20%
// 每个分片的磁盘用量: 65GB
// 可以轻松扩展到16个分片(基于一致性哈希)Known Issues Prevention
已知问题预防
All 10 documented errors prevented:
- ✅ Wrong shard key (hotspots) → Test distribution first
- ✅ Missing shard key in queries → Code review, linting
- ✅ Cross-shard transactions → Use 2PC or Saga pattern
- ✅ Sequential ID hotspots → Use hash-based sharding
- ✅ No rebalancing strategy → Consistent hashing from day 1
- ✅ Timestamp sharding hotspots → Hybrid hash+range approach
- ✅ Mutable shard key → Choose immutable keys (user_id)
- ✅ No routing layer → Abstract with router from start
- ✅ No monitoring → Track per-shard metrics
- ✅ Weak hash function → Use MD5, MurmurHash3, xxHash
See: for detailed fixes
references/error-catalog.md全部10个已记录的错误都已覆盖预防方案:
- ✅ 错误的分片键(热点)→ 提前测试分布情况
- ✅ 查询未携带分片键 → 代码评审、lint检查
- ✅ 跨分片事务 → 使用2PC或Saga模式
- ✅ 顺序ID热点 → 使用哈希分片
- ✅ 无重平衡策略 → 从第一天就使用一致性哈希
- ✅ 时间戳分片热点 → 哈希+范围的混合方案
- ✅ 可修改的分片键 → 选择不可变更的键(user_id)
- ✅ 无路由层 → 从一开始就用路由层做抽象
- ✅ 无监控 → 追踪每个分片的指标
- ✅ 弱哈希函数 → 使用MD5、MurmurHash3、xxHash
参考: 查看详细修复方案
references/error-catalog.mdResources
资源
Templates:
- - Hash-based sharding
templates/hash-router.ts - - Range-based sharding
templates/range-router.ts - - Directory-based sharding
templates/directory-router.ts - - Aggregation patterns
templates/cross-shard-aggregation.ts
References:
- - Strategy comparison
references/sharding-strategies.md - - Key selection guide
references/shard-key-selection.md - - Router implementations
references/implementation-patterns.md - - Query patterns
references/cross-shard-queries.md - - Migration strategies
references/rebalancing-guide.md - - All 10 errors documented
references/error-catalog.md
Production Examples:
- Instagram: Range sharding for media
- Discord: Hash sharding for messages
- Salesforce: Directory sharding for orgs
Production-tested | 10 errors prevented | MIT License
模板:
- - 哈希分片实现
templates/hash-router.ts - - 范围分片实现
templates/range-router.ts - - 目录分片实现
templates/directory-router.ts - - 跨分片聚合模式
templates/cross-shard-aggregation.ts
参考文档:
- - 分片策略对比
references/sharding-strategies.md - - 分片键选择指南
references/shard-key-selection.md - - 路由实现方案
references/implementation-patterns.md - - 查询模式
references/cross-shard-queries.md - - 迁移策略
references/rebalancing-guide.md - - 全部10个错误的记录
references/error-catalog.md
生产案例:
- Instagram: 媒体数据的范围分片
- Discord: 消息数据的哈希分片
- Salesforce: 租户的目录分片
经过生产环境验证 | 覆盖10个常见错误的预防方案 | 采用MIT许可证