编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优点与挑战。nginx
做者介绍:Chris Richardson,是世界著名的软件大师,经典技术著做《POJOS IN ACTION》一书的做者,也是 cloudfoundry.com 最初的创始人,Chris Richardson 与 Martin Fowler、Sam Newman、Adrian Cockcroft 等并称为世界十大软件架构师。web
Chris Richardson 所著全部文章已独家受权 DaoCloud 翻译并刊载。docker
本期内容
微服务在当下引发普遍关注,成为文章、博客、社交媒体讨论和大会演讲的热点;在 Gartner 的 “Hype Cycle” 上排名也很是靠前。与此同时,在软件社区也有人质疑微服务并不是新事物。反对者认为微服务只是 SOA (Service Oriented Architecture)的二度包装。然而,不管是追捧仍是质疑,微服务架构拥有巨大优点,尤为是它让敏捷开发和复杂的企业应用交付成为可能。数据库
本系列包含 7 篇文章,介绍了微服务的设计、构建和部署,并与传统的单体架构进行了比较。本系列将分析微服务架构的各类因素,你也将了解微服务架构模型的优劣、是否适合你的项目,以及如何应用。后端
Chris Richardson 微服务系列全 7 篇:缓存
1. 微服务架构概念解析服务器
2. 构建微服务架构:使用 API Gateway网络
3. 深刻微服务架构的进程间通讯架构
4. 服务发现的可行方案以及实践案例app
5. 微服务的事件驱动数据管理
6. 选择微服务部署策略
7. 将单体应用改造为微服务
首先让咱们了解为什么要将微服务归入考量。
构建单体应用
假设咱们要开发一款全新的与 Uber 和 Hailo 竞争的打车软件。在前期的会议和需求整理后,你要么须要手动建立一个新项目,要么可使用 Rails、Spring Boot、Play 或者 Maven 来生成。这个新应用可能采用了六边形架构模块,以下图所示:
应用的核心是商业逻辑,它由定义服务、域对象和事件各模块来完成。各类适配器围绕核心与外部交互。适配器包括数据库访问组件、生成和 consume 信息的消息组件,以及提供 API 或者 UI 访问支持的 web 模块。
尽管拥有逻辑缜密的模块化设计,整个应用仍然以总体打包和部署,实际格式依赖于应用的语言和框架。譬如,许多 Java 应用被打包为 WAR 文件,部署在 Tomcat 或者 Jetty 这样的应用服务器。有些 Java 应用自己就是包涵 JARs 的软件包。与此相似,Rails 和 Node.js 应用也经过目录层级打包。
采用此种风格的应用很是广泛。因为 IDE 和其余工具擅长构建单一应用,这类应用也易于部署。这类应用也很是容易测试。你能够很是轻松地进行端到端测试,使用 Selenium 测试 UI 。总体应用也便于部署,只需将软件包复制到服务器。你也能够经过运行多个包和负载均衡实现扩展。在项目早期这么作很是有效。
踏入单体架构的地狱
很不幸,这一简单的方法有着巨大的局限。成功的应用最终会随着时间变得巨大。在每一个 sprint 阶段,开发团队都会新加许多行代码。几年后,本来小而简单的应用会变得臃肿。举个极端的例子,我最近与一位开发者交流,他正在开发一款小工具,来分析他们应用(包括几百万行代码)中的几千个 JARs 的依赖。我相信每一年都会有大量开发者竭尽全力地对付这种麻烦。
一旦你的应用变得庞大、复杂,你的开发团队将饱受折磨,苦苦挣扎于敏捷开发和交付。一大缘由就是应用已经格外复杂,庞大到任何一个开发者都没法彻底理解。最后,修复 bug 和实施新功能也就极其困难且耗时颇多。更可怕的是,这是一个向下的螺旋发展。代码库越难理解,正确的修改就越难。最后你会深陷庞大的、没法估量的泥淖之中。
而这种应用的尺寸也会拖慢开发进度。应用越大,启动时间越长。譬如在最近的调查中,很多开发者指出启动时间长达 12 分钟。我也据说有的应用启动时间竟然得 40 分钟。若是开发者不得不频繁重启应用服务器,那大量时间就被浪费,生产效率也饱受其害。
庞大且复杂的单体应用的另外一大问题就是难以进行持续部署。如今, SaaS 应用的发展水平足以在单日内屡次将修改推送到生产环境。然而要让复杂的单个应用达到此水平却极为棘手。想更新应用的单个部分,必须从新部署整个应用,漫长的启动时间更是雪上加霜。另外,因为不能彻底预见修改的影响,你不得不提早进行大量人工测试。结果就是,持续部署变得不可能。
若是单体应用的不一样模块在资源需求方面有冲突的话,那应用的扩展也很难。好比,模块之一须要执行 CPU-intensive 图像处理逻辑,最好部署到 AWS 的 EC2 Compute Optimized instances;而另外一模块须要内存数据库,最好适配 EC2 Memory-optimized instances。因为这两个模块须要共同部署,你不得不在在硬件选择方面作妥协。
单体应用的另外一问题就是可靠性。因为全部模块都运行在同一进程中,任何模块中的一个 bug,好比内存泄漏均可能弄垮整个进程;此外,因为应用中的全部实例都是惟一,这个 bug 将影响整个应用的可用性。
最后,单体应用会让采用新框架和语言极其困难。举例来讲,你有两百万行使用 XYZ 框架的代码,若是要使用 ABC 框架重写代码,不管时间仍是成本都将很是高昂,即使新框架更好。这也就成为使用新技术的阻碍。
总结:这个一开始曾经成功关键业务应用,最终却变成一个臃肿的、没法理解的庞然大物。它使用老旧、陈腐、低效的技术,几乎吸引不到出色的开发者。这个应用很是难于扩展,也不稳定可靠。最终,敏捷开发和交付几乎成为不可能。
你该何去何从?
微服务——直击痛点
诸如亚马逊、eBay、Netflix 等公司已经经过采用微服务架构范式解决了上文(第一部分)提到的问题。不一样于构建单1、庞大的应用,微服务架构将应用拆分为一套小且互相关联的服务。
一个微服务通常完成某个特定的功能,好比订单管理、客户管理等。每一个微服务都是一个微型应用,有着本身六边形架构,包括商业逻辑和各类接口。有的微服务经过暴露 API 被别的微服务或者应用客户端所用;有的微服务则经过网页 UI 实现。在运行时,每一个实例一般是一个云虚拟机或者 Docker 容器。
对于前文所述的系统,一种可能的系统分解图以下:
应用的每一个功能区都由其自身微服务实施。此外,整个网页应用被拆分为一套简单的网页应用(好比咱们的打车软件拆分为乘客应用和司机应用),从而可以轻松地针对特定用户、设备或者用户案例进行单独部署。
每一个后端服务包括一个 REST API 和由其它服务提供的服务消耗 API。例如,司机管理服务使用“通知”服务器来告知司机即将的行程。UI 服务唤醒其它服务,从而呈现网页。这些服务也可能用到基于信息的异步通讯。内部服务通讯会在本系列文章中详述。
有的 REST API 也对司机和乘客的移动应用开放。这些应用并不能直接访问后端服务器,相反,通讯由名为 API Gateway 的中间人调解。AIP Gateway 负责负载均衡、缓存、访问控制、API 计费、监控等,经过 NGINX 高效实施。本系列的后续文章将会讲解 API Gateway。
上图是 Scale Cube 的 3D 模型,来自《The Art of Scalability》 一书。微服务架构范式对应 Y 轴,X 轴由负载均衡器后端运行的多个应用副本组成,Z 轴(数据分割)将需求路由到相关服务。
应用一般同时使用这三种不一样类型的扩展。Y 轴扩展将应用分解为如图一(https://www.nginx.com/wp-content/uploads/2015/05/Graph-031-e1431992337817.png)所示的微服务。在运行时维度,X 轴扩展在输出和可用性的负载均衡后运行多个实例。部分应用会使用 Z 轴扩展来对服务进行数据分割。下图展现了行程管理服务(Trip Management)是如何使用 Docker 部署到 AWS EC2 上的。
在运行时,行程管理服务包括多个服务实例,每一个服务实例都是一个 Docker 容器。为了实现高可用性,这些容器运行在多个云虚拟机上。在应用实例前面是 NGINX 这样的负载均衡,将请求分发给所有实例。负载均衡也能够处理缓存、访问控制、 API 测量和监控等。
微服务架构范式对应用和数据库的关系影响巨大。每一个服务都有自身的数据库计划,而不与其它服务共享同一个数据库。一方面,这个方法相似企业级数据模型。同时,它也致使部分数据的重复。然而,要想从微服务中获益,为每一个服务提供单个的数据库计划就很是必要,这能保证松散耦合。下面的图表展现了示例应用的数据库架构。
每一个服务都有其本身的数据库。此外,单个服务可使用符合本身须要的特定类型的数据库,即多语言一致性架构。例如,为了发现附近乘客,驾驶员管理服务必须使用高效支持地理位置请求的数据库。
表面上看,微服务架构范式与 SOA 很是相似,这两种架构都包括一套服务。然而,微服务架构范式被看做不包含某些功能的 SOA 。这些功能包括网络服务说明( WS-* )和 Enterprise Service Bus (ESB) 的商品化和请求包。基于微服务的应用更青睐 REST 这样简单的、轻量级的协议,而不是 WS-* 。他们也极力避免在微服务中使用 ESBs 及相似功能。微服务架构范式也拒绝 SOA 的其它部分,好比 canonical schema 的概念。
微服务架构的好处
微服务架构模式有不少好处。首先,经过分解巨大单体应用为多个服务方法解决了复杂性问题。在功能不变的状况下,应用被分解为多个可管理的分支或服务。每一个服务都有一个用 RPC- 或者消息驱动 API 定义清楚的边界。微服务架构模式给采用单体式编码方式很难实现的功能提供了模块化的解决方案,由此,单个服务很容易开发、理解和维护。
第二,这种架构使得每一个服务均可以有专门开发团队来开发。开发者能够自由选择开发技术,提供 API 服务。固然,许多公司试图避免混乱,只提供某些技术选择。而后,这种自由意味着开发者不须要被迫使用某项目开始时采用的过期技术,他们能够选择如今的技术。甚至于,由于服务都是相对简单,即便用如今技术重写之前代码也不是很困难的事情。
第三,微服务架构模式使得每一个微服务独立部署,开发者再也不须要协调其它服务部署对本服务的影响。这种改变能够加快部署速度,譬如 UI 团队能够采用 AB 测试并快速部署变化。微服务架构模式使得持续化部署成为可能。
最后,微服务架构模式使得每一个服务独立扩展。你能够根据每一个服务的规模来部署知足需求的实利。甚至于,你可使用更适合于服务资源需求的硬件。好比,你能够在 EC2 Compute Optimized instances 上部署 CPU 敏感的服务,而在 EC2 memory-optimized instances 上部署内存数据库。
微服务架构的不足
Fred Brooks 在 30 年前写道 “there are no silver bullets”,像任何其它科技同样,微服务架构也有不足。其中一个跟他的名字相似,“微服务”强调了服务大小,实际上,有一些开发者鼓吹创建稍微大一些的,10-100 LOC服务组。尽管小服务更乐于被采用,可是不要忘了微服务只是结果,而不是最终目的。微服务的目的是有效的拆分应用,实现敏捷开发和部署。
另一个不足之处在于,微服务应用是分布式系统,由此会带来固有的复杂性。开发者须要在 RPC 或者消息传递之间选择并完成进程间通信机制。此外,他们必须写代码来处理消息传递中速度过慢或者不可用等局部失效问题。固然这并非什么难事,但相对于单体式应用中经过语言层级的方法或者进程调用,微服务下这种技术显得更复杂一些。
另一个关于微服务的挑战来自于分区的数据库架构。同时更新多个业务主体的事务很广泛。这种事务对于单体式应用来讲很容易,由于只有一个数据库。在微服务架构应用中,须要更新不一样服务所使用的不一样的数据库。使用分布式事务并不必定是好的选择,不只仅是由于 CAP 理论,还由于当前高扩展性的 NoSQL 数据库和消息传递中间件并不支持这一需求。最终你不得不使用一个最终一致性的方法,从而对开发者提出了更高的要求和挑战。
测试一个基于微服务架构的应用也是很复杂的任务。好比,对于采用流行的 Spring Boot 架构的单体式 web 应用,测试它的 REST API,是很容易的事情。反过来,一样的服务测试须要启动与它有关的全部服务(至少须要这些服务的 stubs)。再重申一次,不能低估了采用微服务架构带来的复杂性。
另一个挑战在于,微服务架构模式应用的改变将会波及多个服务。好比,假设你在完成一个案例,须要修改服务A、B、C,而 A 依赖 B,B 依赖 C。在单体应用中,你只须要改变相关模块,整合变化,部署就行了。对比之下,微服务架构模式就须要考虑相关改变对不一样服务的影响。好比,你须要更新服务 C,而后是 B,最后才是 A。幸运的是,许多改变通常只影响一个服务,而须要协调多服务的改变不多。
部署一个微服务应用也很复杂,一个单体应用只须要在复杂均衡器后面部署各自的服务器就行了。每一个应用实例是须要配置诸如数据库和消息中间件等基础服务。相比之下,一个微服务应用通常由大批服务构成。根据 Adrian Cockcroft 的分享,Hailo 由 160 个不一样服务构成,而 NetFlix 则超过 600 个服务。每一个服务都有多个实例,这就造成大量须要配置、部署、扩展和监控的部分。除此以外,你还须要完成一个服务发现机制(后续文章中发表),以用来发现与它通信服务的地址(包括服务器地址和端口)。传统的解决问题办法并不能解决这么复杂的问题。最终,成功部署一个微服务应用须要开发者有足够的控制部署方法,并高度自动化。
自动化的方法之一是使用譬如 Cloud Foundry 这样的 PaaS 服务。PaaS 能让开发者轻松部署和管理微服务,让他们无需为获取并配置 IT 资源劳神。同时,配置 PaaS 的系统和网络专家能够采用最佳实践和策略来简化这些问题。另一个自动部署微服务应用的方法是开发本身的基础 PaaS 系统。一般的起步方式是 Mesos 或 Kubernetes 这样的集群管理方案,配合 Docker 使用。做为一种基于软件的应用交付方法,NGINX 可以方便地在微服务层面提供缓冲、权限控制、API 统计、以及监控。咱们会在后续的文章中分析它如何解决这些问题。
总结
构建复杂的应用的确很是困难。单体式的架构更适合轻量级的简单应用。若是你用它来开发复杂应用,那真的会很糟糕。微服务架构模式能够用来构建复杂应用,固然,这种架构模型也有本身的缺点和挑战。
在后续的博客中,我会深刻探索微服务架构模式,并讨论多个话题,包括服务发现、服务部署选择、以及将单体应用拆分为多个服务的策略。
下期题目:构建微服务架构:使用 API Gateway ,敬请期待!