核心洞察
支撑 1000 用户和支撑 100 万用户的区别不是 talent,而是 traffic 到来之前做出的架构决策。
1. 先定义需求
大多数工程师跳过的步骤——也是他们六个月后重建一切的原因。
非功能需求
| 指标 | 目标 |
|---|---|
| 峰值 QPS | 10k-50k requests/second |
| P99 延迟 | < 200ms(目标 < 100ms) |
| 可用性 | 99.99%(每月最多 4 分钟停机) |
| 一致性模型 | 金融数据强一致,feed 和时间线最终一致 |
| 成本上限 | 每 1000 用户设定严格金额 |
Scale Cube 三维模型
| 维度 | 策略 | 说明 |
|---|---|---|
| X 轴 | 水平复制 | 运行更多相同服务器 |
| Y 轴 | 功能分解 | 拆分为更小、专注的服务 |
| Z 轴 | 数据分区 | 按用户 ID 或地区分片 |
单独这个思维模型就能防止 90% 的扩展灾难。
2. 选择正确的基础
语言和框架
| 场景 | 选型 | 理由 |
|---|---|---|
| 原始性能 | Go / Rust | 性能和内存效率 |
| 团队速度优先 | TypeScript (NestJS) / Java/Kotlin (Spring Boot) | 开发效率 > 原始吞吐量 |
API 策略
| 场景 | 协议 |
|---|---|
| 对外 | REST + GraphQL |
| 内部服务间 | gRPC(类型安全、快速、支持流) |
架构演进
从模块化单体开始。只在特定服务成为可测量的 proven bottleneck 时才提取微服务。
过早微服务是扩展阶段工程速度的头号杀手。
3. 负载均衡和边缘层
请求路径
用户 (Lagos / London / Mumbai)
↓
Cloudflare / Fastly: CDN + DDoS 保护 + 边缘缓存
↓
Global Load Balancer: AWS Global Accelerator / GCP 等价物
↓
API Gateway: 速率限制 + WAF + bot 检测
↓
Application Services
在 100 万用户时,边缘层是第一道防线。 在请求到达应用服务器前尽可能处理更多流量。
4. 应用层设计
四条不可妥协的规则
| 规则 | 实现 |
|---|---|
| 无状态 | Session 放在 Redis 或 Dragonfly,绝不在应用内存 |
| 后台任务进队列 | Kafka 或 Pulsar(不是 RabbitMQ,不是内存处理,不是 setTimeout) |
| 调用级韧性 | 熔断器、带抖动的重试、硬超时——一个慢依赖不应级联为全系统故障 |
| 正确信号自动扩展 | CPU 是滞后指标。按队列深度和错误率扩展——反映实际系统压力 |
5. 数据库策略
单一数据库既是性能天花板也是单点故障。绝不要只用一种。
推荐栈
| 用途 | 技术 |
|---|---|
| 主 OLTP | PostgreSQL + Citus(水平分片) |
| 高写入路径 | Cassandra / ScyllaDB |
| 缓存和实时数据 | Redis Cluster |
| 分析和聚合 | ClickHouse |
关键规则
- 所有写入通过 query router、Vitess 或 Citus
- 按 user_id 取模分片,数据均匀分布
- 读副本在 PgBouncer 后做连接池
第一天就要选好 shard key。生产环境后更改是最痛苦的迁移之一。
6. 多级缓存
缓存是高规模系统中最大的成本杠杆。目标命中率 85%+。
| 层级 | 内容 | 命中时 |
|---|---|---|
| L1 Edge CDN | 静态资产、公开可缓存响应 | 绝不到达源站 |
| L2 应用 Redis | 计算结果、session 数据、热记录 | |
| L3 查询结果缓存 | 昂贵数据库读取 |
只有 full cache miss 时请求才到达数据库。
失效策略
- 通过 Kafka 事件驱动失效
- 用户 profile 更新事件应立即失效相关缓存 key
- TTL 单独不可靠,不能用于关键数据
7. 可观测性
从第一天就要有完整可观测性,而不是凌晨 2 点出事后才补。
技术栈
| 组件 | 用途 |
|---|---|
| Prometheus | 指标 |
| Jaeger | 分布式追踪 |
| Loki | 日志 |
| OpenTelemetry | 统一 instrumentation |
| Grafana | 仪表盘 |
| Alertmanager | 关键告警路由到 PagerDuty |
四个黄金信号
每个服务都要 instrument:
- Latency:请求耗时
- Traffic:请求量
- Errors:失败率
- Saturation:资源接近极限的程度
定义真实 SLO。跟踪错误预算。在用户注意到之前告警。
8. 数据一致性和幂等性
分布式系统以部分、不可预测的方式失败。从第一天就为此设计。
Outbox Pattern
在同一事务中写入事件表和业务逻辑。后台进程读取并发布。即使消息 broker 宕机,事件也不会丢失。
Saga Pattern
跨多个服务的事务使用补偿动作序列,而非两阶段提交。每步都有定义的 rollback,当下游步骤失败时执行。
幂等性 Key
每个变更操作接受唯一请求 ID。相同请求到达两次,返回原始结果。这是在不可靠网络上处理重试的唯一安全方式。
最终一致性在这个规模不是弱点,是正确的架构 trade-off。
9. 安全
| 措施 | 实现 |
|---|---|
| 服务间 mTLS | 所有内部调用都认证和加密 |
| 零信任网络 | 默认不信任任何服务,无论请求来源 |
| 加密 | 静态和传输中全加密,无例外 |
| Chaos Engineering | 故意杀死生产环境随机 pod,验证韧性假设 |
在受控测试中发现故障模式,比在凌晨 2 点的流量峰值中发现要好无限倍。
10. 完整架构
┌─────────────────────────────────────────┐
│ 1 Million Users │
├─────────────────────────────────────────┤
│ Edge + CDN + WAF │
├─────────────────────────────────────────┤
│ Global Load Balancer │
├─────────────────────────────────────────┤
│ API Gateway (Rate Limiting + Auth) │
├─────────────────────────────────────────┤
│ Stateless Application Services │
├─────────────────────────────────────────┤
│ Redis Cluster / Kafka Event Bus │
│ Sharded PostgreSQL + Cassandra │
├─────────────────────────────────────────┤
│ Background Workers │
├─────────────────────────────────────────┤
│ Observability: Prometheus, Grafana, │
│ Jaeger, Loki │
└─────────────────────────────────────────┘
这个架构处理 100 万日活用户,并有显著余量增长到数千万,无需根本性重写。
启动前检查清单
- 从小开始,测量一切。基于数据优化,而非假设。
- 用 k6 或 Locust 以 2x 预期峰值负载测试
- 使用 feature flags 和 canary 部署,绝不直接推给 100% 用户
- 优化前先 profile 热点路径——瓶颈很少在你以为的地方
- 非关键工作负载使用 spot/preemptible 实例显著削减基础设施成本
资源
- 作者:Akintola Steve (@Akintola_steve)
- 原文:https://x.com/Akintola_steve/status/2055620856802357587
- 延伸阅读:
- Designing Data-Intensive Applications (Martin Kleppmann)
- Uber Engineering Blog
- Netflix Tech Blog
- ByteByteGo