热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

重构到微服务,第1部分执行整体迁移时的考虑事项

如何从传统的中间件架构迁移到微服务


在云社区和敏捷编程社区中,好像大家都在谈论微服务。REST 等架构原则正在风靡整个开发世界,微服务目前是最新一波的热潮。但是,微服务是什么?为什么 Java™ 开发人员会关心它们?

在本系列中,我将回答这些问题,并解释为什么您要将自己的应用程序迁移至微服务(第 1 部分)。我还将深入探讨数据重构(第 2 部分),并给出一个循序渐进的方法来帮助您迁移到微服务(第 3 部分)。

什么是微服务?

在 Martin Fowler 和 James Lewis 关于这个问题的经典文章 中,我们可以找到最简单的微服务架构 定义:“一种架构方法,包括利用小型服务在各自的过程中构建系统,以及利用轻量级协议进行通信。” 要理解的一个关键概念是,每个微服务代表一个独特的业务功能。

Fowler 还将微服务称为 “正确完成的面向服务”。如 Fowler 和 Lewis 所述,而且其他许多人都已证明,企业计算的世界中,到处都是失败的大型 SOA 项目的范例。微服务可以 帮助扭转这一趋势,但我们必须明白在什么地方应用微服务,更重要的是,我们要了解可以发挥微服务最大作用的项目,而不是目前那些最巧妙的、最酷的项目。

为什么重构为微服务?

尽管在硅谷的人有时愿意相信,但并非每一个应用程序都是一块绿地。现实情况是,企业有很多现有的 Java 代码,以及许多 Java 开发人员。扔掉所有的 Java 代码,用全新的运行时和编程语言重新开始,从经济角度来看,这根本就是不可行的。

更好的办法是,找出好的部分,并在正确的框架中重用这些部分。这就是为什么将现有的应用程序重构 到微服务往往是最好、最稳妥的办法,可以在保持现有的系统运行的同时将它们迁移到一个更加可持续的模型中。

如何重构为微服务?

那么,我说的重构 是什么意思?编程社区将重构定义为 “引入保持行为的代码转换”。这可以归结为保持外部 API 不变,而改变代码运算或打包的方式。因此,重构到微服务就意味着,将微服务添加到应用程序,而不必改变它所做的事情。您不会在应用程序中添加新功能,但您会改变它的打包方式,或许这就是这个 API 的表达方式。

重构到微服务并非适合所有应用程序,而且并不是总能获得成功。但是,当您不能把所有一切都扔掉的时候,重构是值得考虑的。三个基本的考虑事项是:

  • 如何打包(和构建)您的应用程序?
  • 您的应用程序代码如何工作?
  • 如果这些数据源采用了不同的结构方式,您的应用程序如何与后端数据源进行交互?

第 1 步. 重新打包应用程序

最好的起点是,重新检查您的 Java 应用程序打包结构,采用一些新的打包实践,然后再开始修改代码。在 21 世纪初,我们开始构建一些越来越大的 EAR 文件,以包含我们的逻辑应用程序。然后,我们将这些 EAR 文件部署到服务器场中的每个 WebSphere® Application Server 上。问题是,这种做法试图对应用程序的每段代码都使用相同的部署时间表和相同的物理服务器。任何改变都意味着要重新测试一切,这使得任何改变都变得过于昂贵,不在考虑范围之内。

但现在我们使用了 Docker 等容器和 PaaS,以及 WebSphere Liberty 等轻量级 Java 服务器,经济因素已经发生了改变。所以,现在您可以开始重新考虑打包。下面是您需要开始运用的三项原则:

  1. 拆分 EAR:不要将所有相关的 WAR 打包到一个 EAR 中,而是将它们拆分成独立的 WAR。这可能涉及到一些小的代码改动,或者更可能的是,如果您将应用程序的上下文根改成是分开的,将会涉及要修改静态的内容。
  2. 应用 “每服务容器 (Container per service)”:接下来,应用 “每服务容器” 模式,将每个 WAR 部署到它自己的 Liberty 服务器中,最好是在它自己的容器中(比如一个 Docker 容器或一个 Bluemix 即时运行时)。然后,您可以独立地扩展容器。
  3. 独立地构建、部署和管理 :一旦进行了拆分,您就可以通过自动化的 DevOps 管道(如 IBM DevOps Pipeline Service)独立地管理每个 WAR。这是获得持续交付的优势的一个步骤。

您可以看到运用这三项原则的效果:

重构到微服务,第 1 部分 执行整体迁移时的考虑事项

第 2 步. 重构代码

