mcpField
D
database-sharding

database-sharding

github.com/secondsky数据与数据库240277 次安装5 周前更新
代码仓库

关于 database-sharding

为数据库水平扩展提供分片策略、路由模板和实施指南的技能,面向设计或维护分片架构的开发者。内容涵盖哈希、范围和目录路由,以及分片键选择、跨分片操作和重平衡。

主要功能

  1. 01哈希、范围和目录分片策略
  2. 02分片路由器模板
  3. 03分片键选择准则
  4. 04跨分片查询与事务参考
  5. 05监控和重平衡指导

适用场景

  1. 01为用户或租户数据选择分片键
  2. 02构建数据库分片路由层
  3. 03规划新增分片和数据迁移
  4. 04排查热点与跨分片查询问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/secondsky/claude-skills --skill database-sharding

安装后在 Claude Code 中输入/database-sharding确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
cross-shard-queries.md
error-catalog.md
implementation-patterns.md
rebalancing-guide.md
shard-key-selection.md
sharding-strategies.md
templates/
cross-shard-aggregation.ts
directory-router.ts
hash-router.ts
range-router.ts

详细介绍

database-sharding

用于水平扩展的综合数据库分片模式,涵盖哈希、范围和基于目录的策略。


快速入门(10 分钟)

步骤 1:从模板中选择分片策略:

# Hash-based (even distribution)
cat templates/hash-router.ts

# Range-based (time-series data)
cat templates/range-router.ts

# Directory-based (multi-tenancy)
cat templates/directory-router.ts

步骤 2:选择分片键标准:

  • ✅ 高基数(数百万个唯一值)
  • ✅ 均匀分布(没有单个值超过 5%)
  • ✅ 不可变(永不更改)
  • ✅ 查询匹配(出现在 80% 以上的 WHERE 子句中)

步骤 3:实现路由器:

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']);

关键规则

✓ 务必做到
规则原因
在查询中包含分片键避免扫描所有分片(慢 100 倍)
监控分片分布在热点导致服务中断前发现它们
提前规划重新平衡之后无法轻松添加分片
选择不可变的分片键更改键 = 数据迁移噩梦
使用生产数据测试分布合成数据会掩盖真实热点
为数据局部性进行反规范化将相关数据保留在同一分片上
✗ 务必避免
反模式不良影响
使用范围分片的顺序 ID最新分片会接收所有写入(热点)
将时间戳用作分片键最新分片负载过重
未使用 2PC 的跨分片事务数据损坏、不一致
不使用一致性哈希的简单取模添加分片时必须完整重新分片
可空的分片键对 NULL 的特殊处理会造成热点
没有分片路由层硬编码分片 = 无法重新平衡

7 个最关键的错误

错误 1:分片键选择错误(热点)

症状:一个分片接收了 80% 以上的流量 修复:

// ❌ 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
错误 2:查询中缺少分片键

症状:查询会扫描所有分片(极慢) 修复:

// ❌ 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
错误 3:使用范围分片的顺序 ID

症状:最新分片会接收所有写入 修复:

// ❌ 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
错误 4:没有重新平衡策略

症状:受困于初始分片数量,无法扩展 修复:

// ❌ 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
错误 5:跨分片事务

症状:数据不一致、部分写入 修复:

// ❌ 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
错误 6:可变的分片键

症状:记录会在分片间移动,导致重复 修复:

// ❌ 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
错误 7:没有监控

症状:热点未被察觉,性能突然下降 修复:

// ✅ 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 shard

加载 references/error-catalog.md,查看全部 10 个错误及详细修复方法。


分片策略

策略最适用场景优点缺点
哈希用户数据、均衡负载至关重要无热点、可预测范围查询会分散到多个分片
范围时序数据、日志、仅追加数据范围查询高效、便于归档最新分片会形成热点
目录多租户、复杂路由灵活、易于重新平衡查找开销、单点故障

加载 references/sharding-strategies.md,查看详细对比和生产环境示例(Instagram、Discord、Salesforce)。


