前沿
本重构文档仅是本人在项目重构时的汇报文档,如有不当之处欢迎指正。后期还有个重构后性能对比有机会我也会贴出来。在此记录也是为了方便自己以后查证,温故,希望对有需要的朋友有帮助。
1、背景
A 项目现有系统架构继承于外包公司、导致整个系统架构比较落后、臃肿引入很多没必要模块、模块之间耦合度太大无法进行拆分和搽出无关的模块。导致开发、升级、发布比较痛苦。
项目管理后端、APP医生端、APP患者端整个代码交织在一起,无法做到单独功能、模块的升级、部署。往往会出现解决一个Bug又引入更多的Bug。
2、原有架构
从系统架构图上看、此系统是一个类SOA服务的简化本、大家看着也比较熟悉
整理架构让看着也不是太落后但是代码实现让人看着非常怀旧、里面使用大量的使用落后技术分装的比较臃肿的类库。整个系统架构使用N年以前封装的一些臃肿的类库硬堆成SOA服务架构,里面还是MVC架构。
2.1、原架构的存在问题
2.1.1 DAO
DAO使用自己分装一个大而全的数据库访问操作。优势(对于外包)一个Jar解决所有的第三方ORM框架。缺点是项目变得臃肿、垃圾代码耦合度太大无法升级。
2.1.2 Service
业务逻辑为Controller层提供具体业务的实现。但在实现上、问题很多。如果是严格按照分层架构来实现、对业务逻辑层进行拆分、将本地调用变成远程调用、即可比较容易拆分、但实际中遇到如下问题。
业务层往往未实现单向依赖、部分业务逻辑层实现被注入了接口层的参数(request、response)或者直接在接口层来实现、使其和接口层的耦合的增加。
为了应为不但变更的需求、不少接口使用map作为输入输入参数、此类接口在维护时无法约束其参数。
Service层绝大部分操作使用PO对象来作为数据处理对象,未对业务实体建模。这个层的实现是不完整。这使的对业务实体的操作需要推迟到Controller层来实现、导致Controller臃肿。
当服务之间存在大量依赖关系时,开发人员往往会直接将Spring BeanFactory注入到各个服务中,或者简单封装一个FacadeService,通过这个Service可以访问到所有的业务逻辑对象。这个类的使用导致无法评估Controller层对Service业务对象的具体依赖。
2.1.3 Controller
Controller层承担了大量的业务逻辑使其臃肿、难以测试。
2.2功能问题
从整个系统上看、系统并没有区分、APP患者端、医生端、系统管理、使其代码完全耦合在一起、只是实现了功能、完全没有考虑可用性和扩张性。
3、实施问题
3.1可扩展性和性能提升困难
应用性能瓶颈基本都在数据库上。这个系统使用mysql作为数据库。三个应用对应一个数据库。读写都在一个库上操作。
3.2系统臃肿、学习周期长
500多个接口,全在一个项目中。项目最多有1000多个类,可用类大概在300左右、存在大量的僵尸类。Nginx前置路由。路由这个让人欣慰,它是整个重构工作的有力支撑。纯后端的项目,为移动端app,PC,WEB应用提供接口。
三个应用的的所有代码全部交杂在一个臃肿的系统中、业务逻辑混难导致开发人员不敢去碰现有的代码、修改一个小功能可能会导致整个系统的崩溃。
3.3合作成本
随着项目组人员增加,每次新版本开发都需要多人一起合作,修改同一个项目代码。虽然使用版本控制工具来对分支进行管理,但是不可避免的,大量的时间花费在代码冲突处理上。新增功能,增强功能,bug修复,支持各种客户端,都在一个项目上进行,需要建立不同的分支,高峰期五六个分支同时进行都是常见的。这种情况下,代码冲突的频率非常高。一个周的小版本开发,1天时间在解决冲突都是很正常的。
3.4测试难度
测试工作也逐步的恶化了。测试环境构建难度高。随着分支的增加,每个进入测试的分支,都需要准备独立的测试环境。环境构建成本高。刚测试完的功能,由于分支合并冲突处理,又得重新跑一遍。严重影响项目进度
3.5上线风险高
随着系统复杂度的增加,上线风险也越来也大。一个小功能的修改,打印一个日志,修复一个bug,都需要整体上线。一旦有一个地方修改错了,这个系统就崩溃了。上线时间长,一次上线,半个小时是必须的。
3.6引入新技术难度大
公司对新技术的追求和使用显得特别饥渴、这种生搬硬套的架构伪SOA架构降低了开发成本,但是对屏蔽了其它技术的导入。
很长一段时间这个系统都是由一位同事在维护和开发、对外接口全部混杂在一起,访问量也不大、开发人员完全是在本地开发、出现问题首先想到的是打补丁、而不会考虑是否结束这种混乱的架构而去从新构建系统。而当公司做业务调整,人员迅速增加后,原有的方式,就需要变更了。这就应了所谓的康威定律。
4、重构思路
根据现有系统的遇到问题,我们现在使用微服务架构来从新重构整个项目的架构。根据微服务的特性其可以解决上诉所有问题。
性能问题:对性能要求高的接口可以建立缓存来优化接口。
学习周期:一个项目仅包含少数紧耦合的接口、接口业务单一、开发人员1-2小时就可以同读代码、即可上手。
合作成本:每个项目相对独立,项目之间仅通过接口来交互。确定完接口后,开发、测试、上线,都是独立进行的,从而降低了沟通成本。
版本控制:由于项目之间是接口依赖而不是代码依赖,每个项目都可以建立独立的代码库。同时项目切分的比较细,每个项目开发时,仅会有一个开发人员对其做修改。这基本就不存在代码合并工作,也避免了代码合并过程中的各种问题。实际上,基于微服务架构的开发,我们并没有采用分支策略,而是直接用主干开发。
测试难度:每个项目独立部署、独立测试。由于消除了代码分支,没有代码合并的隐患,重复测试的工作量减少了。
上线风险:每个项目独立上线,就算出现问题了,也仅影响到少数接口。
新技术:在微服务改造进行中,各种新技术将被引入到系统中,开发不再局限于简单架构。集群、分布式、限流、降级、容错、Redis等缓存系统,都开始在项目中使用,并有效地解决的业务上存在的问题。
4.1现有业务拆分
根据现有业务进行梳理后、将整个系统进行拆分为:
API网关(gateway-server)
统一权限服务(auth-server)
医生聚合服务(doctor-consumer-server)
患者聚合服务(patient-consumer-server)
管理系统聚合服务(system-consumer-server)
用户基础服务(user-provider-server)、
医生基础服务(doctor-provider-server)、
资源基础服务(resource-provider-server)
患者基础服务(patient-provider-server)
消息基础服务(msg-provider-server)
注册中心(eureka-server)
4.2基础架构
4.3逻辑架构
4.4 排期
……