如何完成应用上云方案设计

对于复杂应用系统来说,单体应用架构代码复杂度高、可扩展性差、业务开发及部署周期慢,不能满足现业务发展需要。对于业务复杂的单体应用系统上云需求,我们建议以微服务化重构改造上云。
核心问题
服务拆分
如何将单体应用进行服务化改造,是“一步到位,推倒重来”还是“循序渐进的蚕食”,选取哪些功能或业务进行服务化改造,如何减少对原单体应用的修改等,这些都是在服务拆分时首要面对的问题。
跨服务查询
单体应用里实现查询相对简单,因为具有统一的数据库。但在微服务架构下,一个查询可能需要检索分布在不同的服务中数据,而这些服务都会拥有自己的数据库。传统的分布式数据查询机制不适用,因为会打破服务之间的数据隔离性,该隔离性要求以服务的形式提供数据,不能直接暴露数据库。
改造原则
渐进式,不要“推倒重来,一步到位”
快速见效、快速收到回报、可挑选出高价值的模块先进行服务化改造,更早的拿到结果来获得业务团队的支持。
减少对单体应用的改动
单体应用的修改是不可避免的,重要的是要减少改动同时保持数据一致性。
改造主要从业务维度入手,少量的技术维度。
拆分时做“垂直切片”
含业务逻辑、库表结构等前后端逻辑。
改造策略
(1)新业务构建为服务
将新的业务或功能以服务的形式进行构建,这不仅会阻止单体扩大和继续发展,快速开发出新业务功能,更体现出微服务架构的价值。常见的办法是对新业务进行领域建模,得到领域模型、服务接口等必要元素。但同时会带来问题,即新旧系统结合,即微服务与单体应用怎么协作。
问题识别
无论是新构建的微服务,还是旧系统提取的新服务,都会面临新旧系统如何结合的问题。新的微服务与单体应用同时存在,许多业务还需要新旧系统彼此协作才能完成。但新旧系统存在各种差异,如:协议不同(微服务以REST为主,而单体式可能基于SOAP或TCP),模型不同(实体、名称及属性等)。我们推荐的方案是使用双向代理层来完成新旧系统的交互与对接。
解决方案
双向代理层
在微服务和单体应用之间构建一个双向代理层,通过代理层完成新旧系统的对接集成,避免相互干扰,保持彼此松耦合状态。代理层还可以对单体式应用进行服务化封装,让其像微服务一样以 REST的方式对外服务。代理层支持双向通讯,重点解决新旧系统对接集成、协议适配和模型转换等问题,按照此功能定位我们可以将代理层划分成三个模块:
旧系统侧的集成对接:采用外观(Facade)模式,屏蔽旧系统内部细节,简化新系统对接的复杂度。
旧系统侧的协议适配:采用Adapter模式,向新系统提供所需的服务实体,负责请求和应答的协议适配。
领域模型转换器:负责请求和应答中新旧系统领域模型的转换,新旧系统都需要。
领域事件
单体与微服务之间的数据交互,使用API是较为直接的方式。但当一方数据变化后,API方式无法主动进行通知。因此,另一个方式是基于领域事件的数据同步。比如:单体应用发布领域事件,微服务进行订阅。当单体数据产生变化时,可以通过领域事件的方式通知微服务,微服务获取事件,更新本地数据,供本地业务查询使用。
(2)业务功能提取为微服务
挑战:对单体应用做拆分时,采取的策略是自上而下的“垂直切分”,要涵盖被拆分的业务的全部逻辑,主要包含业务逻辑及数据库表。为此带来了一些挑战:
领域模型的拆分:跨服务的对象引用、通用类的拆分等
数据库表的拆解分,如:从已有的表中拆出新表
提取入口:关于提取哪些部分进行服务化,一个重要判断点是否能给业务快速带来价值,而价值可以从新业务上线效率,或解决棘手的性能及扩展性等方面来考虑。一般来说,具有下面特点的功能模块可以入手来做改造,提取功能为服务后,同时也需要重构数据库。如:改造数据库的库表结构,提取并创建新服务对应的表及数据。
频繁变化(业务维度)
频繁调用
相对独立
共享的基础数据
计算密集型(利于弹性伸缩,技术维度)
最小化改造:对单体应用进行改造,势必会带来领域模型、库表结构等的变化。例如:我们拆分订单业务,提取出送货子业务。这些变化会直接影响代码,即要求对变化的部分做出代码调整。由于每一处访问变化部分的代码都需要,这会直接修改单体应用的代码,可能带来较大工作量,这是我们不愿意看到的,因为大量工作花费在要被替代的单体应用上。理想的方式是,在拆分出新服务的同时,不修改或尽量减少修改原有单体应用。
保持单体应用的数据库结构基本不变;
拆分出的新服务使用独立的新库表结构;
新服务获取数据后写入新的库表;
使用触发器之类机制将新库表的数据同步到单体应用库表;
在单体应用里,只需修改代码去调用新服务即可;数据读取可依赖原有单体应用。