拆分策略可以按功能和非功能维度进行考虑,功能维度主要是划分清楚业务的边界,非功能维度主要考虑六点包括扩展性、复用性、高性能、高可用、安全性、异构性。接下来详细介绍下。
1、功能维度
功能维度主要是划分清楚业务边界,采用的主要设计方法可以利用 DDD(关于 DDD 的理论知识可以参考网上其它资料),DDD 的战略设计会建立领域模型,可以通过领域模型指导微服务的拆分,主要分四步进行:
第一步,找出领域实体和值对象等领域对象。
第二步,找出聚合根,根据实体、值对象与聚合根的依赖关系,建立聚合。
第三步,根据业务及语义边界等因素,定义限界上下文。
第四步,每一个限界上下文可以拆分为一个对应的微服务,但也要考虑一些非功能因素。
以电商的场景为例,交易链路划分的限界上下文如下图左半部分,根据一个限界上下文可以设计一个微服务,拆解出来的微服务如下图右侧部分。
举一个典型的电商业务例子。电商的业务体系庞大,涉及各方面的细节。但是我们大概能够根据业务的职能做一个拆分,比如阿里的电商中台业务,包含 用户账号子系统、商品子系统、订单子系统、客户子系统、物流子系统 等。
因为职能不同,这些领域之间包含清晰的界限,所以我们可以按照这个方向将服务于不同领域(商品域和订单域)的子系统拆成独立的服务颗粒。如下图:
2、非功能维度
当我们按照功能维度进行拆分后,并不是就万事大吉了,大部分场景下,我们还需要加入其它维度进一步拆分,才能最终解决单体架构带来的问题。
1)扩展性
区分系统中变与不变的部分,不变的部分一般是成熟的、通用的服务功能,变的部分一般是改动比较多、满足业务迭代扩展性需要的功能,我们可以将不变的部分拆分出来,作为共用的服务,将变的部分独立出来满足个性化扩展需要。同时根据二八原则,系统中经常变动的部分大约只占 20%,而剩下的 80% 基本不变或极少变化,这样的拆分也解决了发布频率过多而影响成熟服务稳定性的问题。
比如一个电商领域的系统,用户信息、基本商品信息、物流信息 等模块的管理能力和视图界面,一般是比较稳定的;而类似运营活动的功能和页面一般是经常变化的(520、618、双11),会有不同的活动策略和视图界面,需要经常迭代发布。如下图所示
2)复用性
不同的业务里或服务里经常会出现重复的功能,比如每个服务都有鉴权、限流、安全及日志监控等功能,可以将这些通过的功能拆分出来形成独立的服务,也就是微服务里面的 API 网关。在如,对于滴滴业务,有快车和顺风车业务,其中都涉及到了订单支付的功能,那么就可以将订单支付独立出来,作为通用服务服务好上层业务。如下图:
3)高性能
将性能要求高或者性能压力大的模块拆分出来,避免性能压力大的服务影响其它服务。常见的拆分方式和具体的性能瓶颈有关,例如电商的抢购,性能压力最大的是入口的排队功能,可以将排队功能独立为一个服务。同时,我们也可以基于读写分离来拆分,比如电商的商品信息,在 App 端主要是商详有大量的读取操作,但是写入端商家中心访问量确很少。因此可以对流量较大或较为核心的服务做读写分离,拆分为两个服务发布,一个负责读,另外一个负责写。还有数据一致性是另一个基于性能维度拆分需要考虑的点,对于强一致的数据,属于强耦合,尽量放在同一个服务中(但是有时会因为各种原因需要进行拆分,那就需要有响应的机制进行保证),弱一致性通常可以拆分为不同的服务。
根据性能需求来进行拆分。简单来说就是访问量特别大,访问频率特别高的业务,又要保证高效的响应能力,这些业务对性能的要求特别高。比如积分竞拍、低价秒杀、限量抢购。
我们要识别出某些超高并发量的业务,尽可能把这部分业务独立拆分出来。这么做的原因非常简单,一个保证满足高性能业务需求,另一个保证业务的独立性,不互相影响。
4)高可用
将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。具体拆分的时候,核心服务可以是一个也可以是多个,只要最终的服务数量满足“三个火枪手”的原则就可以。比如针对商家服务,可以拆分一个核心服务一个非核心服务,核心服务供交易服务访问,非核心提供给商家中心访问。
5)安全性
不同的服务可能对信息安全有不同的要求,因此把需要高度安全的服务拆分出来,进行区别部署,比如设置特定的 DMZ 区域对服务进行分区部署,可以更有针对性地满足信息安全的要求,也可以降低对防火墙等安全设备吞吐量、并发性等方面的要求,降低成本,提高效率。
主链路是高频且核心的主业务模块,把主链路的服务与其他起辅助作用的业务服务隔离开来,避免次链路服务的异常情况影响到主链路服务。
6)异构性
对于对开发语言种类有要求的业务场景,可以用不同的语言将其功能独立出来实现一个独立服务。
以上几种拆分方式不是多选一,而是可以根据实际情况自由排列组合。同时拆分不仅仅是架构上的调整,也意味着要在组织结构上做出相应的适应性优化,以确保拆分后的服务由相对独立的团队负责维护。