首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

项目重构之服务拆分及粒度划分

业务系统实施微服务改造时,首先想到的就是如何拆分服务,原本的单个项目被拆分成多个项目,每个项目都是一个独立的服务,每一个服务都可以独立部署,服务之间可以互相调用,形成可以复用的服务,最大程度的避免在日后的开发过程中防止重复建设。

项目的腐化之路

在项目刚刚开始的时候,我们通常都是抱着最小可用产品的理念,尽快做出最小可用产品,丢给客户使用,快速获得客户或者用户的反馈,在反馈的基础上我们再快速的迭代开发。因为在没有交付使用之前,再好的架构也都只是假设,产品越晚使用,失败的风险和成本就越高,我们应该小步快走,通过持续迭代获取客户反馈,最大程度上降低失败的风险。一个好的架构不是买来的,也不是最开始就被设计出来的,而是在业务的发展过程中,逐步演化过来的。

在开发的初期,我们对于服务的拆分,往往是根据产品或者是客户的需求,通过恰当的分层和包名来完成服务的拆分。

这个也就是我们通常所说的单一应用,在这个阶段,我们通常会有如下几个准则:

1、为了降低耦合,系统应进行恰当的分层,比如我们常说的MVC。

2、用于增删改查的ORM框架是一个关键,一个好的ORM框架能大大提高我们的开发效率。

3、一些基本的、通用的框架比如Spring应该被引入,为了考虑到以后新人的加入和持续的可维护性,我们不应该使用一些冷门的框架。

4、我们会从需求中抽象出来一些关键名词、动词和属性,并对一些核心概念进行抽象,完成建模,并在团队内形成“通用语言”,我们在团队的日常交流中都应该使用这些“通用语言”。

5、我们应该有数据库和持续集成服务器,便于快速发布应用,必要时要引入代码审查工具。

在这个开发的过程中,一切都有条不紊的进行,产品经理的需求可以很快得到了满足,更多的新同事加入进来,更多的功能也加入进来,所有人都对现状和架构很满意,因为这个单一的项目架构是如此的清晰、简单、高效。团队不大,交流也非常高效,大家配合的很默契。

可是好日子不长,产品经理有很多的想法,新的功能一个个被添加进去,代码变的非常臃肿,每次编译都需要花费很长时间。这时开始有人想到重构,在重构的过程中,会把一些通用的代码封装成common项目,也可能把不同的层,比如service层独立封装成一个项目。

可是随着新加入的员工越来越多,并不是所有人都对所有的代码都很熟悉,构建时间越来越长,开发工具也慢了下来,代码变的越来越臃肿。开发速度也慢了下来,每次想增加一个新的功能,会发现代码之间纵横交错,不知道从哪里下手,为了快速实现需求, 无奈只能新增加一个接口,可能他并不知道已经有类似的接口存在,慢慢的增加了很多冗余代码。突然有一个程序员,想把某一个功能重构,但是他翻看一下代码,发现有很多看不懂的业务,无奈他放弃了。随着越来越多的类似事情发生,最终没有一个人能清楚的知道系统是怎么运行的。

此时此刻,系统通常会面临如下几个问题:

1、开发速度慢,编译速度慢,代码之间耦合严重,每次开发一个新功能,都可能会牵涉到很多模块,在开发的过程中有很多隐患很难排查。

2、项目过大,发版困难,在发版时,甚至可能需要停机。

3、业务复杂,新人接手困难,任何人都不敢轻易调整代码,随便调整一处,都可能影响到很多自己不知道的模块。

4、技术升级困难,团队对于新技术越来越保守,不敢随意引入新技术,会增加技术风险。

5、连接池之类的底层资源压力巨大,因为数据库是单点,在机器的横向扩展过程中,数据库连接数过大。

假如你没有满足上述条件,博主并不建议去服务化,因为服务化有很多以前单点系统中没有遇见过的挑战,需要提前规划起来,比如通讯、分布式事务、服务如何拆分以及拆分的粒度等问题。

