Chris Richardson微服务翻译:重构单体服务为微服务
Chris Richardson 微服务系列翻译全7篇链接:
- 微服务介绍
- 构建微服务之使用API网关
- 构建微服务之微服务架构的进程通讯
- 微服务架构中的服务发现
- 微服务之事件驱动的数据管理
- 微服务部署
- 重构单体应用为微服务(本文)
原文链接:Refactoring a Monolith into Microservices
微服务重构的概述
将单体应用转化为微服务是应用现代化的一种形式,数十年来开发者们一直致力于此。因此,将应用重构为微服务时,我们可以借鉴其中的一些经验。
首先不要大规模地重写代码,不要集中所有力量从头构建一个新的微服务应用,这中方式听起来很吸引人,但是会有极大的风险,有可能以失败告终。正如 Martin Fowler 所言:
the only thing a Big Bang rewrite guarantees is a Big Bang!
相反,我们应该渐进式的重构单体应用。逐步构建由微服务组成的新应用,与单体应用一起运行;随着时间的推移,单体应用实现的功能会不断收缩,直至完全消失或者转变为另一个微服务。这一方法虽然充满挑战,但风险远小于大规模重写代码。
Martin Fowler 将这一策略称为“杀手应用”。这一名称源自热带雨林中的杀手藤。杀手藤附生于大树的周围,企图得到树冠处的阳光,最后树木死后,留下树状的藤蔓。应用现代化也遵循这一方式。我们将围绕着遗留应用构建由一些列微服务组成的新应用,直至遗留应用消失。

接下来了解不同的实现策略。
策略一:停止挖坑
如果发现自己掉入坑里,应该马上停止挖坑。一旦单体应用变的难以管理,你应该停止让单体应用继续变的庞大,实现新功能时,不应该往单体应用中添加新的代码。相反的,而是把新代码放到独立的微服务中。下图展示了此方法的系统架构:

除了新服务和遗留的单体应用,这个系统还包括其他两个组件:第一个是请求路由,用来处理 HTTP 请求,与之前文章中所说的 API 网关类似。路由将与新功能相对应的请求发送到新服务上去,将遗留请求发送到已有的单体应用上去。
另一组件是胶水代码,用来集成微服务与单体应用。微服务很少独立存在,通常需要访问单体应用拥有的数据。胶水代码存在于单体应用或微服务中,或者两者兼有,用来负责数据的集成。微服务使用胶水代码来对单体应用的数据进行读写。
微服务可以通过以下三种方式来访问单体应用的数据:
- 调用单体应用提供的 API
- 直接访问单体应用的数据库
- 维护一份数据副本,与单体应用的数据库保持同步
胶水代码也被称为 anti-corruption layer。因为胶水代码能防止拥有全新领域模型的服务被遗留单体应用的领域模型所污染。胶水代码在两种不同的模型间进行转换。anti-corruption layer 这一术语来自 Eric Evans 撰写的 Domain Driven Design 中。要想远离单体应用的泥淖,开发 anti-corruption layer 是必不可少的。
以轻量级微服务的方式实现新功能有许多优点:它能够防止单体应用变的不可管理。微服务能够独立开发、部署和扩展。你可以通过创建新的服务来体会到微服务架构的好处。
然而,这一方法并没有解决单体应用的问题。要想解决这些问题,需要拆分单体应用。让我们看一下拆分的策略。
策略二:前后端分离
缩小单体应用的策略之一是将展示层从业务逻辑层和数据访问层中拆分出来。典型的企业应用包括一下三种组件:
- 展示层:处理 HTTP 请求并实现基于 REST API 或 HTML 的 Web UI。在一个-
用户界面复杂的应用中,展示层通常包含了大量的代码 - 业务逻辑层:应用的核心,实现了业务逻辑
- 数据访问层:访问数据库和消息代理等基础架构组件
通常展示层对于业务逻辑层与数据访问层来讲,彼此有着清晰的划分。业务层由若干个 API 组成,内部封装了业务逻辑。这些 API 是将单体应用拆分为两个更小应用的分界线。一个应用包含表示层,另一个应用包含业务逻辑层和数据访问层。拆分后,展示逻辑的应用向业务逻辑的应用发起远程调用。下图展示了重构前后的构架:

