1.1、分布式之弹性:服务隔离

4.1、简介

​ 最经典的比喻就是轮船的设计,隔离设计的英文叫”Bulkheads”,被翻译为隔板,我们的轮船的船舱就是通过隔板隔离出来的空间。其中一个船舱进水了,并不会影响其他船舱,也不会造成沉船,是一种很安全的设计。

在我们微服务的设计当中,难免一些服务”进水(故障)”,隔离设计保证其中一个服务出现问题,其他服务可以保证正常提供服务。

4.2 隔离方案

4.2.1、按业务隔离

​ 这里我们我们按照业务分为三个模块。活动页、首页feed、社交关系。很多业务场景,打开首页的时候,弹出活动页,提示你参加活动,进入活动页H5。

​ 同样根据业务分组,我们将DB资源也进行了隔离。不同的业务对应不同的资源。通过这种分组隔离,我们可以保证如果活动页出现了问题。最差的影响是进入App,首页的活动页消失,这种影响对于用户来说,也仅仅是不能参加活动而已,不影响App的正常使用。

​ 设计隔离的粒度在细,也难免出现跨业务的调用。比如首页关注feed流,拉取所有我关注人发布的信息。如果使用pull的方式,必然先去调用”社交关系”业务模块的相关服务。如果社交依赖业务出现问题。同样也会影响feed流。当然你也可以使用push的模式,将资源隔离的粒度更细,甚至完全独立(就是下面分享的多租户模式)。这种会带来资源冗余度高的问题。

  • 针对业务之间的交互,首先保证自身业务的高可用,其次可以通过消息队列订阅通知的模式实现业务之间的消息互换。
  • 针对业务的依赖,可以采用二阶段提交的方式。

4.2.1.1、小结

  • 隔板的设计围绕业务的需求与技术的需求
  • 如果生产者与消费者之间被隔离,比如利用消息队列,这个时候通过隔离的粒度来评估实现的成本,管理的复杂度,以及性能的开销。
  • 需要考虑因为隔离产生的异常如何处理,重试、熔断、限流。

4.2.2、按用户隔离

​ 根据用户维度进行隔离,就是根据不同的用户进行分区。每个分区对应一个服务实例,或多个服务实例。其中ServiceA中的一个实例挂了,只会影响Client1的用户,Client2与Client3的用户可以继续访问,不被影响。

​ “多租户”架构设计很因为隔离粒度的不同,产生不同的复杂度。但是一般是已下三种设计方案:

  • 接口分区,数据分区
  • 接口共享,数据分区
  • 接口共享,数据共享

对应的,资源共享度越来越高,复杂度越来越高,隔离性越来越低,资源成本越来越低。从分析中可以看出,接口分区,数据分区接口共享,数据共享,属于两个极端。一般采用接口共享,数据分区

​ 接口共享,针对不同的用户,不同用户间的数据进行隔离。例如,做活动相关业务,每个人活动状态,活动进度,就可以完全独立开。甚至是多个不同活动的业务,也可以进行区分隔离。

例如:redis有序集合

1
2
3
key:tasks_accepted_{用户di}_{活动业务id}
value:活动进度
score:时间戳

4.3 总结

​ 隔离设计选择根据用户维度进行隔离还是根据业务级别隔离,需要根据业务来恒定。甚至两种都结合使用。在设计中需要注意以下几点:

  • 隔离粒度根据业务来权衡
  • 隔离设计要保证服务的高可用,因为隔离产生的异常处理,限流,熔断,重试。
  • 消费者与生产者之间交互方式,结合复杂度引入如消息队列的技术方案
  • 将服务之间隔离,利用容器可以很好的平衡资源。考虑好运维方案。
  • 当将服务划分为隔板时,考虑将它们部署到单独的虚拟机、容器或进程中。容器提供了很好的资源隔离平衡和相当低的开销
  • 监控每个分区的性能和流量等