博客 | NGINX

微服务简介

NGINX-F5-horiz-black-type-RGB 的一部分
克里斯·理查森缩略图
克里斯·理查森
2015 年 5 月 19 日发布

2023 年 3 月微服务现已开放报名。 在此处查看议程并注册

编辑– 本系列文章共七部分,现已完成:

  1. 微服务简介(本文)
  2. 构建微服务: 使用 API 网关
  3. 构建微服务: 微服务架构中的进程间通信
  4. 微服务架构中的服务发现
  5. 微服务的事件驱动数据管理
  6. 选择微服务部署策略
  7. 将整体式架构重构为微服务

您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署

另请查看我们的微服务解决方案页面。

微服务目前受到了很多关注:文章、博客、社交媒体上的讨论和会议演示。 它们正迅速走向Gartner 成熟度曲线中膨胀预期的顶峰。 与此同时,软件社区中也有怀疑论者,他们认为微服务并不是什么新鲜事物。 反对者声称这个想法只不过是 SOA 的品牌重塑。 然而,尽管有炒作和怀疑,微服务架构模式仍然具有显著的优势——特别是在实现复杂企业应用的敏捷开发和交付方面。

这篇博客文章是关于设计、构建和部署微服务的七部分系列文章中的第一篇。 您将了解该方法以及它与更传统的单片架构模式的比较。 本系列将描述微服务架构的各种元素。 您将了解微服务架构模式的优点和缺点,它是否适合您的项目,以及如何应用它。

让我们首先了解一下为什么应该考虑使用微服务。

构建单体applications

假设你开始构建一个全新的出租车叫车应用,打算与 Uber 和 Hailo 竞争。 经过一些初步会议和需求收集之后,您可以手动创建一个新项目,或者使用 Rails、Spring Boot、Play 或 Maven 附带的生成器。 这个新的应用将具有模块化六边形架构,如下图所示:

模块化但仍然是整体式的架构,用作示例微服务应用的基础

应用的核心是业务逻辑,它由定义服务、领域对象和事件的模块实现。 核心周围是与外部世界交互的适配器。 适配器的示例包括数据库访问组件、生成和使用消息的消息传递组件以及公开 API 或实现 UI 的 Web 组件。

尽管具有逻辑模块化架构,但应用被打包并部署为整体式架构。 实际格式取决于应用程序的语言和框架。 例如,许多 Java应用被打包为 WAR 文件并部署在 Tomcat 或 Jetty 等应用服务器上。 其他 Java应用被打包为自包含的可执行 JAR。 类似地,Rails 和 Node.js应用被打包为目录层次结构。

以这种风格编写的应用极为常见。 由于我们的 IDE 和其他工具专注于构建单个应用,因此它们很容易开发。 这些类型的应用测试起来也很简单。 您只需启动应用并使用 Selenium 测试 UI 即可实现端到端测试。 单片应用也易于部署。 您只需将打包的应用复制到服务器即可。 您还可以通过在负载均衡器后运行多个副本来扩展应用。 在项目早期阶段,它运行良好。

迈向单体地狱

不幸的是,这种简单的方法有很大的局限性。 成功的应用往往会随着时间的推移而增长,并最终变得庞大。 在每个冲刺期间,您的开发团队都会实现更多的故事,这当然意味着要添加许多行代码。 几年后,你的小而简单的应用将会发展成一个庞大的整体。 举一个极端的例子,我最近与一位开发人员进行了交谈,他正在编写一个工具来分析其数百万行代码(LOC)应用中数千个 JAR 之间的依赖关系。 我确信,这样的庞然大物是经过大量开发人员多年的共同努力才打造出来的。

一旦您的应用变成一个庞大而复杂的整体,您的开发组织可能会陷入痛苦之中。 任何敏捷开发和交付的尝试都将失败。 一个主要问题是该应用过于复杂。 它实在太大了,任何单个开发人员都无法完全理解。 因此,修复错误和正确实现新功能变得困难且耗时。 更糟糕的是,这往往会形成恶性循环。 如果代码库难以理解,那么就无法正确地进行更改。 你最终会得到一个巨大而难以理解的泥球

应用的庞大规模也会减缓开发速度。 应用越大,启动时间越长。 例如,在最近的一项调查中,一些开发人员报告的启动时间长达 12 分钟。 我还听说过一些应用需要长达 40 分钟才能启动的故事。 如果开发人员需要定期重启应用服务器,那么他们一天中的大部分时间都将花在等待上,他们的工作效率就会受到影响。

