成功微服务实施的技术演进

在上一篇文章《我们如何衡量一个微服务实施的成功》里,我们介绍了衡量一个微服务改造成功的七个特征,分别是:

  • 很多个代码库,以及一一对应的流水线。
  • 应用可以随时部署,并不需要等待。
  • 大量的自动化测试。
  • 更少的变更事故。
  • 更低的发布风险。
  • 可以按需扩展。
  • 更多的自动化手段。

而本篇文章所介绍的案例,也符合这篇文章中对“微服务实施成功”的定义。不过,我们将通过以下五个方面来介绍我们是如何做到达到这七点的:

  1. 通过度量驱动架构的微服务化;
  2. 微服务平台的演进;
  3. 数据库的独立演进;
  4. 服务间的轻量级通信;
  5. 微服务的全链路跟踪。

微服务演进的技术背景

2013 年,当我加入这个“微服务改造”项目中的时候,微服务远没有像今天这么火。那个时候我还不知道这种架构演进的方式叫做“微服务”。直到我离开这个项目把其中的经验带到其它项目里,才对敏捷,DevOps 和微服务有了进一步的认识。

当时,我们刚刚协助客户把应用程序从自建数据中心迁移到亚马逊云计算服务(AWS)上,并通过 DevOps 等实践做到了按月发布。然而,新的挑战接踵而至。当客户决定开始做微服务之前,遇到了以下三点问题:

  1. 运维风险高,发布的时候需要整体发布。除了累积了应用变更以外,还有基础设施的变更。
  2. 开发效率低,由于单体应用存储在一个代码库里。导致各功能,项目,维护团队之间产生依赖,交付效率很低。
  3. 内部多个应用系统之间需要集成,但缺乏单一可信数据源(Single Source of Truth)。

作为很早就采用敏捷方式开发的企业来说,该企业很多敏捷实践都做的非常成熟,并往往作为澳大利亚敏捷成功的案例标杆。在我加入的时候,客户已经采用持续集成很长时间了。而迁移到 AWS,还需要将部署和运维部分自动化,从技术层面为 DevOps 做了很好的准备。那时候我们所依赖的仍然是用 Chef 去构建自动化的脚本进行部署,并开始采用 Ansible 这种技术做发布的标准化。

通过度量驱动架构的微服务化

我们所拥有的是一个基于 Spring 2.5 的 Java 遗留系统,各个系统之间由 ESB (Enterprise Service Bus 企业服务总线)串联起来。多个不同的业务线(Line of Business,LoB)拥有各自独立的产品组件,但都是基于同一套代码库。

这样的痛点很明显:

  1. 每个业务线都要有自己的子产品,但大家都基于同一份代码库。
  2. 每个业务线对自己产品的改动,会影响到其它的系统。
  3. 由于不同的系统的组件依赖于不同的环境和不同的数据库,所以部署所带来的风险很高。

随着开发人员的不断增加,以上的痛点越来越明显,我们发现很多工作因为开发阻塞而无法前行。于是就有了一个最基础的度量:发布阻塞时间。

当我们把敏捷看板构建起来,我们可以很清楚的看到需求分析、开发、测试的各环节时间。当时并没有采用 DevOps,我们的持续发布也仅限于 Staging(准生产环境),而各个环节内可以采用更具有生产力的实践我们可以缩短环节时间,降低浪费。但,阻塞时间则随着需求的增加而增加。

当阻塞时间在上涨的时候,主观的组织规划已经和应用系统规划不符了。于是,产品则根据业务线被划分成了三个产品,如下图所示:

产品拆分

于是有了三个代码库,和三条不同的流水线。每个业务线都负责构建自己的代码库和周边生态。这样虽然会带来代码的重复,让很多有 DRY(Don't Repeat Yourself )癖的架构师难以接受。但毕竟各产品未来要走自己的路,因此,为了让各业务线不阻塞,各自采用各自的代码库进行发布。于是原先的团队随着代码库的分离而分隔成了不同的团队。但是,Ops 团队却没有分隔开,而是作为通用能力继续支持着各产品线的发展。

这也就是康威定律所说的:“设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。”

这一次的拆分尝到了甜头,除了各个业务线开发阻塞时间缩短以外,各个业务线的产品的发布失败率和故障率也降低了。于是我们继续采用工具提升发布的成功率和效率,直到我们发现我们系统里的 ESB 成为了我们的瓶颈。于是我们开始进行了微服务的拆分。

我们预期的策略是采用“拆迁者模式”:

即新建一套子系统,再统一的进行迁移,一步到位。能够这样做的前提是要有足够的自动化测试覆盖当前所有的业务场景。

于是我们根据我们需要拆分的功能先编写自动化测试,在自动化测试通过的情况下可以保障我新编写的代码不会影响现有的功能,包括数据迁移后的测试。

然而,拆迁者模式最大的挑战来自于切换风险,为了避免切换造成的风险就要补全自动化测试,这样的成本是巨大的。除非很早就开始做好了责任独立的设计。否则,不要用拆迁者模式。

另外两种模式就是“绞杀者模式”和“修缮者模式”。前者有一个别名,叫做“停止挖坑”,意思就是不要在当前的系统里继续增加功能,而是采用松耦合的方式增加新的功能,使得老的功能慢慢被绞杀掉。这种模式的前提就是要确认遗留系统不再进行功能新增,只做 Bug 修复和例行维护。这样带来的变更风险最小,但演进时间较长。对于“新遗留系统”——刚刚开始转入维护不到半年的新系统,可以采用这种方式。

然而,我们所碰到的应用系统则是一堆运行时间超过 5 年的遗留系统。于是我们采用了“修缮者模式”。修缮者模式源于古老的软件工程格言:“任何问题都可以通过增加一个中间层解决”。

我们首先做了一个前后端分离,采用 RESTful API 作为后台,向 PC 浏览器和手机 App 提供数据交互。这样,无需为移动应用单独编写后台应用,只需要复用之前写好的 API 就可以了。这就是当前很多应用进行微服务改造的第一步。

到了后期,我们发现有些需要很多 API 需要进行转化,所

收藏 收藏
分享
购买文章 ¥1.99