本文是来自于Macro在一次大会上的一個分享
本系列共有两个部分,主要关注我们如何以及为什么要在我们的微服务应用中部署API api网关与服务总线区别第二部分主要关注我们洳何把Mashape的开源api网关与服务总线区别组件Kong运用到我们自己的微服务架构当中。
大家好我叫Macro,今天我们谈论有关微服务和api网关与服务总线区別的话题我是Mashape的CTO,也同时是开源api网关与服务总线区别Kong的开发者之一。Kong是一个APIapi网关与服务总线区别今天我们就来窥探一下它究竟是怎么工莋的以及它如何运用到你的微服务架构中去。
为了明白我们为什么需要APIapi网关与服务总线区别我将从单体架构vs微服务架构谈起。这两个有什么不同点呢然后我会介绍APIapi网关与服务总线区别模式以及它是如何适应“面向微服务”的架构的。然后我们会讨论Kong以及NGINX
Ok,过去几年我們目睹的一件事就是从单体应用到面向微服务的架构的过渡我们都熟悉单体应用程序,以及它们通常的工作原理这是一个简单的展示。我们把所有的东西都放到一块而且通常也只有一个数据存储。
通过在多个服务器上重复部署相同的巨大代码块可以横向扩展单体应鼡程序。所以每次我们调整应用程序时我们其实相当于是在改动这些被放在一起的所有的模块,因为他们是一体的
每一种做法,都有利弊单体应用程序可以比较容易地构建,而且是以更小的代码库来开始我们可以在同一个代码库中构建和开发所有内容,这意味着我們不用担心模块化以及如何把不同的组件放在一起来共同工作这些事情
而且测试起来也简单。通常当我们测试一个单体应用时我们一開始就只面对一个应用,然后测试我们集成的单元测试我们只需要面对一个应用就够了。
而且很多IDE对单体应用已经支持的非常好了。仳如Eclipse围绕着单体应用就提供了很多成熟的测试工具包括idea也是。
但你也许也发现了一个代码库(codebase)的问题,随着代码量的急剧膨胀我们把所有的都放在一个代码库里显然不是一种理想的选择。随着时间的推移越来越多的功能需要构建进去,代码越来越多在一个地方跟踪玳码将变得更加的困难。
由于这些原因团队在一个大的代码库上迭代将会变慢。再来说个事情比如我现在要更换数据库存储方案,或鍺想要使用一种新的技术在单体应用中,这样的改动通常是非常痛苦的
由于上面所有的原因,你开始扩张你的组织然后发生的事情僦是团队内部沟通成本变得更昂贵,因为理解代码库里的代码究竟是干什么的变得更加困难
在过去的几年里(一两年吧),我们亲眼目睹了我们的应用架构向微服务转变的这个过程容器在这个转变中也出了很大的力气,因为它围绕微服务创建了一些伟大的工具这一部汾我们稍后会具体谈到。
在一个微服务架构中你把应用拆分成不同的模块(component)。于是取而代之的是多个不同的service被彼此独立的部署彼此獨立的伸缩。在上面的这个例子中客户的订单和发票,这些模块将会被分别部署在他们自己的server上
这些service之间的通信机制可以是多种格式嘚,通常是HTTP 或者 RPC(以及事件发布订阅的方式)有时候你也可为每个模块分配不同的数据存储schema。这样的话我们就把每个模块的能力都隔離开了,而且你还让它独立于其他模块而工作
这样也意味着很多时候你可能需要通过事件源机制来搞定一些事件触发。在这个例子中愙户端创建一个新的订单。你就可以不用让客户端创建订单并且生成发票取而代之的是,你可以创建一个新的订单然后Orders这个模块push一个苼成发票事件,然后其他的模块可以监听这个事件然后来异步生成发票。
这样的话你算是构建了一个异步的应用程序,它没有依赖于愙户端并且它可以自主的为你生成发票这也就是意味着,如果Invoices模块down了可以在稍后重试生成发票。
面向微服务的架构也有其两面性微垺务并不适合所有的主体,也不能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,有的简单有的比较难。这取决于你要测试的内容
如果只是测试一个独立的模块,那就比较简单但要测试一个多重依赖的那种的话可能就比较复杂了。通常的话如果你想要测试一个构建于微服务架构之上的应用的話,前提条件就是你必须要同时启动所有的这些模块这样可以确保彼此都可以相互通信,并且要成功地实现了集成测试
Ok,为什么我们需要一个APIapi网关与服务总线区别呢
我们总是听到编排这个词,所以我喜欢这张幻灯片 – 它展示了一个乐队然后有个指挥家,下面一堆人(微型服务)演奏自己的乐器这个指挥家(APIapi网关与服务总线区别)可以以某种方式来协调我们的架构如何处理请求。
API api网关与服务总线区別模式意味着你要把API api网关与服务总线区别放到你的微服务们的最前端并且要让API api网关与服务总线区别变成由应用所发起的每个请求的入口。这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式
以前的话,客户端不得不去请求Customers然后再到Orders,然后是Invoices客户端需偠去知道怎么去一起来消费这三个不同的service。使用APIapi网关与服务总线区别我们可以抽象所有这些复杂性,并创建客户端们可以使用的优化后嘚端点并向那些模块们发出请求。
例如优化的端点。如果我们假设客户(Customers)订单(Orders)和发票(Invoices)每个模块都返回不同的JSON响应,并且假设客户端想要检索此信息有两种方法。一种方式是客户端向客户(Customers)模块发出GET请求以检索客户,然后到订单(Orders)然后到指定订单的发票(Invoices)。
第二种方式是我们可以通过使用APIapi网关与服务总线区别来抽象此客户端实现的复杂性然后,APIapi网关与服务总线区别可以公开一个特定的端点在这个端点上将产生请求,然后在[api网关与服务总线区别]消费了微服务之后返回给客户端一个唯一的响应(response)
也就是说,比如我們可以把很多的response折叠成一个,request也是一个这样对我们帮助很大,而且特别是对于手机等其他移动客户端来说特别的受益这样就可以加速峩们的客户端的实现。而且可以轻松的做一些替换
有一个很nice的事情,就是APIapi网关与服务总线区别让我们的客户端不用再需要知道和关心模塊的地址(address)了api网关与服务总线区别负责来搞这些事情,你只需要知道api网关与服务总线区别就好了你可以去改变实现而且还可以改变API接口。不过通常来说你改变接口后,会增加客户端出问题的风险
使用APIapi网关与服务总线区别后,你可以在单独的层上有效地抽象这样伱就可以更改实现和接口,同时保持现有客户端的公共接口相同这意味着你总是可以做一些调整的事情。
APIapi网关与服务总线区别对于那些從单体转变到微服务的应用来说也是一个非常有帮助的工具如果你现在维护一个单体应用,你就可以把一个APIapi网关与服务总线区别放到这個单体的最前面然后你就慢慢地开始把单体拆分成很多的不同的微服务,在这个过程中客户端就一直是通过APIapi网关与服务总线区别来保歭自己的运作,这样让你的迁移过程更优雅!
APIapi网关与服务总线区别将随着时间的推移实现和消费后端的上游service同时保持客户端的正常工作。拥有一个APIapi网关与服务总线区别可以帮助我们实现这样的过渡
当然了,创建一个优化的端点仅仅是APIapi网关与服务总线区别的好处之一你還可以通过APIapi网关与服务总线区别中心化中间件的能力。当你开始创建越来越多的服务时你会发现自己面临了一个新的问题 – 就是你发现伱需要对一些服务进行身份验证和流量控制。
有的服务是public的;有的是private的;有的则是合作伙伴的API这些你只能提供给一些特定的用户。迟早伱会发现自己在实现每个微服务时总是一次次的重复编写一些相同的代码这些代码其实都是可以抽象为中间件的。
这显然不是每个微服務应该去关注的事情APIapi网关与服务总线区别才应该把这件事情揽下,也就是说微服务只负责接收进来的request-然后返回一个类似JSON格式的response即可然後APIapi网关与服务总线区别就把这些例如身份验证、日志(logging)以及流量控制都归于麾下。
在这个slide还要介绍的就是最下面的Faas(function as a service),这个是一个佷酷的东西它意味着你正在消费的某个API端点可能正在地球的某一个角落在做一些事情。
它也许运行在一个serverless的架构之上或者并没有运行茬你自己的server上。这意味着你同样可以在这些能力前面前置一个APIapi网关与服务总线区别也可以在他们之上运行一些上面所说的那些中间件。
這里我只是向你们展示了一些使用场景然后让你知道它是如何让我们的“生活”变得更简单。比如布署,deploy这件事情在微服务架构中,一个特定的service也许在一天内要被deploy很多次(它不像单体时布署是一件艰难的事情)
在单体应用中,布署(deployment)往往是一件比较耗时和缓慢的倳情因为你每次做的一点点改变,你都不得不要把一整个单体应用重新布署一遍而且随着应用规模的增长,布署这件事情就变得越来樾复杂而在微服务中呢?你可以独立的去布署一个模块很多次因为模块布署起来要更快更容易,因为只需要布署一个小小的块
而且洳果你需要,你还可以实现blue/green布署APIapi网关与服务总线区别可以让这件事情通过一种简单的方式实现变为可能。比如如果有一些Customer模块是1.0.0版本,有些Customer模块则是1.0.1版本api网关与服务总线区别能够知道这些所有的版本的模块的location,然后提供接口可以让你从旧的版本切换到新的版本
另一種发布策略是金丝雀发布(canaryreleases)。当我们创建软件的时候有时候你不希望让所有的流量都一次性的到达新的版本,因为那个新的版本也许並没有测试地很充分
金丝雀发布策略允许你直接只导入指定量的流量到新的版本,APIapi网关与服务总线区别就可以帮你来做这件事情你可鉯配置10%的请求到新的版本,然后一旦你确保了新版本没有bug你可以把流量切换到100%。
APIapi网关与服务总线区别的另外的一个能力就是可以负载均衡在一定场景下,APIapi网关与服务总线区别可以是负载均衡器APIapi网关与服务总线区别知道所有的service的地址和位置,所以你可以在APIapi网关与服务总線区别和上游service之间加一个负载均衡器或者它本身就是一个负载均衡器。
当它是负载均衡器时APIapi网关与服务总线区别就可以利用诸如Consul或etcd这些服务发现工具来负载均衡请求(request)。
每次你去请求一个DNS地址服务发现(service?discovery)工具就会给你一个新的IP地址。一般会在DNS这一层中做一些类姒round-robin等策略的负载均衡
现在我们闭目想想,假定你的某个service突然停止了工作然后返回了大量的错误。
APIapi网关与服务总线区别可以帮你实现断蕗器(circuit breakers)的能力,也就是说超过了指定的阈值APIapi网关与服务总线区别就会停止发送数据到那些失败的模块。
这样就给了我们时间来分析日志实現修复以及push更新。通常当你发现一个模块下的某个实例失败后这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他嘚模块这样就会发生级联故障,或者叫雪崩
断路器通过简单的断开流量的方式,这样就不会有新的请求到达那些有问题的实例这时候我们就有相对充分的时间来修复和解决问题。
在这里我想说明一个经常被误解的内容有时,产品经理和软件工程师认为构建API与运行API楿同,因此构建微服务与运行微服务相同但这是两个不同的问题。他们必须以不同的方式解决
我认为构建API通常是构建微服务器所需的笁作量的50%。这是一个大概的估计并不是把每个人都考虑到了。现在我们有一个API运行它可以接受请求和返回响应,但是我们如何处理管理身份验证,流量控制和速率限制
那么我们用户的速率限制之后的下一步就是将这些用户的一小部分列入白名单的问题,允许这一蔀分人无论如何都不会被限制这算是一种更高端的速率限制。
微服务可以为你提供更多不仅仅是一个你可以消费的API。
然后是监控分析 - 這是非常重要的你需要持续地监视和跟踪模块和文档的状态。 如果你有API你还需要有适当的文档。这不仅对公共开发人员而言是重要的而且对于组织内部的开发人员也是重要的。
比如你有一个语音API以及一个SMS API如果您希望纽约和旧金山的两个团队合作,团队只需要发布一個API接口的文档然后你组织内的任何人都可以使用那个API。保持文档最新是非常重要的
这也是通常在创建新API时一般不会纳入那50%的一部分內容,但这确实是面向微服务的体系架构的一部分
下集将会介绍Kong如何运用到你的微服务架构中。