目录

弹力设计note

弹力设计note

以下为左耳听风 记录的笔记。

认识故障和弹力设计

系统可用性测量

分布式系统的容错设计,在英文中又叫Resiliency(弹力),即系统在不健康甚至出错的情况下能够承受住或者能够恢复的能力。

  • 系统可用性公式:

$$ Avaliability = \frac{MTTF}{MTTF+MTTR} $$

MTTF(Mean TIme To Failure):平均故障前的时间,即系统平均能够正常运行多长时间才发生一次故障。系统的可靠性越高,MTTF越长。

MTTR(Mean Time To Recovery):平均修复时间,即从故障出现到故障修复的这段时间。

根据公式来说,如果要提高可靠性,要么提高系统的无故障时间,要么减少系统的故障恢复时间

故障原因

工业界中会把服务不可用的因素分成两种:一种是有计划的,一种是无计划的。

  • 无计划的宕机原因

    https://img.zhengyua.cn/20210210112026.png

    • 系统级故障,包括主机、操作系统、中间件、数据库、网络、电源以及外围设备;
    • 数据和中介的故障,包括人员操作、硬盘故障、数据混乱;
    • 自然灾害、认为破坏、以及供电问题等;
  • 有计划的宕机原因

    https://img.zhengyua.cn/20210210112051.png

    • 日常任务:备份和容量规划,用户和安全管理,后台批处理应用;
    • 运维相关:数据库维护、应用维护、中间件维护、操作系统维护、网络维护;
    • 升级相关:数据库、应用、中间件、操作系统、网络,包括硬件升级;

总结来说,一共有以下几类问题:

  • 网络问题;
  • 性能问题;
  • 安全问题;
  • 运维问题;
  • 管理问题;
  • 硬件问题;

故障不可避免

我们需要意识到:

  • 故障是正常的,而且是常见的;
  • 故障是不可预测突发的,而且相当难缠;

不要尝试去避免故障,而是要把处理故障的代码当成正常的功能做在架构里写在代码里

弹力设计就是要降低MTTR即故障修复时间:

  • 一方面,在好的情况下,该设计对于我们的用户和内部运维来说是完全透明的,系统自动修复不需要人的干预;
  • 另一方面,若修复不了,系统能够自我保护,而不让事态变得更糟糕;

隔离设计

在分布式软件架构中我们需通过隔离设计来让出现的故障得到隔离,从而不让故障“蔓延“。

一般来说对于系统的分离有两种方式:

  • 以服务的种类来做分离;
  • 以用户来做分离;

按服务的种类来做分离

一般最常见的架构就是将每个服务实例包括接入层、应用层、数据层都完全隔离开来,这种隔离下在物理来说一个板块的故障就不会影响另一个板块。但是也会存在以下的问题:

  • 若需要调用其他实例的服务和数据,一旦同时调用或者调用过多就不可避免就会降低性能(响应时间,而不是吞吐量);
  • 若要降数据都抽取到一个数据仓库中进行计算,也会增加数据合并的复杂度;
  • 业务逻辑若需要跨板块则故障会导致流程无法进行,严重会导致整体业务故障;
  • 跨板块交互复杂情况下就需要类似于消息队列中间件来交互各个板块的数据和信息交换;
  • 多个板块可能也会出现分布式事务的问题;

按用户的请求来做分离

将用户分成不同的组,并把后端的同一个服务根据这些不同的组分成不同的实例,这样让同一个服务对于不同的用户进行冗余和隔离,即所谓的“多租户”模式。

对于“多租户”架构来说,会引入系统设计的复杂度,一方面若完全隔离则资源使用就会较为浪费,若共享的话则会导致程序设计的复杂度增加。

通常来说多租户的方案有以下三种:

  • 完全独立的设计。每个租户有自己完全独立的服务和数据;
  • 独立的数据分区,共享的服务。多租户的服务是共享的,但数据是分开隔离的;
  • 共享的服务,共享的数据分区。每个租户的数据和服务都是共享的;

https://img.zhengyua.cn/20210210115858.png

隔离设计的重点

做好隔离设计,我们需要有如下一些设计考量:

  • 认真分析业务需求和系统分析,定义好隔离业务的大小和粒度;
  • 需要考虑系统的复杂度、成本、性能、资源使用的问题,找到合适的均衡方案或是分布实施的方案;
  • 隔离模式需要配置一些高可用、重试、异步、消息中间件、流控、熔断等设计模式的方式配套使用;
  • 分布式系统中运维复杂度的提升需要自动化运维工具和系统;
  • 服务的监控系统;

异步通讯设计

通讯一般来说分同步和异步两种。

同步调用虽然让系统间只耦合于接口,且实施性也会比异步调用高,但也有以下问题:

  • 整个同步调用链的性能会由最慢的那个服务所决定;

  • 同步调用会导致所有参与方拥有相同的等待时间;

  • 同步调用只能是一对一的情况,较难做到一对多的通讯方式;

  • 同步调用链只要有一个地方出现故障就会导致整条链出现故障;

异步通讯的三种方式

  1. 请求响应式
  2. 通过订阅的方式
  3. 通过broker的方式

分布式系统的服务设计是需要向无状态服务努力的,其中第一种方式服务是有状态的,而其他方式可让服务间的依赖只有事件,即事件驱动架构。

事件驱动方式的优势有如下:

  • 服务间是平等的即无依赖且每个服务高度可崇勇并可被替换的;

  • 服务的开发测试运维以及故障处理都是高度隔离的;

  • 服务件通过事件关联即不会出现相互阻塞的情况;

  • 服务之间增加一些Adapter较为容易;

  • 各个服务可按自己的处理速度进行;

但事件驱动的架构也有一些不好的地方:

  • 业务流程不再那么明显且较难管理,整个架构变得复杂;

  • 事件可能会乱序,需要很好地管理一个状态机的控制来解决;

  • 事件处理变得复杂,需要保证一致性等问题;

异步通讯的设计重点

首先我们要明白为什么要异步通讯的原因:

  • 解耦服务间的依赖,比如通过Broker机制;

  • 解耦的目的是让各个服务的隔离性更好,如故障隔离等;

  • 吞吐量变得均匀即可达到削峰的目的;

  • 服务相对独立会在运维管理上面较为容易;

设计异步通信的时候需要注意以下事宜:

  • 用于异步通讯的中间件需要设计成高可用且不丢消息的,也需要注意消息的顺序问题;

  • 异步通讯导致业务处理流程不那么直观,需要有相关的服务消息跟踪机制,否则出现问题后不容易调试;

  • 服务件只通过消息交互,业务状态最好由一个总控方来管理维护整个业务流程的状态变迁逻辑;

  • 消息传递中需要处理方有幂等的处理;