数据密集型
数据密集型(Data-intensive):对于一个应用系统,如果数据是其成败的决定性因素,包括:数据的规模、数据的复杂度、数据的产生与变化速率等,即可称为“数据密集型应用系统”。与之相对应的是“计算密集型系统”,CPU主频是其主要制约瓶颈。
数据密集型应用通常基于标准模块构造而成,每个模块负责单一功能,如:数据库、高速缓存、索引、流式处理、批处理等。单个组件无法满足所有数据处理与存储需求,因而需将任务分解,每个组件高效完成一部分,多组件依赖应用层代码有机衔接起来。
软件系统需主要关注三个问题:
- 可靠性(Reliability):出现意外情况如硬件、软件故障、人为失误等,系统应可以继续正常运转;虽然性能可能有所降低,但确保功能正确。
- 可拓展性(Scalability):随着规模的增长,例如数据量、流量或复杂性,系统应以合理的方式来匹配这种增长。
- 可维护性(Maintainability):随着时间的推移,许多新的人员参与到系统开发和运维,以维护现有功能或适配新场景等,系统都应高效运转。
可靠性
可简单认为是:即使发生了某些错误,系统仍可以继续工作。
故障(faults)和失效(failure)不完全一致,故障通常被定义为组件偏离常规规格,失效意味着系统作为一个整体停止,无法向客户提供所需服务。通常需要设计容错机制避免从故障引发系统失效。
一般可以通过故意引发故障的方式,来持续检验、测试系统的容错机制(Netflix - Chaos Monkey) 。
硬件故障
硬盘崩溃、内存故障、电网停电、网络中断。
为硬件添加冗余来减少系统故障率:一个组价故障时,冗余组件快速接管,之后再更换失效组件。
软件错误
软件BUG、某进程使用共享资源(内存、CPU等)时消耗过度、所依赖服务故障、级联故障
没有快速解决办法,需认真检查依赖条件和系统交互,进行全面测试,进程隔离,允许进程崩溃并自动重启,并监控评估行为。
人为失误
以最小出错方式设计系统。想办法分离最容易出错的地方。
充分的测试:单测、集成测试、手动测试。
快速回滚配置改动、滚动发布新代码、提供校验数据工具。
详细而清晰的监控子系统。
管理流程及培训。
可拓展性
应对系统使用增长的措施、如何添加资源来处理额外的负载。
描述负载
负载参数的选择取决于系统的体系结构。例如:Web 服务器每秒请求数,数据写入比例,聊天室同时在线人数,缓存命中率等。有时平均值很重要,有时系统瓶颈来自于少数峰值。
描述性能
延迟(latency)和响应时间(response time)的区别在于:响应时间是客户端看到的,除了处理请求的时间外,还包括网络延迟和各种派对延迟。延迟则是请求花费在处理上的时间。很重要的一点是要在客户端来测试响应时间。
一般选择指标时,平均值并不合适,最好选择百分位数(percentiles),如将响应时间从快到慢排序,中位数(median)就是列表中间的响应时间。最常见的百分位数是95、99、99.9(即P95、P99、P999)。
还需要考虑长尾效应,如P99之外的请求恰恰可能是最重要的一个或多个,也是最有价值的一个。
实践中的百分位数:设置一个10min的滑动窗口,监控其中响应时间,滚动计算窗口中的中为数和各种百分位数然后绘制性能图表。
应对负载增加的办法
特定级别负载不能应对超过目标10倍的实际负载。若目标服务处于快速增长阶段,则需认真考虑增加一个数量级的负载需如何设计。
扩展分为水平扩展(负载分布到多个更小机器)和垂直扩展(升级到更强大的机器),需在其中做出取舍。
将无状态服务扩展至多台机器相对比较容易,而有状态服务从单个节点扩展到分布式多机环境复杂度会增加。
扩展能力好的架构通常会做出某些假设,然后有针对性地优化设计,如哪些操作是最频繁的。
可维护性
软件系统的三个设计原则:
- 可运维性:方便运营团队保持系统平稳运行
- 简单性:简化系统复杂性,使新人可以轻松理解系统。通过良好的抽象降低复杂度。
- 可演化性:后续工程师可以轻松地对系统进行改进,即易于改变