以这种方式拆分单体应用有两大好处:1)它使得两个应用可以独立的开发、部署和扩展。尤其是,它使得展示层的开发者能够快速迭代用户界面,轻松的进行 AB 测试。2)暴露了可被其他服务调用的 API
这种策略也只是部分解决方案,很有可能两个应用会变成难以管理的单体应用。这时需要使用第三种策略来消除剩余的单体应用。
策略三:提取微服务
重构的第三个策略是将单体中现有的模块变成独立的微服务,每次提取模块为微服务时,单体就会缩小,一旦转化了足够多的模块,单体应用将不再是问题,要么消息,要么变成另一个微服务。
为需要转化为微服务的模块设置优先级
大型、复杂的单体应用由数十甚至数百个模块组成,所有模块都是可提取的。弄清楚哪个模块需要首先被提取往往是挑战性的问题。一个好的方式是先选择易于提取的模块,这将给开发者熟悉微服务以及积累提取经验。之后可以提取哪些可以带来最大收益的模块。
将模块转变为微服务通常需要一定时间,一般会根据获得收益的大小来给模块排序。通常转换经常变化的模块带来的收益也最大。一旦把一个模块转换为微服务,就可以独立开发、部署它了,从而加快了开发速度。
提取那些对资源有独特需求的模块也会带来很多好处。例如,把需要内存数据库的模块转化为微服务,就能部署在大内存的主机上。同样的,将实现计算密集型算法的模块提取出来也是值得的,该微服务可以部署在拥有多个 CPU 的主机上。这种方式使得应用更容易扩展。
当决定哪些模块需要提取时,找出现有粗粒度的边界(即分界线)也大有裨益。这会使模块转化为微服务更加简单、省力。例如:一个只通过异步消息与其他部分通信的模块,转化为微服务是更简单的。
如何提取模块
提取模块的第一步是确定模块和单体应用的接口粒度。单体应用和微服务需要访问彼此的数据,更像是双向 API,模块和应用其它部分之间存在着互相依赖,因此实现这些 API 一般充满挑战。重构时使用领域模型来实现业务逻辑变的尤为困难,一般需要大的代码改动才能打破这些依赖。
一旦实现粗粒度的接口,就可以将模块转化为独立的微服务。要做到这一点,必须能够让单体应用和微服务通过 API 通信。 下图展示了重构前、重构中和重构后的不同架构:

