随笔分类
可靠,可扩展,可维护性
关于数据系统的思考
现如今很多的应用程序都是数据密集型(data-intensive),而非数据计算型(conpute-intensive)。换句话讲,当今应用程序的主要瓶颈不在于硬件(CPU、内存、硬盘等),在于日益剧增的数据量、数据复杂性、以及数据的变更速度。
单个工具不再满足应用程序的需求,取而代之的是,总体工作被拆分成能被单个工具高效完成的任务,并通过业务代码将其它们缝合起来。
软件系统中很重要的三个问题:
可靠性 (Reliability)
系统在困境(Adversity, 硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,达成预期性能水准)。
可扩展性 (Scalability)
有合理的办法去应对系统的增长(数据量、流量、复杂性)
可维护性 (Maintainability)
可靠性
- 造成错误的原因叫故障 (Fault),能预料并应对故障的系统特性称为容错 (Fault-Tolerance),
- 故障不等于失效:故障定义为系统的一部分状态偏离标准,失效则是系统作为一个整体停止向用户提供服务。
- 比起阻止错误,我们更加倾向于容忍错误,但也会有预防胜于治疗的情况。
硬件故障
说起系统失效,常会联想到硬件故障:硬盘崩溃、内存出错、网线被拔了之类的,任何与大型数据中心打过交道的人会告诉你:一旦你拥有很多机器,这类事情总会发生(组件失效是常态,看成是凸曲线分布图,很多机器同时发生故障以及都不发生故障的概率都是极小的)。
硬件同一时刻发生故障通常是存在关联性,因此在部署机器时一方面不会部署在从同一个厂商上购买的机上上,其次出于意外事故的避免,应用节点会部署不同数据中心下(数据中心通常是跨地域存储)
随着数据量和应用计算需求的增加,云平台设计时优先考虑的是灵活性和弹性,而不是单机可靠性。
软件故障
- 这类软件故障的 Bug通常会潜伏较长时间,直到被异常情况触发为止。
- 无特效药,解决方法:仔细考虑系统中的假设和交互;混沌测试;重启;进程隔离;监控
人为错误
- 人是不可靠的,运维配置错误是导致服务中断的主要原因。
- 解决方案:以最小化犯错机会的方式设计系统;充分测试;快速恢复;监控;培训
可扩展性
可扩展性是用来描述系统应付负载增长能力的术语,在可扩展性中我们关注于两方面:负载、性能。
描述负载
负载可以用一些称为负载参数的数字来去描述,对于不同的系统,负载参数也各不相同,这与系统架构设计以及对应业务相关。
如Twitter的负载参数则跟其业务相关,即对每秒推文的发送量。
描述性能
- 当系统负载描述好了后,问题就变成了:
- 增加系统负载并保持系统资源(cpu、内存、网络带宽等)不变时,系统的性能将受到什么影响?
- 增加负载参数并希望系统性能不变时,需要增加多少系统资源?
- 对于在线系统,关注的是请求的响应时间,这关系到用户的体验;对于离线系统(数据批处理能力),更加关注于吞吐量,即指定时间内对数据的处理能力。
- 延迟区别于响应时间:响应时间是用户所看到的,除了实际处理请求的时间,还包括了网络延迟(受网络拓扑、带宽影响)和排队延迟(请求到达服务端,受限于cpu并行处理能力,需要排队等待请求被处理,这种效应有时也叫头部阻塞);延迟指的是某个请求等待处理的持续时长,在此期间处于休眠状态。
- 对于系统响应时间而言,相比于平均时间,更加推荐去使用百分位点,这最能体现出典型的响应时间:中位数、P99,etc。
应对负载:
一个良好适配应用的架构,是围绕着假设建立的:哪些操作是常见的?哪些操作是罕见的?这就是你所谓的负载参数
- 纵向扩展:转向更加强大的机器,或在系统资源不变下写出能高可扩展性的代码。
- 横向扩展:将负载分不到多台机器上,简单来说,机器廉价,加机器去解决问题。
- 弹性系统:检测到负载增加时自动扩增系统资源
- 无状态服务跨机器部署非常简单,但带状态的数据系统跨机器部署配置时可能会引入更多的复杂性,因此尽可能现将数据库放在单个节点上,直至被迫改为分布式。
可维护性
在设计之初就尽量考虑尽可能减少运维期间的痛苦,从而避免自己的软件系统变成遗留系统。
对于可维护性,我们更加关注于:可操作性(便于运维团队保持系统平稳运行);简单性(管理系统复杂度,使得新工程师也能轻松理解系统);可演化性(工程师可以再未来轻松对系统进行更改,当需变化时为新应用场景做适配)。