微服务与API网关(上): 为什么需要API网关?

号外: 最近整理了之前编写的一系列内容做成了PDF,关注我的公众号"程序猿DD"来领取吧!

本文是来自于Macro在一次大会上的一个分享。

本系列共有两个部分,主要关注我们如何以及为什么要在我们的微服务应用中部署API 网关。第二部分主要关注我们如何把Mashape的开源网关组件Kong运用到我们自己的微服务架构当中。*

目录


0:00 微服务与网关(Microservices & API Gateways)

大家好,我叫Macro,今天我们谈论有关微服务和网关的话题。我是Mashape的CTO,也同时是开源网关Kong的开发者之一。Kong是一个API网关,今天我们就来窥探一下它究竟是怎么工作的以及它如何运用到你的微服务架构中去。

0:23 主题(Topics)

为了明白我们为什么需要API网关,我将从单体架构vs微服务架构谈起。这两个有什么不同点呢?然后我会介绍API网关模式以及它是如何适应“面向微服务”的架构的。然后我们会讨论Kong以及NGINX。

0:47 单体架构(Monolithic Architecture)

Ok,过去几年我们目睹的一件事就是从单体应用到面向微服务的架构的过渡。我们都熟悉单体应用程序,以及它们通常的工作原理,这是一个简单的展示。我们把所有的东西都放到一块。而且通常也只有一个数据存储。

通过在多个服务器上重复部署相同的巨大代码块,可以横向扩展单体应用程序。所以每次我们调整应用程序时,我们其实相当于是在改动这些被放在一起的所有的模块,因为他们是一体的。

1:45 单体应用的优缺点(Monolithic Application Pros and Cons)

每一种做法,都有利弊。单体应用程序可以比较容易地构建,而且是以更小的代码库来开始。我们可以在同一个代码库中构建和开发所有内容,这意味着我们不用担心模块化以及如何把不同的组件放在一起来共同工作这些事情。

而且测试起来也简单。通常当我们测试一个单体应用时,我们一开始就只面对一个应用,然后测试我们集成的单元测试。我们只需要面对一个应用就够了。

而且,很多IDE对单体应用已经支持的非常好了。比如Eclipse围绕着单体应用就提供了很多成熟的测试工具,包括idea也是。

但,你也许也发现了一个代码库(codebase)的问题,随着代码量的急剧膨胀,我们把所有的都放在一个代码库里显然不是一种理想的选择。随着时间的推移,越来越多的功能需要构建进去,代码越来越多,在一个地方跟踪代码将变得更加的困难。

由于这些原因,团队在一个大的代码库上迭代将会变慢。再来说个事情,比如我现在要更换数据库存储方案,或者想要使用一种新的技术。在单体应用中,这样的改动通常是非常痛苦的。

由于上面所有的原因,你开始扩张你的组织。然后发生的事情就是团队内部沟通成本变得更昂贵,因为理解代码库里的代码究竟是干什么的变得更加困难。

3:55 微服务架构(Microservice-Oriented Architecture)

在过去的几年里(一两年吧),我们亲眼目睹了我们的应用架构向微服务转变的这个过程。容器在这个转变中也出了很大的力气,因为它围绕微服务创建了一些伟大的工具,这一部分我们稍后会具体谈到。

在一个微服务架构中,你把应用拆分成不同的模块(component)。于是取而代之的是多个不同的service被彼此独立的部署,彼此独立的伸缩。在上面的这个例子中,客户的订单和发票,这些模块将会被分别部署在他们自己的server上。

这些service之间的通信机制可以是多种格式的,通常是HTTP 或者 RPC(以及事件发布订阅的方式)。有时候你也可为每个模块分配不同的数据存储schema。这样的话,我们就把每个模块的能力都隔离开了,而且你还让它独立于其他模块而工作。

这样也意味着很多时候你可能需要通过事件源机制来搞定一些事件触发。在这个例子中,客户端创建一个新的订单。你就可以不用让客户端创建订单并且生成发票,取而代之的是,你可以创建一个新的订单,然后Orders这个模块push一个生成发票事件,然后其他的模块可以监听这个事件,然后来异步生成发票。

这样的话,你算是构建了一个异步的应用程序,它没有依赖于客户端并且它可以自主的为你生成发票。这也就是意味着,如果Invoices模块down了,可以在稍后重试生成发票。

