关于 system-design
介绍可扩展、高可用且能承受负载的系统设计原则与模式,适合规划架构和评估常见基础设施方案的开发者。
主要功能
- 01扩展能力与无状态服务
- 02负载均衡与健康检查
- 03缓存与数据库扩展
- 04消息队列与交付保证
- 05高可用与熔断器
- 06CAP、一致性与速率限制
适用场景
- 01规划应对流量增长的服务
- 02选择缓存和数据库扩展模式
- 03设计可靠的消息处理流程
- 04比较可用性与一致性取舍
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ miles990/ claude-software-skills --skill system-design安装后在 Claude Code 中输入/system-design确认已加载。
详细介绍
系统设计
概述
设计能够应对规模、保持可用性并在负载下表现良好的系统的原则。
可扩展性基础
垂直扩展 vs 水平扩展
Vertical Scaling (Scale Up):
┌─────────────────────┐
│ Bigger Server │
│ - More CPU │
│ - More RAM │
│ - Faster disk │
└─────────────────────┘
Limit: Hardware ceiling
Horizontal Scaling (Scale Out):
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│Server│ │Server│ │Server│ │Server│
└──────┘ └──────┘ └──────┘ └──────┘
↑
Load Balancer
Limit: Coordination complexity
无状态服务
// ❌ Stateful - stores session in memory
class BadService {
private sessions = new Map();
login(userId: string) {
this.sessions.set(userId, { loggedIn: true });
}
}
// ✅ Stateless - external session store
class GoodService {
constructor(private sessionStore: Redis) {}
async login(userId: string) {
await this.sessionStore.set(`session:${userId}`, { loggedIn: true });
}
}
负载均衡
策略
| 策略 | 描述 | 使用场景 |
|---|---|---|
| 轮询 | 依次循环使用服务器 | 容量相同的服务器 |
| 加权轮询 | 基于服务器容量 | 容量混合 |
| 最少连接 | 路由到最空闲的服务器 | 长连接 |
| IP 哈希 | 相同 IP → 相同服务器 | 会话粘性 |
| URL 哈希 | 相同 URL → 相同服务器 | 缓存优化 |
健康检查
# Kubernetes-style health checks
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
// Health check endpoints
app.get('/health/live', (req, res) => {
// Am I running?
res.status(200).json({ status: 'alive' });
});
app.get('/health/ready', async (req, res) => {
// Can I serve traffic?
const dbOk = await checkDatabase();
const cacheOk = await checkCache();
if (dbOk && cacheOk) {
res.status(200).json({ status: 'ready' });
} else {
res.status(503).json({ status: 'not ready', db: dbOk, cache: cacheOk });
}
});
缓存策略
缓存模式
Cache-Aside (Lazy Loading):
┌────────┐ miss ┌────────┐
│ App │ ──────────→ │ Cache │
│ │ ←────────── │ │
└────────┘ null └────────┘
│
│ read
↓
┌────────┐
│ DB │ ──── write ──→ Cache
└────────┘
Write-Through:
App → Cache → DB (synchronous)
Write-Behind (Write-Back):
App → Cache → (async) → DB
// Cache-aside implementation
class CachedUserService {
constructor(
private cache: Redis,
private db: Database
) {}
async getUser(id: string): Promise<User> {
// Try cache first
const cached = await this.cache.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Cache miss - read from DB
const user = await this.db.users.findById(id);
if (user) {
// Store in cache with TTL
await this.cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
}
return user;
}
async updateUser(id: string, data: Partial<User>): Promise<User> {
const user = await this.db.users.update(id, data);
// Invalidate cache
await this.cache.del(`user:${id}`);
return user;
}
}
缓存失效
| 策略 | 描述 | 复杂度 |
|---|---|---|
| TTL | 时间过后过期 | 简单 |
| 基于事件 | 写入时失效 | 中等 |
| 基于版本 | 键包含版本 | 中等 |
| 基于标签 | 将相关键分组 | 复杂 |
数据库扩展
只读副本
┌─────────────────┐
Writes ──────→ │ Primary DB │
└────────┬────────┘
│ replication
┌─────────────────┼─────────────────┐
↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Replica 1│ │ Replica 2│ │ Replica 3│
└──────────┘ └──────────┘ └──────────┘
↑ ↑ ↑
└─────── Reads ───┴────────────────┘
分片(分区)
// Hash-based sharding
function getShard(userId: string, numShards: number): number {
const hash = crypto.createHash('md5').update(userId).digest('hex');
return parseInt(hash.slice(0, 8), 16) % numShards;
}
// Range-based sharding
function getShardByDate(date: Date): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
return `orders_${year}_${month.toString().padStart(2, '0')}`;
}
// Consistent hashing for dynamic shards
class ConsistentHash {
private ring: Map<number, string> = new Map();
addNode(node: string) {
for (let i = 0; i < 150; i++) { // Virtual nodes
const hash = this.hash(`${node}:${i}`);
this.ring.set(hash, node);
}
}
getNode(key: string): string {
const hash = this.hash(key);
// Find next node on ring
for (const [nodeHash, node] of [...this.ring.entries()].sort()) {
if (nodeHash >= hash) return node;
}
return this.ring.values().next().value;
}
}
消息队列
模式
Point-to-Point:
Producer → Queue → Consumer
Pub/Sub:
┌─→ Subscriber 1
Publisher → Topic ─→ Subscriber 2
└─→ Subscriber 3
Work Queue:
┌─→ Worker 1
Producer → Queue ─→ Worker 2 (competing consumers)
└─→ Worker 3
投递保证
| 保证 | 描述 | 实现 |
|---|---|---|
| 至多一次 | 可能丢失消息 | 即发即忘 |
| 至少一次 | 可能重复 | 处理后确认 |
| 恰好一次 | 不丢失,不重复 | 幂等性 + 去重 |
// Idempotent processing
async function processOrder(event: OrderEvent) {
// Check if already processed
const processed = await redis.get(`processed:${event.id}`);
if (processed) {
console.log(`Already processed ${event.id}`);
return;
}
// Process the order
await db.orders.create(event.order);
// Mark as processed (with TTL for cleanup)
await redis.set(`processed:${event.id}`, '1', 'EX', 86400 * 7);
}
高可用性
冗余模式
Active-Active:
┌────────┐ ┌────────┐
│Server A│ ←─→ │Server B│ Both handle traffic
└────────┘ └────────┘
Active-Passive:
┌────────┐ ┌────────┐
│ Active │ ──→ │Standby │ Failover on failure
└────────┘ └────────┘
断路器
class CircuitBreaker {
private failures = 0;
private lastFailure: Date | null = null;
private state: 'closed' | 'open' | 'half-open' = 'closed';
constructor(
private threshold: number = 5,
private timeout: number = 30000
) {}
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'open') {
if (Date.now() - this.lastFailure!.getTime() > this.timeout) {
this.state = 'half-open';
} else {
throw new Error('Circuit is open');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess() {
this.failures = 0;
this.state = 'closed';
}
private onFailure() {
this.failures++;
this.lastFailure = new Date();
if (this.failures >= this.threshold) {
this.state = 'open';
}
}
}
CAP 定理
Consistency
/\
/ \
/ \
/ \
/ CA \
/──────────\
/ \
/ CP AP \
/________________\
Partition Availability
Tolerance
CA: Single node (RDBMS)
CP: MongoDB, HBase (may reject writes during partition)
AP: Cassandra, DynamoDB (eventual consistency)
一致性模型
| 模型 | 描述 | 示例 |
|---|---|---|
| 强一致性 | 读取能看到最新写入 | RDBMS |
| 最终一致性 | 最终一致 | DNS、Cassandra |
| 因果一致性 | 尊重因果关系 | 聊天应用 |
| 读己之写 | 看到自己的写入 | 社交动态 |
限流
算法
// Token Bucket
class TokenBucket {
private tokens: number;
private lastRefill: number;
constructor(
private capacity: number,
private refillRate: number // tokens per second
) {
this.tokens = capacity;
this.lastRefill = Date.now();
}
consume(tokens: number = 1): boolean {
this.refill();
if (this.tokens >= tokens) {
this.tokens -= tokens;
return true;
}
return false;
}
private refill() {
const now = Date.now();
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(
this.capacity,
this.tokens + elapsed * this.refillRate
);
this.lastRefill = now;
}
}
// Sliding Window
class SlidingWindowRateLimiter {
constructor(
private redis: Redis,
private limit: number,
private window: number // seconds
) {}
async isAllowed(key: string): Promise<boolean> {
const now = Date.now();
const windowStart = now - this.window * 1000;
const pipe = this.redis.pipeline();
pipe.zremrangebyscore(key, 0, windowStart);
pipe.zadd(key, now, `${now}`);
pipe.zcard(key);
pipe.expire(key, this.window);
const results = await pipe.exec();
const count = results[2][1] as number;
return count <= this.limit;
}
}
常见系统设计
| 系统 | 关键组件 |
|---|---|
| URL 短链接 | 哈希函数、Redis 缓存、DB |
| Twitter Feed | 扇出、Redis 时间线、Kafka |
| 聊天应用 | WebSocket、在线状态、消息队列 |
| 电商 | 购物车服务、库存、支付 |
| 视频流媒体 | CDN、分块、自适应比特率 |
相关技能
- [[architecture-patterns]] - 微服务、事件驱动
- [[database]] - 数据库优化
- [[caching-implementation]] - 缓存策略
- [[reliability-engineering]] - SRE 实践
评论
支持 Markdown