大型复杂的单片应用的另一个问题是它会阻碍持续部署。 如今,SaaS应用的最新技术是每天多次将变更投入生产。 对于复杂的整体式应用程序来说,这极其困难,因为您必须重新部署整个应用才能更新其中的任何部分。 我之前提到的漫长的启动时间也无济于事。 此外,由于通常人们对变化的影响不是很清楚,因此您很可能必须进行大量的手动测试。 因此,持续部署几乎不可能实现。

当不同模块的资源需求相互冲突时,单片应用也难以扩展。 例如,一个模块可能实现 CPU 密集型图像处理逻辑,理想情况下应该部署在 Amazon EC2 计算优化实例中。 另一个模块可能是内存数据库,最适合EC2 内存优化实例。 但是,由于这些模块是一起部署的,因此您必须在硬件选择上做出妥协。

单片应用的另一个问题是可靠性。 由于所有模块都在同一个进程中运行,因此任何模块中的错误(例如内存泄漏)都可能导致整个进程崩溃。 此外,由于应用的所有实例都是相同的,该错误将影响整个应用的可用性。

最后但同样重要的一点是,单片应用使得采用新的框架和语言变得极其困难。 例如,假设您使用 XYZ 框架编写了 200 万行代码。 重写整个应用以使用较新的 ABC 框架会非常昂贵(在时间和成本方面),即使该框架相当好。 因此,采用新技术面临着巨大的障碍。 无论你在项目开始时做出了什么技术选择,你都会被困住。

总而言之:您有一个成功的关键业务应用,但它已发展成为一个巨大的整体,很少有开发人员能够理解。 它是使用过时的、低效的技术编写的,这使得聘请优秀的开发人员变得困难。 该应用难以扩展并且不可靠。 因此,应用的敏捷开发和交付是不可能的。

那么你能做什么呢?

微服务——应对复杂性

许多组织,例如亚马逊、eBay 和Netflix ,通过采用现在称为微服务架构模式的模式解决了这个问题。 其理念不是构建单个庞大的整体式应用,而是将应用拆分为一组较小的、相互连接的服务。

服务通常实现一组不同的特性或功能,例如订单管理、客户管理等。 每个微服务都是一个微型应用,具有自己的六边形架构,由业务逻辑和各种适配器组成。 一些微服务会公开供其他微服务或应用程序客户端使用的 API。 其他微服务可能会实现 Web UI。在运行时,每个实例通常都是一个云虚拟机或一个 Docker 容器。

例如,前面描述的系统的一种可能分解如下图所示:

示例叫车应用的微服务架构,每个微服务都提供一个 RESTful API

应用的每个功能区域现在都由其自己的微服务实现。 此外,Web应用被分成一组更简单的 Web应用(例如,在我们的出租车叫车示例中,一个用于乘客,一个用于司机)。 这使得为特定用户、设备或专门用例部署独特的体验变得更加容易。

每个后端服务都公开一个 REST API,并且大多数服务都使用其他服务提供的 API。 例如,驾驶员管理使用通知服务器来告知可用的驾驶员潜在的行程。 UI 服务调用其他服务来呈现网页。 服务也可能使用异步的、基于消息的通信。 本系列后面将更详细地介绍服务间通信。

一些 REST API 也暴露给司机和乘客使用的移动应用程序。 然而,这些应用程序无法直接访问后端服务。 相反,通信是由称为API 网关的中介来进行的。 API 网关负责负载均衡、缓存、访问控制、API 计量和监控等任务,可以使用 NGINX 有效实现。本系列的后续文章将介绍API 网关

Y 轴上功能分解为微服务的“规模立方体”

微服务架构模式对应于缩放立方体的 Y 轴缩放,这是来自优秀书籍《可扩展性的艺术》的可扩展性的 3D 模型。 另外两个扩展轴是 X 轴扩展,其包括在负载均衡器后面运行应用的多个相同副本,以及 Z 轴扩展(或数据分区),其中请求的属性(例如,行的主键或客户的身份)用于将请求路由到特定的服务器。

