稳定性的模式与反模式
稳定性之于系统,就像健康之于人类,看起来重要不紧急,然而一旦失去,就追悔莫及。
稳定性是一切 0 前面的 1。
本文简单介绍下稳定的模式和反模式,大家在设计系统的时候可以多一点思考。
稳定性的反模式:
集成点
- 每一个依赖点的都有可能有问题。
- 利用断路器、超时、中间件解耦和握手等模式进行防御性编程,以防止集成点出现问题。
同层连累反应
- 例如在负载均衡下,一台服务器的停机会波及其余服务器。
- 可以配置健康检测,有问题时,启动新的实例。
层叠失效
- 层叠失效有一个将系统失效从一个层级传到另一个层级的机制
用户
- 用户会消耗内存
- 用户会做奇怪和随机的事情
- 恶意用户
线程阻塞
- 应用程序的失效大多与线程阻塞相关。系统失效形式包括常见的系统逐渐变慢和服务器 停止响应。线程阻塞反模式会导致同层连累反应和层叠失效。
自黑式攻击
- 无状态、自动化扩展
放大效应
- 留意点对点通信
- 留意共享资源
失衡的系统容量
- 通过测试发现系统容量失衡
一窝蜂
- 一窝蜂是对系统的集中使用,相比将峰值流量分散开后所需的系统能力,一窝蜂需要一
个更高的系统容量峰值。 - 不要将所有 cron 作业都设置在午夜或其他任何整点时间执行。用混合的方式设置时间,
分散负载。 - 固定的重试时间间隔,会集中那段时间的调用方需求。相反,使用退避算法,不同调用
方在经过自己的退避时间后,在不同的时间点发起调用。
做出误判的机器
- 基础设施管理工具可以迅速对系统产生巨大的影响,要在其内部构建限制器和防护措施,防止其快速毁掉整个系统。
缓慢的响应
- 一旦陷入响应缓慢,上游系统本身的处理速度也会随之变慢,并且当响应时间超过其自身的超时时间时,会很容易引发稳定性问题。
- 快速失败:如果系统能跟踪自己的响应情况,那么就可以知道自己何时变慢。当系统平均响应时间 超出系统所允许的时间时,可以考虑发送一个即时错误响应。至少,当平均响应时间超 过调用方的超时时间时,应该发送这样的响应。
无限长的结果集
- 使用切合实际的数据量。
- 在前端发送分页请求。
- 不要依赖数据生产者。
稳定性的模式:
良好的模式能为开发工程师提供架构和设计方面的指导, 从而减少、消除或缓解系统中的裂纹产生的影响。
超时
- 将超时模式应用于集成点、阻塞线程和缓慢响应。
- 超时模式可以防止对集成点的调用转变为对阻塞线程的调用,从而避免层叠失效。
- 采用超时模式,从意外系统失效中恢复。
- 当操作时间过长,有时无须明确其原因时,只需要放弃操作并继续做其他事。超时模式 可以帮助我们实现这一点。
- 考虑延迟重试。
- 大多数超时原因涉及网络或远程系统中的问题。这些问题不会立即被解决。立即重试很 可能会遭遇同样的问题,并导致再次超时。这只会让用户等待更长的时间才能看到错误 消息。大多数情况下,应该把操作任务放入队列,稍后再重试。
断路器
- 出现问题,停止调用。
- 断路器是保护系统免受各种集成点问题的基本模式。如果集成点出现问题,停止调用!
- 与超时模式一起使用。
- 当集成点出现问题时,断路器就能派上用场,避免继续调用。当使用超时模式时,表明集成点存在问题。
- 开放、跟踪并报告断路器状态变化情况。
- 断路器跳闸总是表明出现异常。运维工程师应该注意到这种情况,加以记录和报告,并分析其趋势和相关性。
舱壁
- 当灾难发生时,舱壁模式将系统进行分隔,确保部分系统功能可用。
- 选择有用的分隔粒度。
- 可以对应用程序内的线程池进行分隔,对服务器的 CPU 进行分隔,或对集群中的服务器进行分隔。
稳态
- 便面人为干预生产环境
- 应用自己清理带有应用程序逻辑的数据
- 限制缓存
- 滚动日志
快速失败
- 快速失败,而非缓慢响应
任其崩溃并替换
- 通过组件崩溃保护系统。
- 快速重启和重启归队。
握手
- 创建基于合作的需求控制机制。
- 考虑健康状况检查
考验机
- 优秀的考验机可以让你模拟现实世界中的各种混乱的系统失效方式。
中间件解耦
- 从同步的“请求回复”到异步的通信方式的转变,需要完全不同的设计。此时就需要考虑转换成本。
卸下负载
- 通过卸下负载避免响应缓慢。
背压机制
- 背压机制通过让消费者放慢工作来实现安全性。
- 消费者的处理速度终究会减慢,此时唯一能做的就是让消费者“提醒”提供者,不要过 快地发送请求。
- 在系统边界内运用背压机制。
- 如果是跨越系统边界的情况,就要换用卸下负载模式,当用户群是整个互联网时更应如此。
- 要想获得有限的响应时间,就需要构建有限长度的等待队列。
- 当等待队列已满时只有以下选择(虽然都不令人愉悦):丢弃数据,拒绝工作或将其阻塞。消费者必须当心,不要永久阻塞。
调速器
- 放慢自动化工具的工作速度,以便人工干预。
- 在不安全的方向上施加阻力。
- 考虑使用响应曲线。