分布式系统-容错设计

如果一个服务器出问题的概率是a
那么,一个集群所有服务器同时都出问题的概率是a^n,概率是相当小的;
但是,一个集群所有服务器同时都不出问题的概率是(1-a)^n,概率也是相当小的;
再加上集群有大量的通信,所以做分布式系统的时候,必须要意识到你的系统必定时常内部会出各种小问题,你必须要设法使用乾坤大挪移化解掉这些问题,不然就尴尬了;

下面是一套内功心法,大侠请收好:

1.幂等

  • 前置条件:无
  • 原因:不管是业务重试,框架产生的重试,还是网络层重传导致的重试,都有可能让一个请求发送多次;你必须保证,一个相同的请求发送2次甚至N次,产生的效果是一样的,不会因为发送了多次产生副作用;
  • 使用方式:大部分请求都有时效性,同样的请求隔了几个小时再发送过来,大概率是新的业务而不会是导致的重试;因此幂等保证只要在一定时间内,重复的请求你不再消费即可;常用方式是采用一个分布式的缓存,记录请求中唯一标识的requestId或者订单ID,对于每个请求,都判断一下是否有缓存记录,有则直接跳过请求,或者返回第一次消费得到的结果(看上层业务需求);缓存的超时时间即为请求的有效判断时间;

2.重试

  • 前置条件:幂等
  • 原因: 分布式系统中,请求未到达、或者请求失败时,这种失败很有可能是临时的,不是永久的,重新发送请求有可能成功;
  • 使用方式:重试必须先实现幂等,否则会破坏业务;重试频率一般采用“有限次”、“指数级避退”,同一个请求,成功率是逐次递减的,因此重试的频率也应该逐渐降低,否则会浪费系统资源,重试的次数必须有限,否则容易产生死循环;重试的情况建议列白名单去重试,拒绝无脑重试;

3.异步

  • 前置条件:幂等、重试
  • 原因:分布式系统中,一个请求可能需要经历好多个节点,请求完成的时间可能会较长,并且受整个集群网络和性能状态影响,请求完成的时间会发生较大波动;这个时间对于系统来说会偏长,但是对于业务来说尚可接受;这个时候如果采用同步的方式调用,会有大量的等待线程,并且伴有大量的超时失败,等待的时候也不知道对方是因为没收到请求没回,还是受到了请求没处理完成没回;但是异步方式,如果请求都没接收到,可以快速重试来保证接收到,这个时候要求已经实现了幂等和重试;
  • 使用方式:请求响应式,通过rpc框架发送请求后立即返回(一般返回成功则表明对方已经接收到请求),通过rpc轮询读取结果或者通过发送请求时提供的回调接口返回结果;事件驱动式,通过mafka等消息中间件,请求方发送请求至消息中间件,被调用方消费中间件的消息跑业务,并且将结果放到消息中间件中,请求发送方也通过消费中间件消息获取结果;实际使用中,这两种方式是综合使用的,比如请求响应式的结果返回可以加上消息中间件作为补偿,也可以直接替换成消息中间件方式;

4.隔板

  • 前置条件:无
  • 原因:核心逻辑一般是必须要全部成功的,但是有些非核心逻辑,失败了也并不打紧,或者成功一部分即可;这个时候要把这些非核心逻辑和核心逻辑之间进行隔离,或者非核心逻辑之间进行隔离;
    隔板设计是模仿船舶设计的,一个隔板内漏水不至于整条船沉没


    image.png

    泰坦尼克号是隔板设计的失败案例,隔板设计不合理,导致船舶倾斜,最终沉没


    image.png
  • 使用方式:JAVA中常对非核心业务进行分别的try...catch...,一个业务失败时也就打个日志,并不会影响整体业务;

5.补偿事务

  • 前置条件:隔板
  • 原因:一条路不通了,可以试试另外一条路,总之达到目的就行;比如你要发条消息给客户,微信发不通了,试试短信么。
  • 使用方式:业务逻辑中做业务补充即可,做好隔板,某项失败时不要影响整体业务;

6.降级

  • 前置条件:无
  • 原因:降级分为自动降级和手动降级,自动降级部分类似于补偿事务,但是在很多情况下是影响全局的,当检测到问题时,整个系统都对这个业务进行了业务替代;
  • 使用方式:一种是自动检测并做业务替代,类似于补偿事务;一种是做全局开关,这种开关可以是系统自动打开,或者人工进行打开;

7.熔断和限流

  • 前置条件:幂等、重试
  • 原因:熔断和限流是为了应对性能过载的情形,与其全部业务失败,不如拒绝部分业务,并将剩余业务顺利完成;大部分性能过载是因为一个流量突刺,如果已经设计好了幂等和重试,那么被拒绝的请求将会重新发送过来,那时系统可能已经缓过劲来,可以重新处理请求了;特别是一个集群中,只有一台服务器性能过载的情况,现在集群大部分都通过nginx路由,被拒绝的请求,上层会重新发送并被路由到其他服务器;如果你的系统一直处于性能过载状态,那时只能拓展你的资源,或者从其他架构层面去优化性能了;
  • 使用方式:一般通过限制QPS进行判断,单机或者整个集群达到一定QPS时,自动打开限流或者熔断开关;QPS可以做很多级别的限制,比如某个接口,或者针对某个调用服务器的外部业务;也可以做手动开关,应对紧急情况;

你可能感兴趣的:(分布式系统-容错设计)