现在,您的部署策略已经细化到了独立 WAR 的层次,您可以开始寻找机会将 WAR 重构为更精细的水平。以下有三种情况,您可以在其中找到机会重构代码,以适应独立包装微服务的包装方法。

  • 第 1 种情况:现有的 REST 或 JMS 服务:这是迄今为止最简单的重构情况。您可能已经有一些服务可以兼容微服务架构,或者可以让它们变得兼容。首先从 WAR 中清理出所有 REST 或简单的 JMS 服务,然后将每个服务部署为它自己的 WAR。在这个层面上,配套 JAR 文件的副本是没问题的;主要仍然是包装问题。
  • 第 2 种情况:现有的 SOAP 或 EJB 服务:如果您已拥有一些服务,它们可能是遵循某种功能方法(比如 Service Façade 模式)构建的。在这种情况下,以功能为基础的服务设计通常可以被重构为基于资产的服务设计。这是因为,在许多情况下,Service Façade 中的功能最初都被编写成在单个对象上的 CRUD(创建、检索、更新和删除)操作。如果是这种情况,可以简单地映射到一个 RESTful 接口:只需将 EJB 会话 bean 接口或 JAX-WS 接口重新实现为 JAX-WS 接口。为此,您可能需要将对象表示转换成 JSON,但这通常不是很困难的,尤其在您已经使用了 JAX-B 进行序列化时。


    在不是一组简单的 CRUD 操作的情况下(比如,转账),那么,您可以应用一些不同的方法来构造 RESTful 服务(比如构建 /accounts/transfer 等简单的功能服务),实现 Command 的异体模式。

  • 第 3 种情况:简单的 Servlet/JSP 接口:许多 Java 程序其实只是连接到数据库表的简单的 Servlet / JSP 前端。它们可能完全没有所谓的 “域对象” 层,特别是在它们遵循 Active Record 等设计模式时。在这种情况下,创建域层,然后可以将它表示为一个 RESTful 服务,这是一个良好的开端。通过应用域驱动的设计 (Domain Driven Design),确定您的域对象,这将帮助您确定缺少的域服务层。一旦构建了域层(并将每一个新的服务包装自己的 WAR),您就可以重构现有的 Servlet / JSP 应用程序来使用新的服务,或者您也可以构建一个全新的界面,也许使用 Javascript、HTML5 和 CSS,或者作为原生移动应用程序。

第 3 步. 重构数据

一旦构建并重新打包在上述三种情况下定义的小服务,您可能会希望将注意力转移到可能是采用微服务的最困难的问题:重构作为您的应用程序的构建基础的数据结构。我们将在本系列的第 2 部分更深入地探讨这个难题。但在最简单的情况下,也可以遵循一些规则:

  1. 数据孤岛:从查看您的代码使用的数据库表开始。如果您使用的表独立于其他所有表,或者通过关系联接的几个表进入一个 “孤岛”,那么您可以只将那些表从数据设计中拆分出来。完成这项工作后,您就可以考虑采用适当的服务选项。

    例如,您想留在 SQL 中,或许可以考虑从重量级的企业级数据库(如 Oracle)迁移到一个较小的自包含数据库(比如 MySQL)?或者,可以考虑用 NoSQL 数据库来取代 SQL 数据库?该问题的答案取决于您对数据执行的实际查询类型。如果大多数的查询都是对 “主” 键的简单查询,那么一个 “键-值” 数据库或文档数据库就能很好地满足您的要求。另一方面,如果您确实有变化很大的复杂联接(例如,您的查询是不可预测的),那么,继续用 SQL 可能是您最好的选择。

  2. 批量数据更新:如果只有几个关系,而且您决定将数据迁移到 NoSQL 数据库,那么可以考虑是否只对现有的数据库做一个批量更新。通常情况下,在考虑表之间的关系时,没有将时间因素考虑在内;它们可能并不需要始终是最新的。每隔几个小时运行一次的数据转储/加载方法在许多情况下都是可行的。
  3. 表非标准化:如果您对其他表的关系较多,您可以重构(或用 DBA 术语,“非标准化”)表。现在,讨论这个话题也会让许多数据库管理员发怒。不过,如果退一步讲,您的团队是一个整体,所以应该想想,为什么要开始进行数据标准化。通常情况下,采用高度标准化架构的原因是为了减少重复,从而节省空间,因为磁盘空间很昂贵。然而,情况已发生改变。现在,我们要优化的是查询时间,而非标准化则是实现这个目标的一个简单方法。

结束语

现在您已经大致了解了重构到微服务的意义,以及在选择方法时要考虑哪些因素。好消息是,重构代码并不像想像中那么难,在很多情况下,它实际上是非常简单的。如果您仔细检查自己的代码,寻找这些(相对)简单的情况,您可能会发现,更复杂的代码段其实并不多见。

在这一系列的第 2 部分中,我们将更深入地探讨数据结构如何影响将微服务引入到应用程序中的方式的选择。

相关主题

  • 重构:改进现有代码的设计
  • 在 developerWorks 上的微服务电视节目
  • WebSphere Liberty 服务器开发人员中心
  • IBM Containers 入门
  • Delivery Pipeline 入门


推荐阅读
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 处理docker容器时间和宿主机时间不一致问题的方法
    本文介绍了处理docker容器时间和宿主机时间不一致问题的方法,包括复制主机的localtime到容器、处理报错情况以及重启容器的步骤。通过这些方法,可以解决docker容器时间和宿主机时间不一致的问题。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 本文介绍了在Docker容器技术中限制容器对CPU的使用的方法,包括使用-c参数设置容器的内存限额,以及通过设置工作线程数量来充分利用CPU资源。同时,还介绍了容器权重分配的情况,以及如何通过top命令查看容器在CPU资源紧张情况下的使用情况。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 1.脚本功能1)自动替换jar包中的配置文件。2)自动备份老版本的Jar包3)自动判断是初次启动还是更新服务2.脚本准备进入ho ... [详细]
  • (九)Docker常用安装
    一、总体步骤1、搜索镜像2、拉取镜像3、查看镜像4、启动镜像5、停止镜像6、移除镜像二、安装tomcat1、dockerhub上面查找tomcat镜像 dockersearchto ... [详细]
author-avatar
妈妈说称号长的人很牛也
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有