前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从单体式应用到微服务的低风险演变(上)

从单体式应用到微服务的低风险演变(上)

作者头像
物流IT圈
发布2019-07-16 10:47:12
4050
发布2019-07-16 10:47:12
举报
文章被收录于专栏:物流IT圈物流IT圈

作者:Christian Posta

译者:海松

原题:Low-risk Monolith to Microservice Evolution Part I

在为期两天的微服务研讨会中,我一直在思考如何向大家解释单体应用(monolith-application)分解以及它向微服务过渡后将会是什么样。本文是该主题的一小部分,但我想与大家分享,并得到反馈(在研讨会中,我们会更详细地讨论是否应该分解单体应用!)。本文中我总结了一些亲历的经验,以及在过去几年中与北美许多红帽(Red Hat)客户合作的经历。这里的第一部分主要探讨了架构,即将发布的第二部分则会介绍一些能提供 很大帮助的技术。关注我的Twitter(@christianposta)http://blog.christianposta.com,可以获取最近的更新和讨论。

在深入讨论之前,让我们先做以下假设:

  • 微服务架构并非总是适用的(后面会详细讨论)
  • 需要采用微服务架构时,我们应该确认单体式应用(monolith)会因此发生什么变化。
  • 在极少数情况下,单体式应用会按照原样拆分。其它大多数情况下,要么需要构

建新的特性,要么围绕单体式应用重新实现现有的业务流程(这有点逆潮流而动)

  • 在需要拆分功能或重新实现的情况下,一个不能忽略的事实是单体式应用如今仍在用于生产,并带来巨大的商业价值。
  • 要设法解决这个问题,同时还必须保证不会干扰系统的整体业务价值。
  • 由于单体式应用是个整体,所以变更它下面的数据模型或数据库时非常困难甚至是不可能的。
  • 我们应当降低演变的风险,这过程中可能需要多次部署和发布。

一、抽取微服务

有关这个话题的会议或博文中,都提供了以下的建议:

  • 围绕名词进行组织
  • 做一件事,做好一件事
  • 单一责任原则
  • 它很难

但这些建议没什么用。

有效的建议应该像这样:

  • 识别模块(现有的或是新的模块)
  • 拆分出与这些模块相对应的表,并用服务进行包装
  • 更新此前直接依赖数据库表的代码并用它调用新服务
  • 重复上述流程(Rinse and repeat)

具体来说:

第1步:识别模块

这一过程从烦人的单体式应用开始。在上图中,我简化了这一点来表示其中可能涉及到的不同模块和数据库表。我们要确定哪些模块是想从单体式应用里拆分出来的,找出涉及到的表,然后继续。当然,现实情况是单体式应用极易与模块(如果有的话)相互缠绕。

第2步:拆分数据库表,用服务包装,更新依赖关系

第二步是确定Foo 模块使用了哪些表,将它们拆分,然后加入模块自身的服务中去。该服务就成为现在唯一能访问这些Foo表的服务了。再没有别的共享表了!这是件好事。过去引用Foo的所有功能现在都必须经过新创建的服务的API。在上图中,我们更新了Bar和Cheese服务,当它们需要Foo的时候,会引用Foo服务。

第3步:重复上述流程

最后一步是重复这个过程,直到单体式应用全部消失。在上图中,我们对Bar 服务做了同样的处理,把它搬到了一个架构里,在这里,服务拥有自己的数据和开放的API,这听起来已经很像是微服务了。

通常,这算是一套不错的指导方针,但上述步骤其实回避了许多我们不应忽略的真相。比如我们不能要求时间暂停,然后从数据库中把表删除。同样的:

  • 很少能简洁漂亮地将单体式应用模块化
  • 表格间的关系可以高度规范化,而且在各实体之间表现出紧密的耦合或完整性约束
  • 我们不可能完全清楚单体式应用中的某些代码到底调用了哪些表格
  • 虽然我们已将表抽取到了一个新的服务中,但这并不意味着现有的业务流程停止了,我们可以让他们一个个迁移到新的服务
  • 有一些烦人的迁移步骤也不会凭空消失
  • 可能会存在一些收益递减的回报点,从这个点开始,把某些东西从单体式应用中拆分出来是毫无意义的

