现在的大部分网络应用都是数据密集型,这些应用的问题通常来自数据量、数据复杂性和数据变更速度,而CPU却不是瓶颈。 第一章主要介绍了三个重要的问题:
-
可靠性(Reliability)
系统在 困境(adversity,比如硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,并能达到期望的性能水准)。
-
可伸缩性(Scalability)
有合理的办法应对系统的增长(数据量、流量、复杂性)。
-
可维护性(Maintainability)
许多不同的人(工程师、运维)在不同的生命周期,都能高效地在系统上工作(使系统保持现有行为,并适应新的应用场景)。
可靠性
故障(fault) 是造成错误的原因,通常是系统的一部分状态偏离标准。失效(failure) 则是整个系统停止提供服务。我们要提供可靠性,就是要建立容错机制,防止系统因为故障而失效失效。
故障的解决方法:
- 硬件故障:硬盘崩溃、机房断电、拔错网线等等事故,只要拥有很多机器,这些问题必然发生。
- 最直接的解决方法就是增加硬件的冗余:磁盘组raid、双电源……
- 也可以添加软件容错机制,允许部分节点失效,这样可以修复一个节点而无需系统停机。(比如Raft等一致性协议?)
- 软件错误:代码里的BUG、其他组件引发的故障……往往难以预料。
- 用彻底的测试,找出BUG。
- 提供一些保证,在系统运行时自检,一旦不满足预计的条件就发警报。
- 人为错误:人类错误使用系统
- 彻底的测试
- 精心设计的API
- 提供沙箱进行测试
可伸缩性
描述负载
考虑可伸缩性时,要先思考,到底什么问题对系统是重要的?所以我们要先找到合适的负载参数来描述这件事。它可以是每秒发出的请求、数据库的读写比率……
描述性能
一旦负载被描述好了,我们还要描述系统的性能。比如批处理系统关心吞吐量,在线服务关心响应时间。
一个服务 100 次请求响应时间的均值与百分位数
我们要仔细考虑如何描述性能,这会影响我们对系统优化的方向。比如对响应时间来说,平均值往往不是个好指标,因为它不能反应用户实际经历的延迟。
一般选择百分位点更好,比如中位数,它代表一半用户的请求返回时间低于这个数,更能表示用户体验。针对典型场景,我们可以采用更高的百分位点,比如95、99和99.9,也叫p95、p99和p999.
应对负载的方法
- 垂直伸缩:使用更好的机器。贵,但是简单
- 水平伸缩:使用更多的机器。只有无状态服务才比较好跨多台机器部署,但成本往往更低。可以说是未来趋势。
可维护性
软件系统的三个设计原则:
-
可操作性(Operability)
便于运维团队保持系统平稳运行。
-
简单性(Simplicity)
从系统中消除尽可能多的 复杂度(complexity) ,使新工程师也能轻松理解系统(注意这和用户接口的简单性不一样)。最直接的方式就是抽象。把实现细节隐藏在简洁的接口下。
-
可演化性(evolvability)
使工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配。也称为 可伸缩性(extensibility) 、可修改性(modifiability) 或 可塑性(plasticity) 。
小结
这一章主要介绍数据密集应用的非功能性需求:可靠性、可伸缩性和可维护性。
感觉比较重要的是可伸缩性,设计系统时一定要先根据业务来思考,我们的系统会遇到什么负载问题,为这些负载问题寻找有意义的、合适的描述,然后再考虑我们要让系统达到什么样的性能,选取合适的性能描述。