微服务架构远非一种新趋势;它通常被认为是当今构建应用程序的更好方式。几年前,构建应用程序的常用方法是单体式方法——从功能角度来看,基本上就是一个执行所有操作的部署单元。单体式应用程序适用于小型团队和项目,但是当您需要更大规模并且涉及多个团队的东西时,它开始变得有问题。进行更改变得更加困难,因为代码库变得更大,并且更多人对其进行更改。
这基本上与持续交付完全相反,因为它更紧密耦合,并且需要呈指数增长的协调量才能进行持续更新。因此,更新变得更加痛苦且频率更低,进一步加剧了应用程序的脆弱性。
那么,微服务到底是什么?这种架构如何改进交付周期呢?
微服务的开发是为了分而治之。
基本上,微服务方法简而言之规定,与其拥有一个庞大的代码库让所有开发人员接触,而这通常变得难以管理,不如拥有由小型敏捷团队管理的许多较小的代码库。这些代码库彼此之间唯一的依赖关系是它们的 API。这意味着,只要您保持向前和向后兼容性(尽管这并非易事),每个团队就可以在与其他团队解耦的发布周期中工作。在某些情况下,这些发布周期是耦合的,其中一个服务依赖于另一个服务,或者依赖于另一个服务中的新功能,但这并非通常情况。
当时,像 Netflix 或 Amazon 这样的公司在这方面处于领先地位。他们决定,与其构建一个单体式应用程序来处理其服务的所有方面,不如构建处理离散业务功能的小型服务。这些单元之间的边界是功能性 API,它们公开每个服务的核心功能。对于 Amazon.com 来说,这将是他们网站的不同方面——推荐、购物车、发票、库存管理等等。Amazon 没有将所有这些都作为一个巨大的部署单元的一部分,而是将每个功能都实现为一个具有明确定义的接口的自包含服务。这样做的好处是,您可以拥有不同的团队,每个团队负责其服务从 A 到 Z 的所有方面。因此,如果有一个团队负责计费,他们将负责从编写代码、测试代码、推送到生产环境、处理故障以及该服务可能发生的任何其他事情的所有工作。
毋庸置疑,这对于持续交付来说更好,因为小单元更易于管理、测试和部署。
好的,那么与开源有什么联系呢?
一个例子是 Netflix。作为这种架构趋势的领导者,Netflix 还将其许多工具构建为 开源项目,这些工具便于他们分布式和复杂的架构,任何人都可以 fork 并自定义,这在某种程度上也影响了随之而来的一长串技术。其中一项技术是 Kubernetes,它专门为微服务而设计,通过扩展 Docker 的功能。这使公司能够为工作选择合适的工具,并快速采用它们,而无需复杂的许可周期,还可以根据其特定的架构和业务需求来调整和扩展它们。
听起来好得难以置信?
当然,有好的一面,总有坏的一面。这引发了另一系列问题,例如全面理解系统,什么依赖于什么,以及当一个服务失败时,它将导致级联故障的可能性更高,而级联故障更难追踪。有关微服务架构带来的权衡的更多信息,请阅读 ThoughtWorks 的这篇佳作。
“使用这样的服务确实有缺点。远程调用比进程内调用更昂贵,因此远程 API 需要更粗粒度,这通常更难使用。如果您需要更改组件之间责任的分配,那么当您跨越进程边界时,行为的转移会更难做到。”
为什么 Docker 非常适合微服务?
如果我们深入技术层面,Docker 非常适合微服务,因为它将容器隔离到一个进程或服务。这种有意的单个服务或进程的容器化使得管理和更新这些服务变得非常简单。因此,毫不奇怪,Docker 之上的下一波浪潮导致了框架的出现,这些框架的唯一目的是管理更复杂的场景,例如:如何在集群中管理单个服务,或跨主机在服务中管理多个实例,或如何在部署和管理级别协调多个服务。
为此,我们看到了像 Kubernetes、Maestro-ng、Mesos 和 Fleet 这样的开源项目涌现出来,以回应这种日益增长的需求。如果我们看一下 Kubernetes,例如,它现在真的越来越流行,它由 Google 支持,并且现在看到像 Microsoft 和 Red Hat 这样的主要参与者加入;这个项目是为微服务而构建的,通过提供一些关键功能。
使用 Kubernetes,您可以通过智能标签系统轻松部署和管理相同类型的多个 Docker 容器。您基本上描述您要部署的映像的特性——例如实例数量、CPU、RAM——Kubernetes 将根据您部署到的主机集合上物理上可用的资源为您分配。您无需关心这些物理位置在哪里,因为标签系统使您能够唯一标识您的映像。在标签之上,您可以创建另一个分组级别,称为“pods”,它们本质上是对具有一个或多个标签的容器的持续查询。Kubernetes 不断更新满足查询的容器集合,并在这些容器之间实现负载均衡,以便任何从外部访问它们的人都有一个单一端点。

由 Codemotion 提供。
这种格式非常适合微服务和 Docker,因为它满足了微服务架构如此重要的确切特性——轻松部署新服务(这就是 Docker 打包发挥作用的地方)、独立扩展每个微服务、使单个微服务实例的故障对访问它的客户端透明,并实现基于名称的简单、临时的服务端点发现。
缺少什么?
当涉及到您可以跨负载均衡的简单、无状态服务,以及所有实例完全相同时,这一切都非常有用。这种服务的一个好例子是某种类型的 Web 服务或无状态 Web 应用程序。
当您有状态服务,或者当微服务本身由多个部分组成时(例如数据库或消息队列),事情会变得有点复杂。Kubernetes 有一个隐含的假设,即服务实例之间共享的所有状态(例如存储用户配置文件的 Mongo 集群)都在 Kubernetes 之外管理。
然而,在许多情况下,您想要管理的是由多个层(Web、数据库、消息传递等)组成的,这些层彼此依赖。因此,通常情况下,如果不是不可能,那么用 Kubernetes 完成这将很困难。Kubernetes 专为每个容器实际上都是自包含且可复制的情况而设计;很多时候情况并非如此。如果您想自动化部署和管理非微服务的应用程序层(例如中央数据存储库,例如 Hadoop 或 Cassandra),情况也是如此。后两者无法部署在 Kubernetes 之上(尽管像 Redis 这样更简单的东西是可以的)。

由 Martin Fowler 提供。
在这种情况下,您需要一个能够描述更复杂拓扑和部署的编排器——这就是 TOSCA 融入其中的地方。
TOSCA 的想法是以最理想的方式部署每个部分。如果是简单的无状态微服务,那么最好的方法是使用 Docker 和 Kubernetes(或类似的东西)。当您处理需要复杂编排的更复杂拓扑(例如完全复制和分片的 mongo 集群,或更复杂的微服务)时,这将是使用 TOSCA 蓝图的场景。自然地,TOSCA 蓝图也可以用于前一种情况(即衍生几个 Docker 镜像实例),如果您想坚持单一的做事方式。
这种实现的一个例子是 Cloudify Docker 编排插件,该插件利用 TOSCA 进行简单的微服务部署(使用 TOSCA 输出参数作为公开特定服务端点的手段),并通过支持复杂应用程序堆栈的编排来实现更复杂的拓扑。基于这种方法,您还可以获得支持部署后关注点的额外好处,例如自动扩展、监控和自动修复,这些都是通过 Cloudify 基于 TOSCA 的蓝图实现的。
5 条评论