分享一个真实的重构案例
写在前面
想想为什么要做重构?
如果没有能说出来的理由,建议不要轻易重构。
机票系统A的现状
A系统的背景
业务上:从杭州挪到北京,作为重新孵化项目,想要做大做强。行业竞争压力非常大,做不出成绩,项目就会被毙。
技术上:遗留的老系统,在一个其他系统基础上改出来的单体,换手了四次团队,找不到一个了解这个系统的人了。
关系上:北京公司新成立,拿到这个项目,是作为一个大项目来做,也是要树立起标杆的项目。
当时我写的一封邮件,描述的这个系统现状。
国内机票旧系统开发于2006年,期间几十名开发人员在代码里留下了痕迹。不久前移 交到北京新业务研发团队维护,主要问题有: 1、代码量大(40万行),质量不高,结构复杂,难以修改和维护。一些代码的具体作用 和逻辑细节,没有人清楚。很多注释和代码不一致,文档缺乏,比较混乱。 2、业务处理过程逻辑复杂,中间数据冗余,与外部接口耦合度高,性能较差,稳定性 不高,扛不住大促活动压力。 3、对业务过程的数据和状态监控不足,难以管理控制和跟踪,各方使用不方便。 4、刚交接过来,没有人真正懂这个系统的业务,业务方也是空降,这个问题尤其严重
重构面临的压力和选择
当时看来,重做是最好的办法,但是不现实。
业务方:不能停止业务,否则死路一条
开发方:没有太多资源,且半年后大促。
只能选择在老系统基础上重构。
如何推动重构A系统
一个很常见的冲突点在于:
业务方觉得系统重构不带来业务价值,说不定还搞出点bug,是有风险的。
你一说其他的,他们就会说“反正还能用”。
对于重构各方都有自己的观点和要求。
对于业务方来说,要求如下:
- 业务不停
- 保障稳定
- 提升性能
- 快速开发
对于产品方:
- 提升用户体验
- 改版引流
- 其他同业务方
对于开发方:
- 资源得到倾斜
- 最大满足业务和产品需求,同时能够发展研发团队
最终各方达成一致,但是研发肯定是压力最大的。不用怕,在这种临危受命的同时,可以提要求,定规则。(如果初期不把这些要求提出来,中期再提就没那么容易满足了。)
本着这个目标,提出了如下要求:
- 所有其他项目为这个项目让路,最高优先级
- 资源主要用来保障这个项目,所有人配合,包括后面招聘的
- 人员管理等方面,特事特办,所有人不管考勤等制度
怎么定重构目标
平衡短期利益和长期利益
1. 分阶段
先重构搜索模块,然后是订单交易、产品库存。
搜索模块的目标主要有五个:
- 培养机票新人。梳理清楚国内机票搜索部分的业务和各种潜规则,培养懂机票的新 人。
- 提高代码质量。设计更合理,结构更清晰更易维护,系统耦合更低、扩展性更高。
- 提升搜索性能。使系统更稳定,更高效,搜索更快,资源消耗更低,大促不宕机。
- 监控搜索过程。统一管理搜索过程中的各种开关和参数调整,管理缓存,跟踪搜索 步骤。
- 国内机票搜索去oracle化。 在搜索重构的过程中,用mysql代替旧系统的oracle数 据库。
目标的具体说明:
-
培养新人问题,主要是XX\XX\XXX\XXXX。在此过程中,熟悉淘宝技术体系和开发 过程,掌握国内机票业务,能逐步的cover机票系统。
-
代码质量问题,主要是项目结构合理的分层,搜索的分段式处理,code review,高覆盖率的单元测试,使项目易懂易上手易维护。
-
提升性能方面,主要从简化中间结果和数据结构,理清业务简化旧逻辑,整理各步 骤缓存最大化合理利用缓存结果三个方向来提升系统在CPU计算和内存、以及网络 IO等方面的开销。提高系统吞吐量、QPS,降低响应时间。
-
监控搜索过程,通过哈勃、timetunnel+ateye、memlog、系统log等手段埋点,管 理系统多种粒度的开关和参数设置,跟踪和调试搜索流程中的数据和状态、各种外 部接口数据和缓存。
-
去Oracle,改用mysql+tddl,实现分库分表,为进一步的分布式架构打下基础。
2. 变组织
- 架构师主力,长期大办公室开发,负责核心和全流程
- 其他后备力量,负责业务模块+迭代周期
- 开发期间,试行996(算加班调休),抢在年底大促前完成重构
重构的过程
第一步:规划
确定规划,分步改造。
启动项目,拉齐思想。
- 上线启动10/11
- 灰度发布10/20
- 功能发布10/27
- 全部提测11/08
- 所有上线11/29
- 机票大促12/21
第二步:明确业务
- 重建业务需求稳定,需求是一切的起始点。
第三步:架构调整
分层改造和逐步对接。
所谓分层改造:就是当时我们的系统分为contrller-> ao -> service -> dao -> db
我们可以改造dao层和db层,将oracle换成mysql,service原有的不动,新创建一个实现类,接新的dao层。这样老的和新的实现都有,可以随时切换。
在一个需求周期内,完成业务需求的同时,搭车发布技术改造。
3.1 性能优化
- 从优化业务处理角度。同步大事务到小事务,异步处理
- 从优化系统代码角度。多层for循环的优化
- 从优化数据结构角度。优化掉一个笛卡尔积
- 从优化缓存策略角度,从静态的缓存时间到动态计算缓存时间。
3.2 引入标准
借鉴之前的ESB经验,解决对接的复杂性问题,标准化集成方式。
不同航司的接口,差异非常大,数据结构也不同,数据的有效性也不同。
原有的外部对接与业务系统耦合严重,对接方式也是五花八门。抽离出一个标准规范,做一套ACS系统来专门对接外部航司的接口。支持更好的横向扩展和维护性。
3.3 灰度发布
通过灰度发布+特性开关,保障可靠上线。
先是预发环境上线,办公室内访问。然后线上灰度,公司内部IP访问。再接着杭州和北京访问。最后全国访问,完全放开。
3.4 监控运维
实现一套全方位的运维系统,快速发现和处理问题。实现线上开关和debug的机制,快速定位问题。对每天的业务数据进行自动统计和发邮件,做到所有人对业务情况了然于心。
最后的效果:
- 业务上,支持了大量新功能,包括营销促销系统
- 技术上,重构了新系统,完成了去O和分库分表,保证了大促
- 产品上,优化用户体验,补齐系统的功能短板
- 团队上,培养了一批懂业务,懂新系统底层的核心研发人员。
新系统文档完善,架构先进,代码只有旧系统1/3不到,性能提升30倍。
(注:以上案例是秦金卫老师的真实重构案例)