一、数据密集型应用
现代数据系统通常由数据库、缓存、搜索索引和消息队列等通用组件组合而成。业务服务通过统一 API 隐藏内部实现,并向用户承诺数据正确性、性能与可用性。此时,应用开发者也成为了数据系统设计者。
用户请求 → 商品服务 → 商品数据库、Redis 缓存、搜索索引与变更消息队列
- 可靠性 Reliability:发生故障时,系统仍能正确工作。
- 可扩展性 Scalability:数据量、流量或复杂度增长时,有合理的应对方式。
- 可维护性 Maintainability:系统长期演进、多人维护时,仍能高效运维、理解和修改。
二、可靠性
Fault 与 Failure
- Fault(故障):某个组件偏离预期行为。
- Failure(失效):系统整体无法向用户提供承诺的服务。
- Fault tolerance(容错):阻止局部 fault 演变成整体 failure。
Fault 是内部发生了问题;failure 是问题突破系统边界,影响了服务承诺。
例如 Redis 不可用后,商品服务自动回源数据库。响应从 30ms 增加到 120ms,但数据正确且仍低于 200ms SLA。这是 fault,但不是 failure。如果 SLA 是 100ms,同一事件也构成 failure。
三类故障
- 硬件故障:磁盘、网卡、机器或机房故障,通常通过冗余、复制和故障转移处理。
- 软件错误:连接池泄漏、异常输入导致所有实例崩溃、缓存故障引发数据库雪崩。软件错误可能跨节点相关,更容易造成级联故障。
- 人为错误:错误配置、误删数据、发布错误。应通过权限隔离、灰度发布、审计、自动化和回滚机制降低风险。
Redis 故障 → 大量请求回源 → 数据库过载 → 连接池耗尽 → 商品服务整体失效
保护措施包括主备切换、本地缓存或旧值兜底、热点 Key 请求合并、数据库限流与熔断、非核心功能降级、缓存预热和故障演练。仅准备备用路径还不够,必须验证备用路径在真实故障下仍然可用。
三、可扩展性
负载参数
“支持高并发”不是可验证的描述。应该使用读写 QPS、读写比例、热点集中度、数据增长速度、价格更新速率、MQ 生产和消费速率等参数描述负载。
| 类型 | 例子 |
|---|---|
| 负载参数 | 输入 QPS、写入速率、索引数据量 |
| 容量配置 | 缓存大小、机器数量 |
| 压力信号 | MQ 积压量、P99、错误率 |
MQ 积压量应结合生产速率、消费速率和最老消息等待时间分析。消费速度大于生产速度时积压正在恢复,反之则继续恶化。
吞吐量、QPS 与响应时间
- 吞吐量:单位时间内成功完成的工作量,可以用请求/秒、事务/秒、消息/秒或 MB/秒表示。
- QPS:每秒查询或请求数,是吞吐量的一种具体计量方式。当工作单位就是请求时,成功 QPS 就是吞吐量。
- 输入 QPS:每秒到达的请求数,不一定等于系统成功完成的吞吐量。
- 响应时间:从请求发出到收到结果的总时间,包含执行、排队和网络等待。
P50 描述典型请求,P95、P99 和 P99.9 用于观察长尾。平均响应时间会掩盖偏斜分布和少量极慢请求。商品页并行依赖多个下游服务时,只要其中一个服务变慢,页面就会变慢,形成尾延迟放大。
扩容方式
- 纵向扩展:提高单机 CPU、内存、磁盘和网络能力,架构变化小,但存在硬件上限和单机风险。
- 横向扩展:增加服务实例、缓存分片、搜索节点、数据库分片或 MQ 消费者。有状态组件还要处理分片、复制、一致性和恢复。
- 手动扩容:稳定可预测,但响应较慢。
- 弹性扩容:能随负载变化,但存在启动延迟和扩缩容震荡风险。
大促计算案例
当前流量为 5,000 QPS、缓存命中率为 95%,数据库承担:
5,000 × (1 − 95%) = 250 QPS
大促流量增长到 20,000 QPS,命中率不变时,数据库承担:
20,000 × (1 − 95%) = 1,000 QPS
若数据库最大稳定容量为 600 QPS,仅增加商品服务实例无法解决瓶颈。缓存命中率至少需要达到:
1 − 600 ÷ 20,000 = 97%
实际系统还应预留安全余量,并结合只读副本、热点本地缓存、请求合并、缓存预热、限流和分片处理。
四、可维护性
可运维性 Operability
让开发和运维人员容易观察、管理和恢复系统。典型能力包括统一日志、指标、链路追踪、自动化部署、容量规划、变更记录和运行手册。只能逐台登录服务器查日志,属于可运维性差。
简单性 Simplicity
控制不必要的偶然复杂度,使系统更容易理解。多个服务共享数据库、循环依赖,以及同一业务概念存在多套定义,都会增加复杂度。
可演化性 Evolvability
系统能够安全适应新需求。新增价格类型或商品类型时,如果必须修改大量服务并协同发布,说明系统可演化性差。
五、综合案例
商家修改商品价格后,数据库和缓存已经更新,但 MQ 严重积压,Elasticsearch 两小时未更新:
- 可靠性:搜索页与详情页价格不一致。是否构成 failure,取决于系统承诺的索引同步时效。
- 可扩展性:负载增长后,MQ 生产速度超过消费速度,且 P99 明显升高,说明系统无法合理承载增长后的负载。
- 可维护性:缺少统一链路追踪,只能跨服务手动查询日志,属于可运维性不足。
六、架构评审模板
- 定义正确工作:系统承诺什么?哪些数据必须准确?允许多长时间的数据延迟?SLA 是什么?
- 描述负载:读写 QPS 和比例、热点程度、数据增长速度、MQ 生产和消费速率是多少?
- 描述性能:吞吐量及 P50、P95、P99 是多少?负载增长后哪个组件最先达到上限?
- 分析可靠性:需要容忍哪些故障?哪些 fault 可能演变成 failure?如何检测、隔离、降级和恢复?
- 分析可维护性:系统是否容易观察和恢复?是否存在偶然复杂度?新需求能否局部修改并安全回滚?
七、面试表达
我主要从可靠性、可扩展性和可维护性三个维度评价数据系统。可靠性关注局部故障是否会演变为用户可见的服务失效;可扩展性需要先用 QPS、读写比例、热点程度和数据量描述负载,再通过吞吐量和 P99 等指标观察负载增长后的表现;可维护性则包括系统是否容易运维、是否控制了不必要的复杂度,以及是否能够适应未来需求变化。