……等等等等

现在让我们来看个具体的例子,看看这个方法/模式是什么样的,以及可供的选择都有哪些。

二、具体举例

这个例子来自上面提到的研讨会。我将在分析拆分服务时做些润色,但是研讨会上谈到的更多内容,包括领域驱动设计、耦合模型以及物理或逻辑架构,这里先暂时不提。这个方法表面上似乎只能用于分解现有单体式应用的功能,但其实它同样能为单体式应用增加新功能。后者出现的概率可能更高,因为直接变更单体式应用风险是相当大的。

三、了解单体式应用

这就是单体式应用(Monolith)。它建立在developers.redhat.com上的TicketMonster①教程的基础上。该教程最初只是探讨如何构建一个典型的Java EE应用程序,但最终却成了一个很好的例子:它不过于复杂,而且有足够的内容让我们可以用来说明一些关键点。在即将发布的整个主题的第二部分中,我们将深入探讨技术框架或平台。

在这张图中,单体式应用将所有模块/组件/UI共同部署到了一个单体数据库中。当我们试图变更时,就会牵一发而动全身。试想一下,这个应用程序已经使用10多年了,所以现在变更起来难度很大(有技术原因,还有团队或组织结构的原因)。我们希望拆分出UI和关键服务,使业务变更起来更快,更独立,以交付新的客户价值和商业价值。

注意事项

  • 单体式应用(代码和数据库模式)很难变更
  • 变更需要整个重新部署和团队间高度的协调
  • 我们需要进行大量测试来做回归分析
  • 我们需要一个全自动的部署方式

四、抽取UI

在这步中,我们将从单体式应用中解耦UI。实际上在这个架构中,我们并未从中删除任何东西。为了降低风险,我们添加了一个包含UI的新部署。这个架构中的新UI组件需要非常接近单体式应用中的同一个UI(甚至完全一致),并调用它的REST API。 所以这意味着单体式应用拥有一个合理的API可供外部UI使用。但是,我们可能会发现并不是这么回事:通常这类API可能更像是“内部的”API,这里,我们需要考虑集成单独的UI组件和后端的单体式应用,以及让面向公众的API更可用。

我们可将这个新的UI组件部署到架构中,并使用平台将流量缓慢地路由到这个新架构,同时仍路由一些流量到旧的单体式应用。这样我们就不用停机。同样的,在本主题的第二部分,我们会更详细地看到如何做到这点。无论如何,灰度上线(dark launch)/金丝雀 发布(canary)/滚动发布(rolling release)②等概念在这里(以及后续步骤中)都非常重要。

注意事项

  • 一开始,先不要变更单体式应用;只需将复制UI或者将它传到单独的组件即可
  • 在UI和单体式应用间需要有一个合适的远程API—但并非所有情况下都需要
  • 扩大安全面
  • 需要用某种方法以受控的方式将流量路由或分离到新的UI或单体式应用,以支持灰度上线(dark launch)/金丝雀测试(canary)/滚动发布(rolling release)

五、从单体式应用中删除UI

在上个步骤中,我们引入了一个UI,并缓慢地将流量转移到新的UI(它与单体式应用直接通信)。在这一步中,我们将采用一个类似的部署策略,但不同的是,UI被删之后,我们缓慢地发布了一个单体式应用的新部署。如果发现问题,我们可以慢慢地让流量流出,然后回流。在把所有的流量都送到已删除UI的单体式应用(此后称后端-Backend)中,我们就可以完全删除单体式应用部署了。通过分离UI,我们现在已对单体式应用进行了小规模的分解,并依靠灰度上线(dark launch)/金丝雀测试(canary)/滚动发布(rolling release)降低了风险。

注意事项

  • 从单体式应用中删除UI组件
  • 需要对单体式应用进行最小的变更(弃用/删除/禁用UI)
  • 不停机的前提下,再次使用受控的路由/整流方法来引入这种变更
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 驼马精英 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档