应用通常一起使用这三种类型的扩展。 Y 轴缩放将应用分解为微服务,如本节第一张图所示。 在运行时,X 轴扩展在负载均衡器后面运行每个服务的多个实例,以实现吞吐量和可用性。 一些应用可能还使用 Z 轴缩放来划分服务。 下图显示了如何使用 Docker 在 Amazon EC2 上部署行程管理服务。

出租车服务的示例微服务应用程序,部署在 Docker 容器中,前端设有负载均衡器

在运行时,行程管理服务由多个服务实例组成。 每个服务实例都是一个 Docker 容器。 为了实现高可用性,容器在多个云虚拟机上运行。服务实例前面是负载均衡器(如 NGINX) ,用于在实例之间分配请求。 负载均衡器还可以处理其他问题,例如缓存访问控制API 计量监控

微服务架构模式显著影响了应用和数据库之间的关系。 每个服务都有自己的数据库模式,而不是与其他服务共享单个数据库模式。 一方面,这种方法与企业范围数据模型的理念相矛盾。 此外,它常常会导致一些数据重复。 但是,如果您想从微服务中受益,那么每个服务拥有一个数据库模式至关重要,因为它可以确保松散耦合。 下图显示了示例应用的数据库架构。

乘车服务示例微服务应用中的数据库架构

每个服务都有自己的数据库。 此外,服务可以使用最适合其需求的数据库类型,即所谓的多语言持久性架构。 例如,寻找靠近潜在乘客的司机的司机管理必须使用支持高效地理查询的数据库。

从表面上看,微服务架构模式与 SOA 类似。 对于这两种方法来说,架构都由一组服务组成。 然而,思考微服务架构模式的一种方法是,它是没有商业化和感知负担的Web 服务规范(WS-*)和企业服务总线(ESB)的 SOA。 基于微服务的应用更喜欢 REST 等更简单、轻量级的协议,而不是 WS-*。 他们也极力避免使用 ESB,而是在微服务本身中实现类似 ESB 的功能。 微服务架构模式还拒绝了 SOA 的其他部分,例如规范模式的概念。

微服务的好处

微服务架构模式有许多重要的优点。 首先,它解决了复杂性问题。 它将原本庞大的整体应用分解为一组服务。 虽然总体功能没有变化,但应用已被分解为可管理的块或服务。 每个服务都有一个以 RPC 或消息驱动 API 形式明确定义的边界。微服务架构模式强制实施一定程度的模块化,而这在实践中很难通过单一代码库实现。 因此,单个服务的开发速度更快,并且更容易理解和维护。

其次,这种架构使得每个服务都可以由专注于该服务的团队独立开发。 只要服务遵守 API 契约,开发人员可以自由选择任何合理的技术。 当然,大多数组织都希望避免完全的混乱并限制技术选择。 然而,这种自由意味着开发人员不再有义务使用新项目开始时可能已经过时的技术。 在编写新服务时,他们可以选择使用当前技术。 此外,由于服务相对较小,因此使用当前技术重写旧服务变得可行。

第三,微服务架构模式使得每个微服务能够独立部署。 开发人员永远不需要协调其服务本地变更的部署。 这些变化一旦经过测试就可以立即部署。 例如,UI 团队可以执行 A/B 测试并快速迭代 UI 更改。 微服务架构模式使持续部署成为可能。

最后,微服务架构模式使每个服务能够独立扩展。 您可以仅部署满足其容量和可用性限制的每个服务的实例数。 此外,您可以使用最符合服务资源需求的硬件。 例如,您可以在 EC2 计算优化实例上部署 CPU 密集型图像处理服务,并在 EC2 内存优化实例上部署内存数据库服务。

微服务的缺点

正如弗雷德·布鲁克斯 (Fred Brooks) 近 30 年前所写,没有什么灵丹妙药。 与其他所有技术一样,微服务架构也有缺点。 一个缺点就是名字本身。 微服务这个术语过分强调服务规模。 事实上,有些开发人员主张构建极其细粒度的 10-100 LOC 服务。 虽然小型服务更可取,但重要的是要记住,它们只是达到目的的一种手段,而不是主要目标。 微服务的目标是充分分解应用,以促进敏捷应用的开发和部署。

微服务的另一个主要缺点是由于微服务应用是分布式系统而产生的复杂性。 开发人员需要选择并实现基于消息传递或 RPC 的进程间通信机制。此外,他们还必须编写代码来处理部分故障,因为请求的目的地可能很慢或不可用。 虽然这些都不是火箭科学,但它比单片应用程序复杂得多,在单片应用中,模块通过语言级方法/过程调用相互调用。

