24

如何把单体式应用拆解成微服务?【下】 – IT老兵哥 – 赋能程序人...

 4 years ago
source link: http://www.itlaobingge.com/2020/03/25/microservice-2/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

紧接昨天的上篇《如何把单体式应用拆解成微服务?【上】》,今天我们一起来看看具体的拆解场景:

场景1:数据库表外键引用关系

如果单体式应用中两个功能模块存在数据引用关系,那我们在拆解微服务时如何消除这种外键引用关系呢?首先,停⽌外键引⽤;然后,改成通过RESTful HTTP API⽅式获取原先外键关联的信息。如下图,改造前Payment数据库表中的记录通过外键引用Order,代码层面通常会借助对象关系映射(ORM)框架建立数据对象的关联,改造后代码层面就不能通过ORM框架做关联了。在Payment数据库表的记录中会保存Order的主键值,除此之外还会保存Order的关键属性信息,这样可以避免频繁的跨进程调用,从而可以提高系统的整体效率表现。

下图是改造前的情况:

04.png

下图是改造后的情况:

05.png

场景2:共享静态数据关系

如果单体式应用中两个功能模块彼此共享静态数据,那我们在拆解微服务时如何消除这种共享关系呢?静态数据通常存储在数据库当中,例如:商品类目代号。如果这些静态数据需要更新,那我们就需要频繁地发布系统,这样会导致多个服务的中断。

为了避免这个问题,我们也可以将这些静态数据拷贝多份,分别⽤于每个服务,但维护多份数据拷⻉的一致性是个问题。另外,我们也可以将这些静态数据存⼊每个服务的配置文件,降低更新数据的难度。统一配置中心,微服务架构中的必选组件,我们可以通过它来管理这些静态数据,这样在维护更新上会带来极大的便利。

场景3:共享基础数据关系

如果单体式应用中两个功能模块共享某类基础数据,那我们在拆解微服务时如何消除这种共享关系呢?多个服务共享某类基础数据,例如:用户数据、物流公司数据等等,那我们要为这类数据提炼出专门的领域模型,将它封装成微服务,然后通过该服务来访问这些共享的基础数据。服务化带来的好处就是彼此之间仅仅依赖服务契约,双方具体采用什么技术和方案都是自由的。只要服务契约没有改变,那彼此的升级改造就不会影响。

下图是改造前的情况:

06.png

下图是改造后的情况:

07.png

场景4:共享数据库表格

如果单体式应用中两个功能模块共享一张数据表格,那我们在拆解微服务时如何消除这种共享关系呢?多个服务各自引⽤的数据被合并存储在一张数据库表当中,代码层面借助ORM框架实现多态,这种情况我们需要将每个服务所关注的数据剥离出来,分别存到不同的表格当中。

下图是改造前的情况:

08.png

下图是改造后的情况:

09.png

场景5:共享数据库

在拆解微服务过程中,我们该如何拆分数据库呢?最稳妥的方案就是分阶段重构数据库,数据是最宝贵的资源,我们不要贪图一步到位。下图是改造前的情况:

10.png
  • 第一步,按照业务上下文先将一个数据库拆解成两个数据库,但应用仍然是单体式应用,通过多数据源相关技术应用可以同时访问两个数据库,如下图所示:

11.png
  • 第二步,将单体式应用拆解成微服务,每个微服务都有各自独立的数据库,如下图所示:

12.png

旧模块微服务改造优先级原则

从单体式应用中划分出有界的上下文,作为剥离微服务的候选,然后开始依次重构每个功能模块。那如何判断哪些模块应该优先被剥离成微服务呢?从模块剥离难度看,我们可以遵循先易后难的原则,逐步积累重构经验,这适用于在微服务构建方面经验不太丰富的团队;从需求变化频率看,优先剥离那些变更频繁的模块,整体收益会更大一些,这对于人力资源较为紧张的团队不失为一个好的判断准则;从资源消耗类型看,那些计算或内存密集的模块适合优先剥离,这样有利于弹性伸缩时提升资源利用效率,这对系统规模较大的场景效果最明显;从服务边界粒度看,粒度越粗越好剥离。具体按哪个规则来安排微服务的改造顺序,这就要根据每个团队的具体情况来具体分析了。

我们在支持不同系统实施微服务改造的过程中,上述优先级原则都被采用过,优先级存在的原因就是资源不够。微服务改造不是一蹴而就的事情,这个过程会持续很长时间,可能跨度几年,在不同阶段需要考虑的问题也就不同,最核心的原则就是按照适合自己的节奏有条不紊地开展工作,在确保线上业务稳定的前提下适当地追求速度。

微服务改造是否结束判断标准

那什么时候才算完成微服务改造呢?判断标准就是旧系统中全部有界上下文都被剥离成微服务,此时反腐层就可以被废除了;或者遗留的单体式应用相对较稳定,不再发生变化,重构的投入产出比不再划算;或者遗留的单体式应用关联业务已经退出市场了,系统下线了。

微服务架构新挑战与解决方案

当单体式应用被拆解成多个微服务之后,原先在一个事务边界内的操作现在要跨多个事务边界了,我们如何保证事务的一致性呢?下面是一些分布式事务机制:

  • 再次尝试,最终一致:将每个操作步骤放⼊队列排队,后续再次尝试,确保最后执行成功,状态达成⼀致。
  • 撤销全部操作:补偿事务机制,原事务操作失败之后,启动一个新的事务去撤销之前的操作。如果补偿事务也失败了,那系统需要提供手动或自动再次运⾏补偿事务的功能。
  • 分布式事务:通过一个全局事务管理器来协调各个事务得以成功执行。对于短期事务,通常采用两阶段提交(Two-Phase Commit),第一阶段是投票阶段,分布式事务的参与者告诉事务管理器,判断本地事务是否可以顺利执行。如果事务管理器收集到所有投票结果都是YES,那就开始提交事务执行。

分布式事务机制本身不算太复杂,我们借鉴业界的一些开源产品自研了一套分布式事务框架,跟微服务框架结合起来,应用开发者只需要按照框架的约定实现特定的接口,通过一些注解就可以发起分布式事务,相关细节可以参考阿里的全局事务服务GTS。

当单体式应用被拆解成多个微服务之后,原先集中存储的数据也被分开存储了,报表生成将会遇到新的挑战。在单体式应⽤情况下,通常有一个用于生成报表的从库,从主库同步数据,仅⽤于查询等读操作,避免⽣成报表过程影响主库的读写效率。在微服务情况下,我们将要通过服务调用来获取数据,设计适合报表统计的批量接口,以及增加缓存用于提升数据获取效率。

  • 数据抽取:通过服务调⽤来获取报表所需数据,这会造成非常⼤的负载,以及专⻔为报表设计的API。为了弥补上述不足,我们可以将数据抽取程序独立出来,专门从业务数据库中抽取数据到报表数据库。
  • 事件驱动数据抽取:基于事件驱动的微服务架构,我们可以开发特定事件的订阅者,负责将数据同步到报表数据库,这样可以解耦底层数据库系统。

微服务改造是一个长期过程,这个过程会遇到各式各样的问题,方法论可以帮助我们更好地解决这些问题,并且降低风险。欢迎大家一起探讨微服务改造过程中遇到的任何问题!

原创不易,麻烦动动手指点个「 赞 」。后续我会持续分享职业规划、应聘面试、技能提升、影响力打造等经验,关注「 IT老兵哥 」,赋能程序人生 !

itlaobingge-weixin-mp.jpeg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK