微服务拆分实践

说到微服务就不得不说拆分了,服务拆分要有一些指导依据。

拆分依据

微服务的理论知识有大量的分享,这里是我对微服务理论基础认识的一些观点:

  • 小,且专注于做一件事情,即满足 单一职责原则 。 关于单一职责可以阅读我的另一篇文章 《软件开发中的单一职责》

  • 运行在独立的进程中。

  • 轻量级的通信机制,RPC或者HTTP或者MQ。

  • 松耦合,独立部署。

  • 康威定律:设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。

服务拆分依据结合上面的理论基础充分考虑了以下因素:

  • 业务和领域模型

  • 技术、业务量等其他因素

  • 团队

业务应该说是最实在的,也是最好理解而且最容易把握的。虽然领域的有界上下文从理论上能指导拆分,但是万万需要拆分的不是一个全新的系统,而是一个在线上稳定运行了很长时间的,很多人一砖一瓦堆砌起来的,并且仍然在持续添砖加瓦,不管是桥梁,还是高楼,我们的目的是让系统运行的更健壮,而不是拆成七零八碎,所对于这样的老系统,用领域拆分需要结合团队现状,理论结合实际,事半功倍。

运行时隔离也是很重要的拆分依据,会根据一些具有特定功能的API单独拆分出来作为一个微服务,和其他微服务隔离,避免相互影响,避免一个老鼠害了一锅汤。比如一些文件上传一类的API,特征是响应时间长,对IO依赖比较多,其线程池需要特殊配置;比如多线程利用CPU来换取响应时间的等等。

对于康威定理,究竟是团队影响拆分,还是拆分影响团队,那就需要均衡利弊了。如果是因为拆分微服务,而拆分了团队,那势必会影响到团队的稳定性和团队成员的归属感,尤其是一个组建很久的老团队。反之,团队负责多种业务,也没有明显的职责区分,就要考虑是否拆分团队,明确拆分后的团队职责。

对于正在运行的系统,如何拆分和拆分为多大的粒度,事实上是不能有太过理论化理想化,更需要深入项目本身和该项目团队,了解业务,人和代码。不能是拆迁队,也不是修缮,应该是拆成各种形状的合理大小的积木。

孰重孰轻很难说明白,团队不一样项目不一样,实践就不一样,找到适合自己团队的方法。

拆分粒度

拆分粒度不应该过分追求细粒度,要考虑适中不能过大或过小。按照单一职责原则和康威定律,在业务域、团队还有技术上平衡粒度。拆分后的代码应该是易控制,易维护的,业务职责也是明确单一的。

拆分过程实践

在拆分过程不得不考虑的是业务在跑,砖在砌,不能停,而且拆分工作也必须得进行,过程上不能一部到位,必须一步一步走,也由于此拆分后落地上线也要稳妥。所以,过程上,我也采用了比较稳妥的战术, 先拆分为maven module,然后在拆分为微服务可部署构件 。这样的好处是,拆分过程不影响业务迭代,而且可以随意组合成单体应用和微服务app,并且还可以事先测试和验证拆分,最大限度的降低微服务化实施的风险。

下面是拆分代码过程实践经验:

1). 设计module骨架

module骨架的设计是基础,影响最终拆分结果,拆分成功的向导。按照技术,业务,部署打包,测试这几个维度来规划设计,下面是一个参考。

最终骨架模型:

root web app
 webapp //war module,打包为单体war,整体部署
 micro-services //微服务pom module
 user-service
 customer-service
 order-service
 other-service
 api-gateway
 biz //业务相关的module
 entitys //所有实体类
 biz-base //一些无法拆分的代码上有依赖的服务
 biz-user //用户业务
 biz-customer //客户业务
 biz-order //订单业务
 ... 
 commons
 async-framework //一部框架
 utils //工具类

2). 拆分技术commons

作为第一步,先对整个工程按业务和功能进行了maven多module的拆分。拆分过程没有技巧可言,一步一步走,一步一个脚印。首先是分离出技术上的commons,感觉这应该是最好拆分的了,把相关的类重构到一个包里,在分离出一个module即可。实际过程并非如此,因为是老项目,这类commons也并没有想象的容易,经过很多人的添砖加瓦,并没有完全按照 单一职责原则 来砌,根本就是把业务特征的代码也放到了技术类代码中,不过review代码后感觉还好,微遵循的毕竟是少数,那就先重构代码,把业务特性的砖从类里移出去。

3). 拆分entity

很多在业务代码上都会共享entity类,通常没法也没法把entity类分门别类,最简单就是把所有的entity类放到一个module,谁需要谁依赖的原则。entity类也没有太多jar依赖和业务依赖,也不会形成污染源。

4). 公共业务

同commons和entity方法,不在复述,也被各个业务依赖,这种业务大部分是过渡性的,在未来迭代演进时可以通过其他方式抽象集成。

5). 拆分业务代码

拆分业务是最痛苦的事情了,这个要看原来的代码整洁度和互相依赖程度,一般采取2中方法:

  • 新建业务module,加入基础module的pom依赖,再从源module复制和该业务module相关的代码(包括单元测试代码)过来,解决编译错误和单元测试错误,完成本业务拆分。

  • 从源module复制一个新业务module,保持代码一致,先删除和本义务无关的代码(包括单元测试代码),再删除无关的pom依赖,解决编译错误和单元测试错误,完成本业务拆分。

选择哪种方法,可以根据代码整洁度和互相依赖程度,如果代码很整洁且相互依赖较弱,可以采取前者,否则就采取后者。

6). 拆分微服务

有了以上的拆分基础,可以在合适的业务迭代将各个微服务module迁移到不同的代码仓库,完成进一步隔离管理。

文章标签: 微服务


关注微信公众号“架构说”,加入Q群微群,让架构师带你飞︿( ̄︶ ̄)︿。


原文链接: 阅读原文
免责申明: 架构说任何转载的文章都会明确标注原文链接。如有侵权,请与本站联系。
转载说明: 架构说原创文章转载时请务必注明文章作者、链接和来源。