微服务的另一个挑战是分区数据库架构。 更新多个业务实体的业务交易相当常见。 由于只有一个数据库,因此这些类型的事务在单片应用中很容易实现。 然而,在基于微服务的应用中,您需要更新不同服务拥有的多个数据库。 使用分布式事务通常不是一个选择,而且不仅仅是因为CAP 定理。 当今的许多高度可扩展的 NoSQL 数据库和消息传递代理根本不支持它们。 您最终必须使用基于最终一致性的方法,这对开发人员来说更具挑战性。

测试微服务应用也更加复杂。 例如,使用 Spring Boot 等现代框架,编写一个测试类来启动一个整体式 Web应用并测试其 REST API 非常简单。相比之下,针对某项服务的类似测试类则需要启动该服务及其所依赖的任何服务(或至少为这些服务配置存根)。 再说一次,这不是火箭科学,但重要的是不要低估这样做的复杂性。

微服务架构模式的另一个主要挑战是实现跨多个服务的变更。 例如,假设您正在实现一个需要更改服务 A、B 和 C 的故事,其中 A 依赖于 B,而 B 依赖于 C。在单片应用中,您可以简单地更改相应的模块,集成更改,然后一次性部署它们。 相比之下,在微服务架构模式中,您需要仔细规划和协调对每个服务的更改的推出。 例如,您需要更新服务 C,然后更新服务 B,最后更新服务 A。幸运的是,大多数更改通常只影响一项服务,而需要协调的多服务更改相对较少。

部署基于微服务的应用也更加复杂。 单片应用只是部署在传统负载均衡器后面的一组相同的服务器上。 每个应用实例都配置了数据库和消息代理等基础设施服务的位置(主机和端口)。 相比之下,微服务应用通常由大量服务组成。 例如,根据Adrian Cockcroft的说法,Hailo 有 160 种不同的服务,而 Netflix 则有 600 多种服务 [编辑 - Hailo 已被 MyTaxi 收购。] 。 每个服务都会有多个运行时实例。 还有更多活动部件需要配置、部署、扩展和监控。 此外,您还需要实现一个服务发现机制(在后面的文章中讨论),使服务能够发现它需要与之通信的任何其他服务的位置(主机和端口)。 传统的基于故障单和手动的操作方法无法扩展到这种复杂程度。 因此,成功部署微服务应用需要开发人员对部署方法有更强的控制力,并实现高度的自动化。

实现自动化的一种方法是使用现成的 PaaS,例如Cloud Foundry 。 PaaS 为开发人员提供了一种部署和管理其微服务的简便方法。 它使他们免于采购和配置 IT 资源等担忧。 同时,配置 PaaS 的系统和网络专业人员可以确保遵守最佳实践和公司政策。 自动化部署微服务的另一种方法是开发本质上属于您自己的 PaaS。 一个典型的起点是使用集群解决方案(例如Kubernetes )与 Docker 等技术结合。 在本系列的后面,我们将研究如何利用像 NGINX Plus 这样的基于软件的应用交付方法来帮助解决这个问题,它可以轻松处理微服务级别的缓存、访问控制、API 计量和监控。

概括

构建复杂的应用本身就很困难。 单片架构只适用于简单、轻量级的应用。 如果将它用于复杂的应用,最终您将陷入痛苦之中。 尽管存在缺点和实施挑战,但微服务架构模式对于复杂且不断发展的应用来说是更好的选择。

在以后的博客文章中,我将深入探讨微服务架构模式的各个方面的细节,并讨论服务发现、服务部署选项以及将单片应用重构为服务的策略等主题。

敬请关注…

编辑– 本系列文章共七部分,现已完成:

  1. 微服务简介(本文)
  2. 构建微服务: 使用 API 网关
  3. 构建微服务: 微服务架构中的进程间通信
  4. 微服务架构中的服务发现
  5. 微服务的事件驱动数据管理
  6. 选择微服务部署策略
  7. 将整体式架构重构为微服务

您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署

客座博主 Chris Richardson 是原CloudFoundry.com的创始人,该网站是针对 Amazon EC2 的早期 Java PaaS(平台即服务)。 他现在为各组织提供咨询服务,以改进他们开发和部署应用的方式。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”