微服务3:微服务拆分策略

★ 微服务系列

微服务1:微服务及其演进史
https://www.cnblogs.com/wzh2010/p/14940280.html

微服务2:微服务全景架构 
https://www.cnblogs.com/wzh2010/p/15311192.html

微服务3:微服务拆分策略
https://www.cnblogs.com/wzh2010/p/15414209.html

前面我们学习了微服务的全景架构,了解到相对于传统单体架构,微服务的优势,以及系统服务化的发展趋势。 

对于新启动的项目,我们在权衡之后可以大方的使用微服务架构。但其实大部分情况下,我们还要去维护一些以前研发的单体系统,这些系统可能因为访问流量的膨胀、功能的扩张而显得非常臃肿不堪,急需要向微服务架构迁移。

1 微服务迁移准备 

1、需对业务充分了解,这是服务拆分,通信设计,资源整合的必要前提。

2、适应微服务架构设计原则:小版本,高速迭代

3、快速的环境提供能力:依赖于云计算、容器技术,快速交付环境

4、服务合理拆分:需符合团队结构或能逆向影响,能对组织架构进行微调并划分职责。(康威定律和逆康威定律)

5、基本的监控能力:包括基础的技术监控和业务监控。

6、快速的应用部署能力:需要部署管道提供快速的部署能力

7、DevOps 自动化运维能力:需要具有良好的持续集成和持续交付能力,还需要对问题、故障的快速响应能力,开发、测试和运维能协同工作。

2 微服务颗粒的拆分策略

前面两篇文章我们学习了What & Why(什么是微服务和为什么需要做微服务架构),这一章我们就来探讨如何做微服务架构的拆分(How)。

微服务拆分没有一个绝对的标准答案,服务拆分的粒度需要根据业务场景来规划,而随着业务的发展,原先的架构方案也需要做调整。

虽然没有固定的套路,但是我们在业务实践过程中总结的一些经验,以做参考。

2.1 基于业务逻辑拆分

基于业务逻辑拆分相对好理解一点,典型的单一职责原则,我们将功能相近的业务整合到一个服务颗粒上。比如一个办公领域系统,考勤、工作流、音视频会议是是三个截然不同的业务领域,这可能就是我们拆分的一个入手点。

2.1.1 领域模型拆分

领域驱动设计DDD(Domain-Driven Design 领域驱动设计)是一个很简单的概念,表示我们对系统的划分是基于领域的,也即是基于业务方向去思考的

举一个典型的电商业务例子。电商的业务体系庞大,涉及各方面的细节。但是我们大概能够根据业务的职能做一个拆分,比如阿里的电商中台业务,包含 用户账号子系统、商品子系统、订单子系统、客户子系统、物流子系统 等。

因为职能不同,这些领域之间包含清晰的界限,所以我们可以按照这个方向将服务于不同领域(商品域和订单域)的子系统拆成独立的服务颗粒。如下图:

 

2.1.2 用户群体拆分

根据用户群体做拆分,我们首先要了解自己的系统业务里的用户角色领域是否没有功能耦合,有清晰的领域界限。

比如教育信息化系统,教师的业务场景和学生的业务场景,基本比较独立,而且拆分后流量上有明显的削弱,这时候结合具体的业务分析,看是否有价值。如下图所示:

 

2.2 基于可扩展拆分 

这个需要区分系统中变与不变的部分,不变的部分一般是成熟的、通用的服务功能,变的部分一般是改动比较多、满足业务迭代扩展性需要的功能,我们可以将不变的部分拆分出来,作为共用的服务,将变的部分独立出来满足个性化扩展需要。
同时根据二八原则,系统中经常变动的部分大约只占 20%,而剩下的 80% 基本不变或极少变化,这样的拆分也解决了发布频率过多而影响成熟服务稳定性的问题。
比如一个电商领域的系统,用户信息、基本商品信息、物流信息 等模块的管理能力和视图界面,一般是比较稳定的;而类似运营活动的功能和页面一般是经常变化的(520、618、双11),会有不同的活动策略和视图界面,需要经常迭代发布。如下图所示

2.3 基于可靠性拆分

2.3.1 核心模块拆分

我们团队在做MySQL数据库和Redis集群拆分的时候,总会把一些重要的模块独立放在一个集群上,不与其他模块混用,而这个独立的集群,服务机性能要是最好的。这样做的目的是,当重要度较低的模块发生故障时,不会影响重要度高的模块。

同要的道理,我们会将  账号信息、登录信息、服务中心等重要度最高的要害模块单独拆分在一个服务颗粒上(因为这类模块不可用之后,整个系统基本完全瘫痪),再做成服务集群,来保障它的高可用。 如下图所示:

2.3.2 主次链路拆分

在各个业务系统中,其实都会有主次业务链路。主业务链条,完成了业务系统中最核心的那部分工作。而次链路是保证其他基础功能的稳定运行。

以电商为例子:商品搜索->商品详情页->购物车模块->订单结算->支付业务,就是一条最简单的主链路。主链路是整个系统的核心主战场,最好的资源跟火力都要放在这里,保证不失守。

一个系统一般有多条核心链路和多条次链路,互相支持构成一个完整的系统。而我们将主次链路进行拆分,主要为了以下几个目标。

异常容错

为主链路建立层次化的降级策略(多级降级),以及合理的熔断策略,这部分我们将在Hystrix服务容错降级的文章中详细解释。

计算资源分配

主链路通常来讲都是高频场景,自然需要更多的计算资源,最主要的体现就是集群里分配的虚机数量多。比如电商场景中特惠专场抢购等。

但是无论是虚机的分配,还是kubernetes的动态扩缩容,应该都需要单独优待,如资源分配倾斜,独立治理等。

服务隔离

主链路是高频且核心的主业务模块,把主链路的服务与其他起辅助作用的业务服务隔离开来,避免次链路服务的异常情况影响到主链路服务。 

2.4 基于性能需求拆分

根据性能需求来进行拆分。简单来说就是访问量特别大,访问频率特别高的业务,又要保证高效的响应能力,这些业务对性能的要求特别高。比如积分竞拍、低价秒杀、限量抢购。

我们要识别出某些超高并发量的业务,尽可能把这部分业务独立拆分出来。这么做的原因非常简单,一个保证满足高性能业务需求,另一个保证业务的独立性,不互相影响。 

类似积分竞拍、超低价秒杀、限量抢购,对瞬间峰值和计算性能要求是非常高的。这部分的业务如果跟其他通用业务放在一块,一个是可能互相影响,比如某个链路阻塞,会导致雪崩沿调用链向上传递。

另外一个是如果多个业务耦合在一块,发布频率变高、服务扩缩容变难、维护复杂度变高。

3 总结拆分原则

  • 先少后多(微服务数量)、先粗后细(粒度)
  • 基于业务逻辑进行拆分(用户群体、业务领域等模型)
  • 基于可靠性(核心模块独立化、主次链路隔离)
  • 基于性能拆分(独立拆分高性能场景)
  • 接口需保证幂等
  • 接口数据定义严禁内嵌,透传
  • 规范化工程结构,符合微服务风格
  • 不止对计算服务记性拆分,服务层 -> 缓存层 -> 数据层 的逐步拆解,才能发挥最大功效。