如何进行服务拆分和重构

从我最近接手的项目为例。

这个项目的现状非常棘手,团队几乎都是新人,几乎没有一个人对系统是如何运行有清晰的认识,项目时间过长,开发过程中没有文档,只能依靠代码中零星的注释。数据库表有近百张,至于真正用到了哪些表,没有一个人能说的清除。和外部系统之间调用模糊,不清楚此系统和外部系统是如何交互的。

在进行拆分和重构之前,我们通常要做如下几件事:

1、需要先摸透所有的业务和数据库。

2、到底有哪些真实在使用的接口,可以依靠访问日志进行排查。

3、和之前参与过的同事进行充分的了解和沟通。

4、排查清楚和外部系统的关系,明确服务的职责和边界,在此过程中需要结合业务进行划分。这个过程还需要协调对应的项目组,进行配合整改,外部协调可能会带来不确定性,需要考虑这些服务是否要先上线。

5、确定数据迁移方案,和产品进行沟通,确定必须要迁移的数据,可能有一些数据并不需要迁移到新系统,或者可以通过其他方式进行解决。

拆分的目标

在重构时,我们应该将系统中的独立业务模块抽取出来,按照业务的独立性进行垂直划分,抽象出基础服务层,抽象的目标是,每一个基础服务层都是无状态的和去中心化的,可以弹性部署,可随着系统的负荷灵活伸缩来提供服务能力,这些基础服务都是通过底层中心系统发生关系的,比如配置中心、日志服务、消息服务、柔性事务服务等。这些基础服务会为上游业务系统提供支撑。

在进行服务化拆分时,我们还需要考虑到的一个问题就是,组织沟通方式决定系统设计,这个主流的理论就是康威定律。我们期望拆分后的服务可以减少协同、减少环节、提升效率。说的通俗一点就是,如果某个应用,需要多个组织之间一起交流和修改,那么它的交流成本就大于组织机构了,出现了不匹配的情况,那么这个应用就很可能太粗而需要拆分。

我们可以将业务的流转过程画成图,先找出其中的名词和动词,每个名词和动词都可能是一个服务。

在服务数量上的划分时,并没有一个准则。服务过多,可能会导致划分过细,破坏业务系统之间的独立性,维护工作量变大,部署时占用内存多,而且定位问题困哪重重,还很难梳理服务之间的依赖关系,比如支付订单、退款订单,被划分成了两个服务。服务过少,可能没有实现很好的解耦,开发维护不好分工,升级影响面变大,比如一个服务要升级,会影响很多业务不可用。

经过服务拆分后,每个服务通常都有自己独立的数据库,在数据库查询时,不要出现A服务中的SQL需要链接查询到B服务中的表等情况,这样在A服务与B服务进行数据的垂直拆库时就会出错。

在服务调用时,服务子系统间应该避免出现环状的依赖调用(比如A服务依赖B服务,B服务依赖C服务,C服务依赖A服务)。

在服务依赖上,服务子系统间的依赖关系链不要过长(不能超过3个)。

在拆分时,应该尽量避免分布式事务,除非可以解决分布式事务,否则无法达到一致性。

从经验上来说,初期应该根据业务划的比较大块,比如账户模块和用户模块合成一个服务,交易和订单作为一个服务,大概分到3至5个服务,根据业务的发展情况,需要细分时再去分。

服务聚合

在拆分后,每个服务都只对自己的业务负责,这些服务对外提供的接口粒度可能都比较细。但总会有一些复杂业务需要依赖多个服务才能实现业务需求。对于这个问题,以我此次重构的经验来说,我会对每一个业务系统(比如某一个App),都建一个对应的后台服务,复杂的需求、需要多个服务组合完成的需求会通过后台服务进行访问,依靠这个App Server完成服务聚合。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180624G1D68Z00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券