一、什么时候需要重构老系统
老系统重构,让大家又喜又悲,喜的是程序员,悲的是业务。
程序员为啥“喜”:多年前的老技术,以及各种历史原因导致的遗留代码、不需要的业务代码混杂在一起,维护起来,那个酸爽,我相信老司机都懂的。
业务为啥“悲”:业务会觉得一堆技术人重心都去发明新轮子,新需求迭代必然受挫。
那什么时候可以进行重构?本着技术需要领先业务“一小步”,综合成本和收益、boss意愿、业务的淡旺季、团队对新框架的掌握熟练度等因素,考虑清楚,方可计划和实施。
为了追赶业务的发展,笔者有幸成功主导过公司几个历史大系统的重构,接下来将讲述一个核心系统的重构之旅。
二、被重构系统的现状
此次重构的系统是10多年前的老系统,简单描述,有如下特征:
- 单体应用,200多张表,千万级别记录的表上百个,部分表记录已上亿;
- 要的和不要的业务功能都参杂其中,毕竟那个时候互联网群雄逐鹿,讲究天下功夫,唯快不破,没有严格实施“童子军规”,着实理解;
- 作为核心系统,外部系统千丝万缕,给人麻麻的感觉。
三、期望达到的目标
- 不影响业务的正常使用
- 不影响其他系统的正常调用和运行
- 技术架构从单体架构升级到微服务架构
因为微服务需要拆分数据库,即从一个大数据库里面,将本系统的表拆到新库,而且此次涉及跨机房(运维哥哥要求的)。
所以,技术上涉及数据迁移并升级,以及系统架构和代码升级两部分。
四、如何去重构为了达到目标,我的方法如下:
1. 不影响业务的正常使用即使用新架构,全新开发一个系统,数据库也使用新的(即将数据迁移并表结构升级),老系统和老数据库正常运行,等新系统开发部署好,再直接通过运维切换到新域名即可
2. 不影响其他系统的正常调用老系统之间交互方式梳理清楚,有两种方式:1)老接口不变,新系统继续兼容老系统的接口调用,比如是HTTP,Hession,RMI等;2)其他系统和本系统交互的部分,他们也愿意一起升级,就使用新接口方式,那是最好的,具体看场景
3. 技术架构从单体架构升级到微服务架构1)数据迁移并升级由于跨机房,源数据库数据量比较大(几百G),并且新库我们做了部分表结构调整,在保证老数据库不停机的情况下,我们使用了zookeeper+kafka+canal+otter等组件集群方式搭建,分两个阶段完成数据迁移,即存量数据和增量数据两阶段处理。
具体操作的流程图如下:
a:通过dump表打包,节约网络带宽,同时记录dump的位点A,方便后续作为增量的起始点;
b:中间备份库作为一个临时库,和新数据库在同一个服务器,这样DBA在临时库改造大表,不影响业务,改造好了,可以直接剪切到新数据库;如果涉及表拆分和复杂业务逻辑,就需要程序来做存量同步;
c:在存量都搞定后,再做老数据库从位点A到新数据库的同步,无业务逻辑,并且可以直接字段对应进行数据同步,使用otter解决,而有业务逻辑等,则使用canal解析bonlog,将数据存到kafka,再通过程序来消费kafka数据,将处理后的数据写入新数据库;
d:待新老数据库数据保持一致后,上线新应用系统,通过配置中心切数据库,并确保切数据后,数据表无“双写”存在。
值得提醒的是:
a:一般建议重构时,没有绝对把握,尽量不做表结构修改,因为这样需要搭建对系统本身的运转和业务的理解足够深入,至少各个字段的生命周期;
b:需要充分做好源字段和目标字段的仔细梳理和测试,这里有巨大的工作量;
c:有些表数据会有依赖,所以需要注意同步时表的先后顺序;
d:不要低估在大表上加新索引的时间(当然,如果能够提前做数据归档那是最好的)。
2)系统架构和代码升级
微服务我们按照业务功能竖切,以及通用非业务功能的横切,建议初期不要切太细,掌握一个度。
由于我们使用Spring Cloud这一套,网上相关资料都比较齐全,我就不详述了。
在这里,需要重点给大家分享做好系统功能分析,可以按内部和外部两个维度分析:
a:内部分析
- 内部功能的代码分析
- 梳理出在使用的表清单和业务逻辑
- 内部Job,含job调度中心和线上服务器各个用户下的cron job等
- 中间件的使用:MQ,Redis等
- 调用第三方的内容:外部翻译接口,支付接口等
b:外部调用分析
- 日志分析:access log等追踪访问的IP,追溯对应调用方
- 老数据库表访问来源分析:数据库上加日志分析JDBC直连
- 其他系统对调用API接口的追踪和梳理等
五、感想
重构老系统,犹如在高速公路上开车换胎:
所以,为了安全起见,建议大家做好以下内容:
- 事先尽量想明白重构的边界,是部分独立功能重构,还是整个系统重构;
- 并提前给业务打好预防针,争取上级领导们的大力支持;
- 并团队自身做好充分准备工作,分析工作,以及其他软技能,比如上下游系统沟通和协调等工作,都尽量做细,正如《孙子兵法》说:知己知彼,百战不殆。