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