模块 Z 是要被提取的模块,它使用到模块 Y ,同时它的组件被模块 X 使用。重构的第一步就是定义一组粗粒度 API,第一个接口是模块 X 调用模块 Z 的 接口。第二个接口是模块 Z 调用模块 Y的接口。
重构的第二步是把模块转变为独立的微服务。对内和对外接口通过 IPC 机制实现,开发人员可能只需要将模块 Z 与微服务支撑框架(Microservice Chassis framework)组合起来构建微服务。
一旦将模块提取完毕,你就拥有了一个新的微服务,它能够独立于单体应用和其它微服务进行开发、部署和扩展。如果想重写微服务的代码,集成微服务和单体应用的 API 会成为这两个领域模型之间的 anti-corruption layer。每提取一个模块,就向着微服务的方向又迈进了一步。随着时间推移,单体应用将会逐渐消失,你也会拥有更多的微服务。
总结
将单体应用迁移到微服务的过程是应用现代化的一种形式。并不需要从头重写代码,而是渐进式地将应用重构为一组微服务。其中有三种策略:使用微服务实现新功能;将展示层从业务逻辑层、数据访问层中拆分;将单体应用内的模块转化为微服务。随着时间的推移,微服务的数量将会增加,从而提升团队的敏捷和效率。
Chris Richardson微服务翻译:重构单体服务为微服务的更多相关文章
- Chris Richardson微服务翻译:微服务之事件驱动的数据管理
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理(本文) 微服 ...
- Chris Richardson微服务翻译:微服务架构中的服务发现
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现(本文) 微服务之事件驱动的数据管理 微服 ...
- Chris Richardson微服务翻译:构建微服务之微服务架构的进程通讯
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯(本文) 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服 ...
- Chris Richardson微服务翻译:构建微服务之使用API网关
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关(本文) 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服 ...
- Chris Richardson微服务翻译:微服务介绍
作者简介:Chris Richardson,世界著名的软件架构师,经典著作<POJOS IN ACTION>的作者,cloudfoundry.com 的创始人 微服务目前正受到大量的关注, ...
- Chris Richardson微服务翻译:微服务部署
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服务部署( ...
- 【转】「Chris Richardson 微服务系列」微服务架构的优势与不足
Posted on 2016年5月4日 编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战. 作者介绍:Chris Ric ...
- 【CHRIS RICHARDSON 微服务系列】事件驱动的数据管理-5
编者的话 |本文来自 Nginx 官方博客,是「Chris Richardson 微服务」系列的第五篇文章.第一篇文章介绍了微服务架构模式,并且讨论了使用微服务的优缺点:第二和第三篇描述了微服务架构模 ...
- 【CHRIS RICHARDSON 微服务系列】微服务架构中的进程间通信-3
编者的话 |本文来自 Nginx 官方博客,是微服务系列文章的第三篇,在第一篇文章中介绍了微服务架构模式,与单体模式进行了比较,并且讨论了使用微服务架构的优缺点.第二篇描述了采用微服务架构的应用客户端 ...
随机推荐
- 关于windows phone 8.1系统手机对html5触摸事件的支持情况
近日购入一部微软Lumia 640手机,目的主要就是为了测试年中开发完成的响应式移动web项目,同时也为了将来升级win10 mobile系统.由于我们的项目目前只考虑支持IOS与Android系统, ...
- 八、 Spring Boot 过滤器、监听器
直接使用@WebFilter和@WebListener的方式,完成一个Filter 和一个 Listener.过滤器(Filter)文件MyFilter.Javapackage org.springb ...
- cookies和re
参考:http://cuiqingcai.com/968.html http://cuiqingcai.com/977.html
- 《CLR via C#(第4版)》【PDF】下载
<CLR via C#(第4版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382189 via C#(第4版)>[PD ...
- 随笔:JavaScript函数中的对象----arguments
关于arguments 调用函数时,如果需要传参,其实参数就是一个数组,在函数体的内置对象arguments可以访问这个数组,如: arguments[0]:第一个参数 arguments[1]:第二 ...
- 队列queue(1) 结构体实现队列
前言 首先,我们先来做一道解密题:一串数列 7 6 8 6 6 7 0 4 1 ,规定一个回收站,把第一个数删除,添加到回收站里,然后把第二个数排到队伍最末尾,把第三个删除,添加到回 ...
- iOS Swift基础知识代码
推荐:Swift学习使用知识代码软件 //集合类型 数组 字典 func array1(){ var arr = [","dd"] //简单写法 var arr1 = [ ...
- 监听键盘弹起View上调
可以用三方库IQKeyboardManager 用这个第三方 http://www.jianshu.com/p/f8157895 #pragma mark - keyboard events - // ...
- jsp上的九个隐含对象
首先说一说件jsp的原理.jsp被认为最经典的解释是 “嵌入了java 代码的html”. 在网上查了一些资料,和我本身对jsp的认识,总结如下: jsp本质上是一个servlet,继承自 当第一次 ...
- 基于阿里云的MQTT远程控制
好久没有写博客了,眼看自己的项目就要快做完了,先分享一下基于MQTT的远程控制,自己买了一个阿里的云端,然后在云端上安装了一个MQTT服务器,其实是一不小心买了两个,所以准备贡献出来一个供大家使用, ...