这种方案的优点是可以通过API隔离数据变化,避免新业务服务与原遗留系统数据之间的直接耦合。可以在API中实现对数据的处理逻辑,满足新业务服务的数据需求。API只对外提供新业务服务允许访问的数据域,从而实现数据权限的控制,更适用于数据库直接访问受限制的场景。但其引入的额外成本是需要在原遗留系统上增加API实现的工作,有时因为遗留系统的技术陈旧、结构复杂等原因,会使得这部分工作比较难于执行。
方案B:新业务服务持有数据,通过数据同步解决数据依赖问题
不难看出,方案A中的方法多多少少都对原系统有一定的侵入性,或与原数据库直接耦合,或需要对原遗留系统进行修改。面向对象设计原则中的“开闭原则”,即“对扩展开放,对修改封闭”,可以帮助我们实现灵活可扩展的软件架构,在这里也同样适用。因此可以考虑在原有系统基础上进行扩展,而不是直接修改原遗留系统,于是诞生了另一个方案:新业务服务持有数据,通过数据同步解决数据依赖问题。
适用场景:不允许新业务访问遗留系统的共享数据,或者数据库分离成本不高。
实现方案:具体实现方法是建立独立的数据库供新业务服务所使用,而新数据库与遗留系统数据库之间通过一个专门的数据同步服务进行同步,将新数据库中的数据转化为与遗留系统数据可兼容的形式,并迁移过去。数据同步服务又称ETL(Extract、Transform、Load)服务,其主要职责是读取、转换和同步数据,如图6-9所示。
图6-9改造场景2:通过ETL进行数据同步
该方案的优点在于使用了独立的数据库,对原遗留系统的侵入性较低,新业务服务持有新的数据库,与原遗留系统解除了直接耦合,新业务服务和新数据库的选型都可以比较灵活。所有新旧数据之间的转换逻辑都在ETL服务中实现,以后任何数据转换与同步的逻辑变化都只与ETL服务有关,无须再去修改原遗留系统和新业务服务。但该方案带来的成本是需要额外实现一个ETL服务。另外由于需要在独立的两个数据库之间进行同步,可能只能满足数据的最终一致性而无法做到强一致性。另外也要考虑ETL服务的可用性,避免引入新的单点故障。
如果进一步考虑到数据隔离问题,避免直接暴露新服务的数据库数据,还可以让ETL服务通过新业务服务的API来访问数据,如图6-10所示。这种方案进一步解除了ETL服务与新业务数据库之间的耦合,新增的API还可以进一步被复用,作为其他服务消费者访问数据库的接口。
图6-10改造场景2:通过ELT访问新业务服务的API进行数据同步
改造场景3:对现有业务微服务化
大多数遗留系统在单体应用架构下已经承载了许多关键业务或持有核心数据,对其进行微服务化改造时,一次性的重构风险是比较大的。因此,更为提倡通过数次小的重构来逐步实现微服务化改造。
适用场景:对遗留系统承载的现有业务微服务化,实现渐进式的重构。
实现方案:以一个含有多模块的单体应用遗留系统改造为例,通过以下三个步骤拆分为业务数据分离的两个服务。
1.将内部代码调用修改为本地REST接口调用:将被调函数修改为REST接口暴露出来,调用者模块通过对本地REST接口调用完成与原有业务等价的功能。此时还未拆分服务,仍然是作为一个服务整体上线。
2.将本地REST接口调用改为服务间REST接口调用:拆分服务,将原有的调用者模块拆分为独立服务,REST接口调用地址改为目标接口所在的服务地址。这一步接口变动的成本相当小,重点在于让拆分后的服务能够独立部署与上线。同时,为避免一次引入过多变更,此阶段拆分后的服务仍然直接访问原数据库的共享数据。
3.业务数据分离:将拆分后的服务所需的数据分离出来,作为新服务的独享数据库所持有。两个数据库之间的数据依赖问题,可以借前文所述的数据同步方案(ETL服务)解决。
按照上述过程,根据需要不断迭代,将原遗留系统的业务逐步微服务化,总体过程的示意图,如图6-11所示。
图6-11改造场景3:对现有业务微服务化