微服务架构中的服务拆分方案和案例

公众号:爱码叔漫画软件设计(搜:爱码叔)

CSDN: https://blog.csdn.net/liyiming2017

知乎:https://www.zhihu.com/people/zhong-guo-ren-83-43

专注于软件设计与架构、技术管理。擅长用通俗易懂的语言讲解技术。对技术管理工作有自己的一定见解。欢迎大家关注我!

在微服务架构中,对于服务范围的定义应该以发展的眼光去看待。随着系统的发展,可能会出现微服务的拆分和合并。这就像面向对象设计的单一职责原则,每个人对单一职责的认知各不相同,而且随着系统的发展,原来符合单一职责的对象可能会变得复杂,直到某一天被重构。微服务也是同样的道理。某个服务中的一块业务,在设计之初可能非常简单,并且依附于其他业务。但是随着业务的发展,该业务逐渐发展壮大,直到和其他业务也能平起平坐,此时需要考虑微服务的拆分。

我们设想如下场景。在某个微服务中,存在服务 A,原来负责业务 A 和 B。最初 B 的业务比较小,随着企业发展,B业务越来越受到重视,也在不断发展壮大。现在需要从A服务中将B业务拆出,构建新的服务 B。以下是此场景的拆分方案。

一、方案简介

本文的微服务拆分方案旨在提供一种平滑拆分微服务的方法。尽量降低服务拆分的风险,并且能够回滚。本方案在实际项目中有过验证,基本做到了零问题,平稳拆分。

微服务拆分的内容主要包括两个部分——服务和 DB(包括但不限于,也可能有消息队列、Redis、云上存储的拆分)。开发、测试阶段均使用两个独立的 DB,但是上线分为以下三个步骤,尽量确保稳妥。

  1. 只拆服务,不拆 DB
  2. 拆分 DB Schema
  3. 拆分 DB
  4. 下图省去了拆分 Schema 的过程。
1712589379407.jpg

二、拆分服务

第一阶段,只拆分服务,不拆分 DB。拆分服务的工作是将原 A 服务的 API 拆一部分出来,移到到新建的 B 服务中。暂时保留两个版本的 API。这个阶段不拆分 DB,目的是为了先确保 API 拆分的正确性、完整性。一旦出现问题,切换路由,快速回滚,不会污染数据。

2.1 拆分服务方案概要

拆分服务的方案考虑如下要点。

1)将服务 A 中 B 业务的 API 全部拆分到新的微服务 B 中

2)A 服务中暂时保留 B 业务 API,以便出问题时,切换回原有 API

3)日志需要记录统计哪个服务的 API 被调用

4)B 服务继续使用原有 DB

2.2 涉及改动的 API 分类

首先需要确定迁移的 API 范围。可以从 A 服务的 DB 中找到属于 B 服务的表,向上推出所有受影响的 API。将这些 API,分为下面的三类。

1)B 业务的 API 只访问 B 业务表

这一类是最简单,只需要将已有 API 从 A 服务原样照搬到 B 服务。原有API直接迁移。

2)A业务API,但要使用B业务表。

拆分前 ,在A 服务中可以访问到B业务表。拆分后A服务无法直接访问B业务表,只能通过B服务API。因此,需要在B服务中新增此类API

3)B 业务的 API,但要使用 A 业务表。

原理同上。需要在A服务中新增此类API,供B服务API调用。

API的分类和解释如下图所示。

1712588925464.jpg

2.3 拆出的 B 服务开发。

针对以上三类 API,对 B 服务的开发如下。

1)第一类直接搬到 B 服务中

2)第二类,B 服务 提供 A 服务需要的 API

3)第三类,B 服务需要使用 A 服务提供的新的 API 操作数据

2.4 原 A 服务修改

1)首先,所有受影响的 API 版本需要弃用,但可回滚。通过版本号,以路由控制是一种方案。

2)第二类,A 服务改为访问B服务 API 获取数据

3)第三类,A 服务提供新的 API 供 B 服务调用

2.5 A、B服务之外受影响的服务修改

站在微服务的视角,将被迁走的A服务中B业务的 API(API分类中的1和3),是对其他服务产生影响的原因。这些 API 决定了其它服务的受影响范围。

我们需要找到哪些服务受到影响,以及这些服务中的哪些业务受到影响。

首先,通过工具、关键字查询等方式,找到所有调用 A 服务的服务。然后分析使用的 API 是否有属于 B 业务的 API。然后再分析被影响到的具体修改点。

所有被影响的地方,都需要将原来访问 A 服务的 B 业务 API,改为访问 B 服务。并且需要能够灵活切换,方便回滚。

2.6 统计监控

提前设计好日志。上线后通过日志统计,确认所有 B 业务的 API 调用全部走 B 服务,不再走 A 服务。

三、拆分 DB schema

经过 API 的拆分和监控。已经确认 API 拆分完整,并且所有 B 业务的 API 调用都走 B 服务。但是有几点没法得到更严谨的验证。

由于 DB 没有拆分,所以不能确认是否 A 服务所有对 B 业务表的访问都被移除,可能存在遗漏。 DB 权限的设置,没有在生产环境验证。 如果直接拆分 DB,一旦出现以上问题,程序会出现错误,数据将被污染,并且恢复难度较大。因此,先在一个 A 的 DB 上建立 B schema,模拟 DB 拆分。

这个阶段的开发工作如下。

  1. 在原 DB 上建立 B 业务的 Schema,将 B 业务表迁移到 B 业务 schema
  2. 重新建立 A、B 服务的 DB 账号,重新分配相应权限
  3. A、B 服务修改 DB 账号和 schema 信息 上线时的工作如下。
  4. 数据迁移。迁移 B 业务表的数据到B Schema中
  5. 切换 A、B 服务 DB 账号

四、拆分DB

拆分 Schema 后,确认 A Schema 中 B 业务表已经没有数据流入,B schema 数据流入正常,系统运行稳定后,可以进行 DB 的拆分。

DB拆分分为以下几步

  1. 提前建立 B 服务 DB,从 A 服务 DB 同步数据
  2. 准备好 B 服务所需要的 DB 账号信息
  3. A 服务 DB 数据同步完成后,切换 B 服务到新的 DB

五、收尾

DB 拆分后,确认 A DB 中的 B schema 没有数据流入后,可以进行收尾工作。主要工作如下。

  1. 移除A DB中的 B schema
  2. 移除A DB中的 B 业务表
  3. 其他服务中如果有临时保留的,用于切换回 A 服务原来 API 的代码,进行删除。
  4. 移除A服务中老版本的API

六、其他受影响方

DB 信息的变更,会影响到从 A DB 取数的第三方,包括但不限于 报表、大数据、数据集成方。需要提前沟通,告知 DB 改变的信息和时间。

七、总结

本方案原来分两个阶段走,先拆分服务、再拆分DB。在实施过程中,团队决定增加拆分schema的阶段,以此降低直接拆分DB带来的风险。实际项目中比文中描述更为复杂,还会涉及路由修改、消息队列拆分等工作。

从宏观看待类似微服务拆分工作。我总结以下几点

  1. 分析先行,合理的分析方法,准确确定影响范围
  2. 分多阶段进行,一次拆分一部分,风险可控、方便回滚
  3. 新的新建;旧的保留;新的验证;旧的删除
  4. 每一个阶段都要有风险应对方案。
  5. 每一个阶段都要有验证方案
  6. 不要忽视对第三方的影响
All rights reserved
Except where otherwise noted, content on this page is copyrighted.