5:47 微服务架构的优缺点(Microservice-Oriented Application Pros and Cons)

面向微服务的架构也有其两面性。微服务并不适合所有的主体,也不能hold所有的使用场景。它适合大型应用。如果您有大型应用程序,则可以将此大型应用程序拆分成不同的模块,开发人员将能够独立地迭代,维护和构建这些模块。

微服务的每个模块(component)只做一件事情,有且仅有一件事情可以做,你可以轻松基于此迭代并且尽情的完善和创新该模块,而且还不会影响到其他的模块。每个模块之间,彼此通过接口进行通信(大多数时候),比如HTTP RESTful接口。你可以改变和实验性的搞一些实现,只要接口不改变,应用就会保持正常的运转。

微服务,Microservices是micro。意味着如果你需要scale组织或团队,你可以为你的团队成员分配一些更小的,应用程序中的一些小碎片,更小的开发任务。这对于开发人员来说,有助于他们更快的理解自己要做什么,代码是如何运作的。而且迭代起来也更快。如果他们要用到其他的模块,他们可以使用接口去消费(consume)其他的模块,而不需要深入到其他模块的代码中去。

在单体应用中,有的地方发生了错误,意味着整个应用程序就无法运转了。很多时候一个bug导致整个应用程序就down了。而在微服务架构中,如果出现一个问题,这个问题是被隔离在一个特定的模块中或者是某个service中。

这意味着整个应用程序只有那一个service处于停止状态,而其他的模块则可以照常运转。就是说我们现在有Orders和Invoices两个模块。如果由于一些原因,开发人员在周五晚上push了一个bug到Invoices模块上,然后导致了发票模块不能工作。我们依然可以保存了这个发票事件。一旦Invoices模块恢复了,我们就可以继续生成发票了(那个之前由于bug而没有被创建的发票又可以被创建了)。

这样的功能我们在单体应用中也可以实现,但是由于微服务架构的推动,让这种事件驱动的风格更加的发扬光大,而随着时间的推移,单体应用变成了“意大利面应用”(spaghetti apps)。

面向微服务应用也有一些很典型的缺点。其中一个就是你现有有一堆不再“固定”的零部件。现在不再是单体那样一个app在一个地方做了所有事情。现在你有多个模块和(或)service。这些模块要在同一时刻共同配合才能最终呈现给用户。

这意味着你要有更强大的基础设施能力。现在你需要有一种魔法,要能简单地部署、伸缩、以及监控和管理这些不同的模块,这些独立的模块。这也是这些年来实时的在线监控和分析技术变得如此火爆的原因之一吧。因为一旦你是面向微服务的架构,你就必须去监控每一个碎片(零部件)并且要在一个集中的地方可以看到你的模块们的运行状态。

在单体中,你只有一个代码库来保存,执行并且所有的entity都在一块。在微服务架构中,我们有很多不同的模块,他们都彼此独立运行,并且只干一件事情。

这就意味着你现在有一个可用性的问题:service们也许会go down 不可用。或者还会有一致性问题:也许你需要把这些微服务scale到多个数据中心。所以你在创建一个应用时,就要把这些问题都要考虑进去。

如果你想要测试一个service,有的简单,有的比较难。这取决于你要测试的内容。

如果只是测试一个独立的模块,那就比较简单。但要测试一个多重依赖的那种的话可能就比较复杂了。通常的话,如果你想要测试一个构建于微服务架构之上的应用的话,前提条件就是你必须要同时启动所有的这些模块,这样可以确保彼此都可以相互通信,并且要成功地实现了集成测试。

11:18 为什么需要API网关?

Ok,为什么我们需要一个API网关呢?

我们总是听到编排这个词,所以我喜欢这张幻灯片 – 它展示了一个乐队,然后有个指挥家,下面一堆人(微型服务)演奏自己的乐器。这个指挥家(API网关)可以以某种方式来协调我们的架构如何处理请求。

11:54 API网关模式(API Gateway Pattern)

API 网关模式意味着你要把API 网关放到你的微服务们的最前端,并且要让API 网关变成由应用所发起的每个请求的入口。这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式。

以前的话,客户端不得不去请求Customers,然后再到