Skip to content

第一章:可靠性,可扩展性,可维护性

1. 数据系统与评估维度

现代应用通常由数据库、缓存、搜索、流处理、批处理、消息队列等组件组合而成。工程上讨论“数据系统”,本质是在讨论这组组件的协作方式与取舍。

设计一个数据系统时,核心评估维度不是“是否用了某个中间件”,而是是否同时满足 可靠性(Reliability)可扩展性(Scalability)可维护性(Maintainability)

2. 可靠性(Reliability)

2.1 定义与边界

可靠性不等于“不崩溃”,而是系统在正常与异常条件下都能持续满足预期:

  • 功能正确:输出符合业务语义与接口约定。
  • 容错能力:面对错误输入、节点故障、依赖抖动仍可服务。
  • 性能稳定:在约定负载下满足延迟与吞吐目标。
  • 安全可控:防止未授权访问与数据破坏。

2.2 故障与失效

  • Fault:组件内部偏离规范状态,例如磁盘坏块、网卡抖动、进程 bug。
  • Failure:系统对外无法提供承诺服务。

工程目标不是“消灭故障”,而是通过容错把故障吸收在系统内部,避免演变为对外失效。

2.3 常见故障来源

2.3.1 硬件故障

单机视角下硬件故障概率不高,但在大规模集群里是常态。常见策略是副本冗余、自动故障转移、在线修复,以及用软件容错替代“昂贵硬件兜底”。

2.3.2 软件故障

软件错误常表现为跨节点相关的系统性问题,例如错误缓存失效策略、重试风暴、雪崩式级联失败。治理重点是隔离、限流、熔断、可观测性与演练。

2.3.3 人为故障

运维配置失误、发布误操作、错误脚本是最常见的中断来源。推荐通过沙箱环境、自动化发布、灰度与回滚、审计追踪降低风险。

2.4 可靠性工程实践

  • 故障注入与混沌工程:验证系统是否真正具备降级与恢复能力。
  • 监控与遥测:覆盖吞吐、错误率、延迟分位、资源与业务指标。
  • 自检与告警:例如入队与出队计数守恒校验,提前发现数据丢失。

3. 可扩展性(Scalability)

3.1 先定义负载,再谈扩展

可扩展性没有统一答案,必须先定义负载参数:

  • Web 服务:RPS、并发连接数。
  • 数据库:读写比、热点比例、查询模式。
  • 流系统:事件速率、分区数、状态大小。

3.2 典型案例:时间线扇出

社交时间线常见两种模型:

  • Pull:写入轻,读取时聚合,读放大明显。
  • Push:读取快,写入时扇出到粉丝时间线,写放大明显。

实务中通常采用混合方案:普通用户用 Push,大 V 用 Pull,以控制极端扇出成本。

3.3 性能指标与尾延迟

  • 批处理更看重吞吐量(Throughput)。
  • 在线请求更看重响应时间(Response Time)。

平均值会掩盖慢请求,容量规划应以分位数为主:p50p95p99p99.9

当一次请求依赖多个下游时,尾延迟会叠加放大。依赖链越长,终端请求落入慢尾部的概率越高。

3.4 扩展路径

  • 纵向扩展(Scale Up):实现简单,但成本高且有硬件上限。
  • 横向扩展(Scale Out):复杂度高,但可持续扩容。
  • 弹性伸缩(Elasticity):适合负载波动明显的云场景。

4. 可维护性(Maintainability)

4.1 可运维性(Operability)

系统应便于日常运行与故障处置:可观测、可自动化、可灰度、可回滚、可容量评估。目标是让运维动作从“人肉排障”转向“流程化处理”。

4.2 简洁性(Simplicity)

要主动压缩“额外复杂度(Accidental Complexity)”。有效手段是高质量抽象:隐藏实现细节,暴露稳定接口,降低心智负担与认知耦合。

4.3 可演化性(Evolvability)

需求变化是常态。系统应通过模块边界、兼容协议、自动化测试与持续重构,保持低成本演进能力。

5. 本章小结

  • 可靠性关注“出问题时仍能正确服务”。
  • 可扩展性关注“负载增长时如何维持性能目标”。
  • 可维护性关注“长期迭代成本是否可控”。

三者共同决定一个数据系统是否能长期稳定支撑业务增长。