分片键选择标准

标准重要性检查方法
高基数关键COUNT(DISTINCT shard_key) > shard_count × 100
均匀分布关键没有值超过总量的 5%
不可变关键值永不更改
查询匹配高80% 以上的查询包含该键
数据局部性中相关记录位于一起

决策树:

  • 面向用户的应用 → user_id
  • 多租户 SaaS → tenant_id
  • 时序数据/日志 → timestamp(范围分片)
  • 产品目录 → product_id

加载 references/shard-key-selection.md,查看全面的决策树和测试策略。


配置摘要

基于哈希的路由器
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']);
基于范围的路由器
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'
);
基于目录的路由器
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');

何时加载参考资料

选择策略

加载 references/sharding-strategies.md,适用于:

  • 在哈希、范围和目录策略之间做出选择
  • 需要生产环境示例(Instagram、Discord)
  • 规划混合方案
选择分片键

加载 references/shard-key-selection.md,适用于:

  • 为新项目选择分片键
  • 评估现有分片键
  • 使用生产数据测试分布
实现

加载 references/implementation-patterns.md,适用于:

  • 从头构建分片路由器
  • 实现一致性哈希
  • 需要处理事务(2PC、Saga)
  • 设置监控和指标
跨分片操作

加载 references/cross-shard-queries.md,适用于:

  • 需要跨分片聚合(COUNT、SUM、AVG)
  • 实现跨分片联接
  • 构建跨分片分页
  • 优化散播-收集模式
重新平衡

加载 references/rebalancing-guide.md,适用于:

  • 添加新分片
  • 在分片之间迁移数据
  • 规划零停机迁移
  • 平衡不均匀的负载
错误预防

加载 references/error-catalog.md,适用于:

  • 排查性能问题
  • 审查分片架构
  • 查看全部 10 个已记录错误及其修复方法

完整设置清单

分片前:

  • 使用生产数据测试分片键分布
  • 80% 以上的查询包含分片键
  • 监控基础设施已就绪
  • 已规划重新平衡策略

路由器实现:

  • 分片路由层(而非将分片硬编码)
  • 每个分片使用连接池
  • 错误处理和重试
  • 收集指标(每个分片的查询数、延迟)

分片配置:

  • 初始设置 4–8 个分片(留有扩展空间)
  • 使用一致性哈希或虚拟分片
  • 每个分片配置副本(HA)
  • 为每个分片制定备份策略

应用变更:

  • 所有查询都包含分片键
  • 消除跨分片联接(反规范化)
  • 遵循事务边界
  • 配置连接池

生产示例

之前(单个数据库不堪重负):

// 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, growing

之后(分片到 8 台服务器):

// 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)

已知问题预防

已预防全部 10 个已记录错误:

  1. ✅ 分片键错误(热点)→ 先测试分布
  2. ✅ 查询中缺少分片键 → 代码审查、代码检查
  3. ✅ 跨分片事务 → 使用 2PC 或 Saga 模式
  4. ✅ 顺序 ID 热点 → 使用基于哈希的分片
  5. ✅ 没有重新平衡策略 → 从第 1 天起使用一致性哈希
  6. ✅ 时间戳分片热点 → 采用哈希与范围混合方案
  7. ✅ 分片键可变 → 选择不可变键(user_id)
  8. ✅ 没有路由层 → 从一开始就通过路由器进行抽象
  9. ✅ 没有监控 → 跟踪每个分片的指标
  10. ✅ 哈希函数较弱 → 使用 MD5、MurmurHash3、xxHash

参见:references/error-catalog.md,了解详细修复方法


资源

模板:

  • 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 - 迁移策略
  • references/error-catalog.md - 全部 10 个已记录错误

生产环境示例:

  • Instagram:对媒体使用范围分片
  • Discord:对消息使用哈希分片
  • Salesforce:对组织使用目录分片

经过生产环境验证 | 预防 10 个错误 | MIT License

评论

支持 Markdown