好的架构不是买来的,也不是最开始就被设计出来的,而是在业务发展中,逐步演化过来的。项目刚开始,应抱着最小可用产品的理念,尽快作出最小可用产品,给客户使用获取反馈,而后基于反馈快速的迭代开发。在没有交付使用前,再好的架构都是假设,产品越晚使用,失败的风险和成本越高。程序员
在开发的初期,咱们对于服务的拆分,每每是根据产品或者是客户的需求,经过恰当的分层和包名来完成服务的拆分。数据库
这个也就是咱们一般所说的单一应用,在这个阶段,咱们一般会有以下几个准则:服务器
一、为了下降耦合,系统应进行恰当的分层,好比咱们常说的MVC。架构
二、用于增删改查的ORM框架是一个关键,一个好的ORM框架能大大提升咱们的开发效率。框架
三、一些基本的、通用的框架好比Spring应该被引入,为了考虑到之后新人的加入和持续的可维护性,咱们不该该使用一些冷门的框架。分布式
四、咱们会从需求中抽象出来一些关键名词、动词和属性,并对一些核心概念进行抽象,完成建模,并在团队内造成“通用语言”,咱们在团队的平常交流中都应该使用这些“通用语言”。工具
五、咱们应该有数据库和持续集成服务器,便于快速发布应用,必要时要引入代码审查工具。开发工具
在这个开发的过程当中,一切都有条不紊的进行,产品经理的需求能够很快获得了知足,更多的新同事加入进来,更多的功能也加入进来,全部人都对现状和架构很满意,由于这个单一的项目架构是如此的清晰、简单、高效。团队不大,交流也很是高效,你们配合的很默契。设计
但是好日子不长,产品经理有不少的想法,新的功能一个个被添加进去,代码变的很是臃肿,每次编译都须要花费很长时间。这时开始有人想到重构,在重构的过程当中,会把一些通用的代码封装成common项目,也可能把不一样的层,好比service层独立封装成一个项目。日志
但是随着新加入的员工愈来愈多,并非全部人都对全部的代码都很熟悉,构建时间愈来愈长,开发工具也慢了下来,代码变的愈来愈臃肿。开发速度也慢了下来,每次想增长一个新的功能,会发现代码之间纵横交错,不知道从哪里下手,为了快速实现需求, 无奈只能新增长一个接口,可能他并不知道已经有相似的接口存在,慢慢的增长了不少冗余代码。忽然有一个程序员,想把某一个功能重构,可是他翻看一下代码,发现有不少看不懂的业务,无奈他放弃了。随着愈来愈多的相似事情发生,最终没有一我的能清楚的知道系统是怎么运行的。
此时此刻,系统一般会面临以下几个问题:
一、开发速度慢,编译速度慢,代码之间耦合严重,每次开发一个新功能,均可能会牵涉到不少模块,在开发的过程当中有不少隐患很难排查。
二、项目过大,发版困难,在发版时,甚至可能须要停机。
三、业务复杂,新人接手困难,任何人都不敢轻易调整代码,随便调整一处,均可能影响到不少本身不知道的模块。
四、技术升级困难,团队对于新技术愈来愈保守,不敢随意引入新技术,会增长技术风险。
五、链接池之类的底层资源压力巨大,由于数据库是单点,在机器的横向扩展过程当中,数据库链接数过大。
假如你没有知足上述条件,博主并不建议去服务化,由于服务化有不少之前单点系统中没有碰见过的挑战,须要提早规划起来,好比通信、分布式事务、服务如何拆分以及拆分的粒度等问题。
如何进行服务拆分和重构
从我最近接手的项目为例。
这个项目的现状很是棘手,团队几乎都是新人,几乎没有一我的对系统是如何运行有清晰的认识,项目时间过长,开发过程当中没有文档,只能依靠代码中零星的注释。数据库表有近百张,至于真正用到了哪些表,没有一我的能说的清除。和外部系统之间调用模糊,不清楚此系统和外部系统是如何交互的。
在进行拆分和重构以前,咱们一般要作以下几件事:
一、须要先摸透全部的业务和数据库。
二、到底有哪些真实在使用的接口,能够依靠访问日志进行排查。
三、和以前参与过的同事进行充分的了解和沟通。
四、排查清楚和外部系统的关系,明确服务的职责和边界,在此过程当中须要结合业务进行划分。这个过程还须要协调对应的项目组,进行配合整改,外部协调可能会带来不肯定性,须要考虑这些服务是否要先上线。
五、肯定数据迁移方案,和产品进行沟通,肯定必需要迁移的数据,可能有一些数据并不须要迁移到新系统,或者能够经过其余方式进行解决。
拆分的目标
在重构时,咱们应该将系统中的独立业务模块抽取出来,按照业务的独立性进行垂直划分,抽象出基础服务层,抽象的目标是,每个基础服务层都是无状态的和去中心化的,能够弹性部署,可随着系统的负荷灵活伸缩来提供服务能力,这些基础服务都是经过底层中心系统发生关系的,好比配置中心、日志服务、消息服务、柔性事务服务等。这些基础服务会为上游业务系统提供支撑。
在进行服务化拆分时,咱们还须要考虑到的一个问题就是,组织沟通方式决定系统设计,这个主流的理论就是康威定律。咱们指望拆分后的服务能够减小协同、减小环节、提高效率。说的通俗一点就是,若是某个应用,须要多个组织之间一块儿交流和修改,那么它的交流成本就大于组织机构了,出现了不匹配的状况,那么这个应用就极可能太粗而须要拆分。
咱们能够将业务的流转过程画成图,先找出其中的名词和动词,每一个名词和动词均可能是一个服务。
在服务数量上的划分时,并无一个准则。服务过多,可能会致使划分过细,破坏业务系统之间的独立性,维护工做量变大,部署时占用内存多,并且定位问题困哪重重,还很难梳理服务之间的依赖关系,好比支付订单、退款订单,被划分红了两个服务。服务过少,可能没有实现很好的解耦,开发维护很差分工,升级影响面变大,好比一个服务要升级,会影响不少业务不可用。
通过服务拆分后,每一个服务一般都有本身独立的数据库,在数据库查询时,不要出现A服务中的SQL须要连接查询到B服务中的表等状况,这样在A服务与B服务进行数据的垂直拆库时就会出错。
在服务调用时,服务子系统间应该避免出现环状的依赖调用(好比A服务依赖B服务,B服务依赖C服务,C服务依赖A服务)。
在服务依赖上,服务子系统间的依赖关系链不要过长(不能超过3个)。
在拆分时,应该尽可能避免分布式事务,除非能够解决分布式事务,不然没法达到一致性。
从经验上来讲,初期应该根据业务划的比较大块,好比帐户模块和用户模块合成一个服务,交易和订单做为一个服务,大概分到3至5个服务,根据业务的发展状况,须要细分时再去分。
服务聚合
在拆分后,每一个服务都只对本身的业务负责,这些服务对外提供的接口粒度可能都比较细。但总会有一些复杂业务须要依赖多个服务才能实现业务需求。对于这个问题,以我这次重构的经验来讲,我会对每个业务系统(好比某一个App),都建一个对应的后台服务,复杂的需求、须要多个服务组合完成的需求会经过后台服务进行访问,依靠这个App Server完成服务聚合。