在最近的一些博客文章中,我们解释了为什么我们认为采用四层应用架构至关重要,在该架构中,应用以微服务集的形式进行开发和部署。 越来越明显的是,如果你继续使用十年前运行良好的开发流程和应用架构,那么你根本无法快速吸引和留住可以从不断增长的应用程序中进行选择的移动用户的兴趣。
转换到微服务架构将为公司在市场上创造令人兴奋的机会。 对于系统架构师和开发人员来说,它承诺在向客户提供创新的全新网络体验时提供前所未有的控制和速度水平。 但在如此令人喘不过气来的速度下,感觉好像没有太多犯错的余地。 在现实世界中,您无法停止开发和部署应用程序,因为您需要重新调整流程。 您知道您未来的成功取决于向微服务架构的过渡,但您实际上该如何做呢?
对我们来说幸运的是,一些微服务的早期采用者现在正本着开源精神慷慨地分享他们的专业知识,不仅以发布代码的形式,还以会议演示和博客文章的形式。 Netflix就是一个典型的例子。 作为网络工程总监和云架构师,Adrian Cockcroft 见证了公司从传统开发模式(由 100 名工程师开发单一的 DVD 租赁应用)向微服务架构的转变,该架构由许多小团队负责数百个微服务的端到端开发,这些微服务协同工作,每天向数百万 Netflix 客户提供流媒体数字娱乐。 Cockcroft现在是 Battery Ventures 的技术研究员,是微服务和云原生架构的杰出推动者,并担任 NGINX 技术顾问委员会成员。
在由两部分组成的系列博客文章中,我们将介绍 Cockcroft 去年在 10 月份的第一届年度 NGINX 大会以及几个月前的硅谷微服务聚会上发表的两次演讲的主要内容。 (完整的视频录像也非常值得一看。)
Cockcroft 将微服务架构定义为由具有有界上下文的松散耦合元素组成的面向服务的架构。
松散耦合意味着您可以独立更新服务;更新一项服务不需要更改任何其他服务。 如果您有一堆小型、专业化的服务,但仍然需要一起更新它们,那么它们就不是微服务,因为它们不是松散耦合的。 在过渡到微服务架构时,人们往往会忽视一种耦合,那就是数据库耦合,即所有服务都与同一个数据库通信,而更新服务意味着更改模式。 您需要拆分数据库并使其非规范化。
有界上下文的概念源自Eric Evans所著的《领域驱动设计》一书。 对于软件开发而言,具有正确界限上下文的微服务是自包含的。 您可以理解和更新微服务的代码,而无需了解其对等体的内部情况,因为微服务及其对等体严格通过 API 进行交互,因此不共享数据结构、数据库模式或对象的其他内部表示。
如果您已经开发过互联网应用,那么您已经熟悉这些概念,即使不知道名字,也是在实践中。 大多数移动应用都会与相当多的后端服务进行通信,以便用户能够在应用环境中执行诸如在 Facebook 上分享、从 Google 地图获取路线以及在 Foursquare 上查找餐馆等操作。如果您的移动应用与这些服务紧密结合,那么在发布更新之前,您必须与所有开发团队进行沟通,以确保您的更改不会破坏任何内容。
在使用微服务架构时,您会将其他内部开发团队视为那些 Internet 后端:作为您的微服务通过 API 与之交互的外部服务。 微服务之间通常理解的“契约”是它们的 API 是稳定的并且向前兼容。 正如 Google Maps API 未经警告而发生更改并且以损害用户利益的方式发生更改是不可接受的一样,您的 API 可以发展但必须与以前的版本保持兼容。
Cockcroft 认为他在 Netflix 担任云架构师的职责并不是控制架构,而是发现和规范 Netflix 工程师构建架构时出现的架构。 Netflix 开发团队为设计和实施微服务架构建立了几种最佳实践。
不要在微服务之间使用相同的后端数据存储。 您希望每个微服务的团队选择最适合该服务的数据库。 此外,使用单一数据存储,不同团队编写的微服务很容易共享数据库结构,也许是为了减少重复工作。 最终你会遇到这样的情况:如果一个团队更新了数据库结构,那么使用该结构的其他服务也必须改变。
拆分数据会使数据管理更加复杂,因为单独的存储系统更容易不同步或变得不一致,并且外键可能会发生意外变化。 您需要添加一个执行主数据管理(MDM) 的工具,通过在后台运行来查找和修复不一致之处。 例如,它可能会检查每个存储订阅者 ID 的数据库,以验证所有数据库中是否存在相同的 ID(任何一个数据库中没有缺失或多余的 ID)。 您可以编写自己的工具或者购买一个。 许多商业关系数据库管理系统 (RDBMS) 都会进行此类检查,但它们通常对耦合提出太多要求,因此无法扩展。
保持微服务中的所有代码具有相似的成熟度和稳定性。 换句话说,如果您需要在已部署的运行良好的微服务中添加或重写部分代码,最好的方法通常是为新代码或更改的代码创建一个新的微服务,同时保留现有的微服务。 [编辑 – 这有时被称为不可变基础设施原则。]这样,您可以迭代部署和测试新代码,直到它没有错误且效率最高,而不会冒现有微服务出现故障或性能下降的风险。 一旦新的微服务与原有微服务一样稳定,如果它们确实一起执行单一功能,或者合并它们可以提高其他效率,您就可以将它们重新合并在一起。 然而,根据 Cockcroft 的经验,更常见的情况是,人们意识到应该拆分微服务,因为它变得太大了。
为每个微服务进行单独构建,以便它可以从适合它的修订级别的存储库中提取组件文件。 这有时会导致各种微服务提取一组相似的文件,但修订级别不同的情况。 通过停用旧文件版本可能会使清理代码库变得更加困难(因为您必须更仔细地验证修订版本是否不再使用),但对于在构建新的微服务时添加新文件的难易程度来说,这是一个可以接受的权衡。 这种不对称是故意的:你希望引入新的微服务、文件或功能变得容易,而不是危险。
在容器中部署微服务很重要,因为这意味着您只需要一个工具即可部署所有内容。 只要微服务在容器中,该工具就知道如何部署它。 容器是什么并不重要。 话虽如此,Docker 似乎很快就成为了容器的事实标准。
将服务器(特别是运行面向客户的代码的服务器)视为组中可互换的成员。 它们都执行相同的功能,因此您不需要单独关心它们。 您唯一关心的是它们的数量是否足够多,能够完成您需要的工作量,并且您可以使用自动缩放功能来上下调整数字。 如果一个停止工作,它就会自动被另一个取代。 避免依赖单个服务器来执行专门功能的“雪花”系统。
考克饶夫 (Cockcroft) 的比喻是,你要将服务员视为牛,而不是宠物。 如果你在生产过程中有一台执行专门功能的机器,并且你知道它的名字,当它发生故障时每个人都会感到难过,那么它就是宠物。 相反,你应该把你的服务器想象成一群牛。 您关心的是可以获得多少加仑牛奶。 如果有一天你发现产奶量比平时少,你就会找出哪些奶牛产奶量不佳,然后将其替换掉。
Netflix 是 NGINX Open Source 的长期用户,并在 2011 年 NGINX, Inc. 成立后成为其首个客户。 事实上, Netflix 选择 NGINX作为其交付基础设施 Open Connect 的核心, Open Connect是世界上最大的内容交付网络 (CDN) 之一。 NGINX 和 NGINX Plus 每秒能够处理数千个甚至数百万个请求,是高性能 HTTP 交付的最佳解决方案,使 Netflix 等公司能够每天为数百万客户提供高质量的数字体验。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”