一、什么是API Gateway
我们知道在微服务架构中,大型服务都被拆分成了独立的微服务,每个微服务通常会以RESTFUL API的形式对外提供服务。但是在UI方面,我们可能需要在一个页面上显示来自不同微服务的数据,此时就会需要一个统一的入口来进行API的调用。上图中我们可以看到,API Gateway就在此场景下充当了多个服务的大门,系统的统一入口,从面向对象设计的角度看,它与外观模式类似,API Gateway封装了系统的内部复杂结构,同时它还可能具有其他API管理/调用的通用功能,如认证,限流,流控等功能。
二、为什么需要API Gateway
在微服务的架构模式下,API Gateway是微服务架构中一个非常通用的模式,利用API Gateway可以解决调用方如何调用独立的微服务这个问题。
从部署结构上说,上图是不采用API Gateway的微服务部署模式,我们可以清晰看到,这种部署模式下,客户端与负载均衡器直接交互,完成服务的调用。但这是这种模式下,也有它的不足。
不足
不支持动态扩展,系统每多一个服务,就需要部署或修改负载均衡器。
无法做到动态的开关服务,若要下线某个服务,需要运维人员将服务地址从负载均衡器中移除。
对于API的限流,安全等控制,需要每个微服务去自己实现,增加了微服务的复杂性,同时也违反了微服务设计的单一职责原则。
上图为采用API Gateway模式,我们通过上图可以看到,API Gateway做为系统统一入口,实现了对各个微服务间的整合,同时又做到了对客户端友好,屏蔽系统了复杂性和差异性。对比之前无API Gateway模式,API Gateway具有几个比较重要的优点:
优点
采用API Gateway可以与微服务注册中心连接,实现微服务无感知动态扩容。
API Gateway对于无法访问的服务,可以做到自动熔断,无需人工参与。
API Gateway可以方便的实现蓝绿部署,金丝雀发布或A/B发布。
API Gateway做为系统统一入口,我们可以将各个微服务公共功能放在API Gateway中实现,以尽可能减少各服务的职责。
帮助我们实现客户端的负载均衡策略。
三、API Gateway分类
API Gateway可分为两类
单节点 API 网关
Backends for frontends 网关
单节点的 API网关为每个客户端提供不同的API,而不是提供一种万能风格的API。
这种模式是针对不同的客户端来实现一个不同的API网关。
四、API Gateway中一些重要的功能
1、负载均衡
在实际的部署应用中,当应用系统面临大量访问,负载过高时,通常我们会增加服务数量来进行横向扩展,使用集群来提高系统的处理能力。此时多个服务通过某种负载算法分摊了系统的压力,我们将这种多节点分摊压力的行为称为负载均衡。
负载均衡分为服务端负载和客户端侧负载。服务端侧负载在访问者和目标服务之间架设LB硬件或者软件中间件,硬件流行的有F5,中间件主流的有Apache、Nginx、HAProxy、KeepAlived等。
请求首先发送到负载均衡服务器,负载均衡服务器根据一定算法,将请求转发给后端服务器之中的一个。服务端侧负载软硬件技术成熟,效率也高。不过后端服务器变动需要修改负载均衡服务器的配置,略有不便,且需要对负载均衡服务器本身实现高可用,增加了部署和维护成本。
客户端侧负载有所不同,后端服务器的地址列表不再由负载均衡服务器存储和维护,而是每个客户端都会存储在本地。后端服务器启动时自动向注册中心注册服务,服务下线时服务注册中心也能获知。客户端建立对服务注册中心的长监听,每当后端服务发生变化,注册中心自动通知客户端更新本地缓存的服务器列表。
目前主流的服务注册中心由Eureka、Zookeeper等。客户端侧负载的好处是方便,后端服务变化对客户端是透明的。但是相比服务端负载,客户端侧负载对后端服务有要求,不是所有的后端服务都能做客户端侧负载。
目前流行的API Gateway有Spring Cloud Zuul,Zuul默认使用Ribbon实现客户端侧负载,利用服务注册中心可知道所有后端服务的地址和状态,通过负载均衡算法,尽可能均衡的转发请求到后台微服务。
Ribbon支持的负载均衡策略即是网关支持的,其默认提供的负载均衡策略包括主要包括以下内容。
2、服务熔断
在实际生产中,一些服务很有可能因为某些原因发生故障而不可用,比如服务内部错误、网络延迟等,如果放任故障服务不管,可能会因为级联故障导致雪崩效应,使得整个系统瘫痪。为此,我们需要对不可用服务的调用快速失败。
Spring Cloud提供了Hystrix组件来实现这一点。当某服务在短时间内多次发生调用失败,服务消费方的断路器会被断开。开路的断路器就像电路跳闸一样,阻止消费方向故障服务发送请求,直接返回失败或者执行消费方的降级逻辑。断路器通常在一定时间后关闭,在这期间可以为底层服务提供足够的空间来恢复。
理解断路器需要了解以下几点:
第一、断路器只是作用在服务调用这一端。
第二、服务的健康状况 = 请求失败数 / 请求总数。
第三、断路器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的。
第四、关闭时, 请求被允许通过断路器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态。
第五、打开状态, 经过一段时间后, 断路器会自动进入半开状态, 这时断路器只允许一个请求通过. 当该请求调用成功时, 断路器恢复到关闭状态. 若该请求失败, 断路器继续保持打开状态, 接下来的请求被禁止通过。
第六、保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待。
第七、在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能。
API网关作为服务请求的统一入口,负责转发请求到后端服务。对于所有后端服务来说,网关就是服务请求方。所以,在网关上配置断路器是最佳实践。Spring Cloud Zuul默认提供了对Hystrix的支持。
3、灰度发布
服务发布上线过程中,我们不可能将新版本全部部署在生产环节中,因为新版本并没有接受真实用户、真实数据、真实环境的考验,此时我们需要进行灰度发布,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,同时影响小。API Gateway可以帮助我们轻松的完成灰度发布,只需要在API Gateway中配置我们需要的规则,按版本,按IP段等,API Gateway会自动为我们完成实际的请求分流。
4、数据聚合
由于不同的客户端往往需要的数据完全不同,而这些数据又是不同的 service 提供的,比如上面提到的查看一个商品详情页,我们可能需要同时从商品服务,库存服务,评价服务等中拉取信息,我们可以借助 Gateway 方便完成来自不同 service 的数据聚合。
5、统一对外接口
当用户需要集成不同产品或者服务之间的功能,调用不同服务提供的能力。利用APIGateway可以让用户在不感知服务边缘的情况下,利用统一的接口组装服务。
对于公司内部不同的服务,提供的接口可能在风格上存在一定的差异,通过APIGateway可以统一这种差异。 当内部服务修改时,可以通过APIGateway进行适配,不需要调用方进行调整,减少对外暴露服务可以增加系统安全性。
而在微服务架构下,一个应用被拆分为若干个微应用,每个微应用都需要对访问进行鉴权,每个微应用都需要明确当前访问用户及其权限,单体应用架构下的鉴权方式就不适合了。为了适应架构的变化,身份认证与鉴权方案也在不断的变革。面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证,如何提供细粒度的鉴权方案,是亟待解决的问题。
API网关作为服务访问的统一入口,所有用户请求都会过API网关,很适合用来做认证鉴权这类切面型服务。网关可以拦截用户请求,获取请求中附带的用户身份信息,调用认证授权中心的服务,对请求者做身份认证,即确认当前访问者确实是其所声称的身份,检查该用户是否有访问该后台服务的权限。
目前主流的认证鉴权方案有2种。
第一种是引入Redis做分布式会话,即用户登录成功后,将用户身份、权限信息存入Redis,以一个唯一ID作为Key,并设置信息在Redis里的失效时间。这个唯一ID的Key将返回给客户端,客户端可以放入Cookie,sessionStorage等处做本地存储。下次访问的时候,将这个唯一ID放入请求参数中一起发送(一般放入Header)。服务端通过检查Redis里有无这个ID来判断用户是否登录,获取用户身份和权限信息。客户端如果长时间没有操作,则存储在Redis里会话信息过期自动删除。客户端每访问一次服务端,需刷新一次会话信息的过期时间,避免固定过期时间带来的低用户体验。
第二种是JWT,即Java Web Token。用户登录成功后,服务端向客户端返回的唯一ID不再是无意义的字符串,而是包含了用户身份、权限、失效时间等信息的加密字符串。并且这个字符串包含数字签名,服务端可对这个字符串做数字签名验签,确保该字符串未经篡改和伪造。相比分布式会话方案,JWT虽省去了Redis存储,但是每次访问都要做数字签名验证,增加了CPU的资源损耗。
refers:
https://zhuanlan.zhihu.com/p/371986798
https://cloud.tencent.com/developer/news/257354