遗留系统的定义
- 维基百科定义:遗留系统是一种旧的方法,旧的技术,旧的计算机系统或者应用。(没有反应出遗留系统的本质)
- 重新定义:是一个还在运行和使用,但已步入软件生命周期的衰老期的软件系统。它符合所谓的奶牛规则:奶牛逐渐衰老,最终无奶可挤,然而与此同时,饲养成本却在上升。
遗留系统产生的原因
- 开发人员的工作目的是为了积累经验而非构建软件
- 学习新事物很有趣
- 时尚
- 今日时尚,明日老套
- 喜新厌旧
- 不必要的依赖和过于紧密的耦合
- 不必要的复杂架构
- 编程语言中的不必要的部分
- 不限制开发人员
- 没有模块化的软件以及没有范围限制的模块
软件应该拥有一位架构师和技术主管,长期负责保护该软件。这位架构师应该在选择技术与处理技术变更时,做出谨慎而明智的决策。这位架构师应该确保软件的模块化,还要确保每个模块只包含结构和编程语言必要的依赖性和复杂程度。从事这些模块开发的工作人员应该了解模块的范围并遵循范围要求。而这位技术主管可以主要通过代码审查以及静态分析来强制执行这些要求。
遗留系统的特点
- 耦合严重
- 升级或者新增困难
- 代码不规范,难于阅读,复杂度高
改造原则
- 少修改代码
- 尽可能的不影响业务
实施误区
重写遗留系统
直接重写遗留系统可行么?遇到遗留系统的改造问题时,不少人可能会首先想到一个直截了当的方案:推翻重写,用全新的系统一次性替换掉遗留系统。采用这种方式,在落地过程中总会发现种种问题,导致新修缮者模式系统无法顺利切换,旧系又无法完全替代。常见的问题有以下几种:
- 上线困难,业务阻塞风险高:在遗留系统重写的过程中,往往会有新增需求对遗留系统的功能进行修改。在新系统未上线前,这些需求要么被阻塞,要么需要付出双倍的工作量在遗留系统和新系统上同时实现,无论哪种选择对团队都是很难接受的。
- 影响面不可控,系统改造周期长:遗留系统往往运行着关键业务或者持有核心数据,会被多个上层服务所调用。一旦决定开始重写,其影响面无法评估,需要极为小心,考虑周全,客观上会造成系统改造周期被无限期拉长。
- 学习成本高,知识传递周期长:遗留系统的改造周期越长,对系统的学习成本就会随之升高。在这个过程中随着人员的正常流失,团队对业务和技术的熟恐程度会逐渐降低,而新人需要花费更多的时间才能熟恶遗留系统改造过程中必要的知识和技术。
寄希望于直接重写遗留系统,进行一次性替换而解决服务改造问题是不现实的,必须探素一条能够持续可演进的道路,实现快速、低成本、影响面可控的改造效果。
遗留系统改造策略
稳健策略-量力而行
- 项目时间有限,跨度中等,以月计
- 投入有限,预算有限
- 技术风险中等,采用成熟技术加少许新技术,难度中等
- 团队技术水平要求略高
激进策略
- 时间充裕跨度长,以年计
- 投入大,需要耗费高预算
- 技术风险高,采用新技术,试错成本高,难度大
- 团队技术水平要求高
保守策略
- 项目紧张跨度短,以周计算
- 投入少
- 局部优化,技术风险小
- 团队技术水平要求略低
实施方法论
绞杀者模式(抽象层):通过逐步替换而非一次性替换的方式,来保证新旧系统的平滑过渡。逐渐用新的应用程序和服务来替代特定功能。创建一个门面,拦截后端遗留系统的请求。门面将这些请求路由到旧应用程序或新服务。现有功能可以逐渐迁移到新系统,消费者可以继续使用相同的接口,不会感知到迁移的发生。
- 考虑新系统和遗留系统之间的数据共享或者同步方式。
- 在微服务中,要确保绞杀者门面服务(即抽象层)不会出现单点故障或成为性能“瓶颈”。
这种模式有助于最大限度地减少迁移的风险,并随着时间推移扩大开发工作。通过门面安全地将用户路由到正确的应用程序,可以以任何喜欢的速度向新系统添加功能,同时确保旧应用程序继续运行。随着时间的推移,功能迁移到新系统,遗留系统最终被“绞杀”,不再需要。 一旦这个过程完成,遗留系统就可以安全地退休。
修缮者模式: 就如修房或修路一样,将老旧待修缮的部分进行隔离,用新的方式对其进行单独修复。修复的同时,需保证与其他部分仍能协同功能。
通过识别内部的被拆模块,对其增加接口层,将旧的引用改为新接口调用;随后将接口封装为API,并将对接口的引用改为本地API调用;最后将新服务部署为新进程,调用改为真正的服务API调用。
抽象分支,同于绞杀者
防腐层:在新的应用程序和依赖于其的遗留系统之间实现装饰层或适配器层。该层转换新的应用程序和遗留系统之间的请求。 使用此模式可确保应用程序的设计不受依赖的旧系统的限制。通过在遗留系统和现代系统之间使用防腐层来隔离它们。该层转换两个系统之间的通信,允许遗留系统保持不变,同时可以避免损害现代应用程序的设计和技术方法。现代应用与防腐层之间的通信始终使用应用程序的数据模型和架构。从防腐层到遗留系统的调用都符合该系统的数据模型或方法。 防腐层包含两个系统之间转换所需的所有逻辑。该层可以作为应用程序中的组件或作为独立服务来实现。
- 防腐层可能会增加在两个系统之间进行调用的延迟。
- 防腐层添加了必须进行管理和维护的附加服务。
- 考虑防腐层如何伸缩。
- 考虑是否需要多个防腐层。你可能希望使用不同的技术或语言将功能分解成多个服务,或者因为其它原因来分割防腐层。
- 考虑如何根据其它应用程序或服务来管理防腐层。如何将其集成到监控,发布和配置过程中?
- 确保事务和数据的一致性得到维护并可以监控。
- 考虑防腐层是否需要处理遗留和现代系统之间的所有通信,或只是功能的一个子集。
- 考虑防腐层是否是为永久性的,或者是在所有旧功能都迁移后最终退休。
网关隔离:使用一个端点将请求按照路由分发到多个服务上去。该模式用于希望将多个服务通过一个单独的端点暴露出去,并将请求按路由分发给适当的服务时。
- 网关服务可能会引入单点故障。确保在设计时就考虑到可用性需求。在实现时考虑可恢复性与故障容错能力。
- 网关服务可能会成为瓶颈。确保网关具有足够的性能以处理负载,并能够容易随着预期增长一致扩展。
- 对网关进行负载测试,以确保你不会为服务引入级联性故障。
- 网关路由位于第7层。可以基于IP、端口、header或URL来实现。
遗留系统进行微服务拆分
48字箴言的微服务拆分核心价值观
功能剥离,数据解耦
自然演进,逐步拆分
小步快跑,快速送代
灰度发布,谨慎试错
提质量线,还技术债
各方一致,过程透明
拆分方法
服务拆分
- 水平拆分(功能维度)
- 垂直拆分(业务维度)
数据库拆分
- 水平分表
- 垂直分库
拆分带来的技术挑战
- 分布式事务数据一致性的问题
- 微服务基础设施
- 自动化运维
- DevOps文化
- 分布式系统带来的复杂性
遗留系统改造技术方案
- 基于zuul网关动态路由方案实现老系统和新系统的动态切换平滑升级,逐步改造推进。
- 前后端分离
- 跨域处理
- 统一认证授权
相关设计模式
- 模板方法模式:抽象公共业务逻辑
- 策略模式解决 if else 问题
- 观察者模式解耦
参考文献
- 本文参考自网络知名开发者:二康
- Top 10 Reasons Your Software Became Legacy
- 从300万行到50万行代码,遗留系统的微服务改造
- 最头疼的遗留系统该如何改造
- 《遗留系统重建实战》
- 《重构》
- 《代码修改的艺术》
- 云设计模式