API网关

1.什么是API网关

API网关的概念是基于微服务架构提出的,作为统一的请求入口,对请求进行路由、负载均衡、协议转换(http-->rpc)、安全防护、限流熔断等,把与业务无关的逻辑提炼出来,与业务逻辑完全分离。

网关的功能

2.API网关结构

API 网关系统架构图

API 网关拆分成为 3 个系统:

Gateway-Core(核心)

Gateway-Admin(管理)

Gateway-Monitor(监控)

Gateway-Core 核心网关,负责接收客户端请求,调度、加载和执行组件,将请求路由到上游服务端,并处理其返回的结果。

大多数的功能都在这一层完成,例如:验证,鉴权,负载均衡,协议转换,服务路由,数据缓存。如果没有其他两个子系统,它也是可以单独运行的。

Gateway-Admin 网关管理界面,可以进行 API、组件等系统基础信息的配置;例如:限流的策略,缓存配置,告警设置。

Gateway-Monitor 监控日志、生成各种运维管理报表、自动告警等;管理和监控系统主要是为核心系统服务的,起到支撑的作用。

3.API网关的核心技术和要实现的主要功能

API 网关技术原理

上面谈到了网关的架构思路,这里谈几点技术原理。平时我们在使用网关的时候,多注重其实现的功能。例如:路由,负载均衡,限流,缓存,日志,发布等等。

实际上这些功能的背后有一些原理我们可以了解,这样在应用功能的时候会更加笃定。下面是几个原理分享给大家。

协议转换

每个系统内部服务之间的调用,可以统一使用一种协议,例如:HTTP,GRPC。

假设每个系统使用的协议不同,那么系统之间的调用或者数据传输,就存在协议转换的问题了。如果解决这个问题呢?API 网关通过泛化调用的方式实现协议之间的转化。

实际上就是将不同的协议转换成“通用协议”,然后再将通用协议转化成本地系统能够识别的协议。

这一转化工作通常在 API 网关完成。通用协议用得比较多的有 JSON,当然也有使用 XML 或者自定义 JSON 文件的。

不同的协议需要转化成共同语言进行传输

链式处理

设计模式中有一种责任链模式,它将“处理请求”和“处理步骤”分开。每个处理步骤,只关心这个步骤上需要做的处理操作,处理步骤存在先后顺序。

消息从第一个“处理步骤”流入,从最后一个“处理步骤”流出,每个步骤对经过的消息进行处理,整个过程形成了一个链条。在 API 网关中也用到了类似的模式。

Zuul 网关过滤器链式处理

下面以 Zuul 为例,当消息出入网关需要经历一系列的过滤器。这些过滤器之间是有先后顺序的,并且在每个过滤器需要进行的工作也是各不一样:

PRE:前置过滤器,用来处理通用事务,比如鉴权,限流,熔断降级,缓存。并且可以通过 Custom 过滤器进行扩展。

ROUTING:路由过滤器,在这种过滤器中把用户请求发送给 Origin Server。它主要负责:协议转化和路由的工作。

POST:后置过滤器,从 Origin Server 返回的响应信息会经过它,再返回给调用者。在返回的 Response 上加入 Response Header,同时可以做 Response 的统计和日志记录。

ERROR:错误过滤器,当上面三个过滤器发生异常时,错误信息会进到这里,并对错误进行处理。

异步请求

所有的请求通过 API 网关访问应用服务,一旦吞吐量上去了,如何高效地处理这些请求?

拿 Zuul 为例,Zuul1 采用:一个线程处理一个请求的方式。线程负责接受请求,然后调用应用返回结果。

如果把网络请求看成一次 IO 操作的话,处理请求的线程,从接受请求,到服务返回响应,都是阻塞状态。

同时,如果多个线程都处在这种状态,会导致系统缓慢。因为每个网关能够开启的线程数量是有限的,特别是在访问的高峰期。

每个线程处理一个请求

为了解决这个问题,Zuul2 启动了异步请求的机制。每个请求进入网关的时候,会被包装成一个事件,CPU 内核会维持一个监听器,不断轮询“请求事件”。

一旦,发现请求事件,就会调用对应的应用。获取应用返回的信息以后,按照请求的要求把数据/文件放到指定的缓冲区,同时发送一个通知事件,告诉请求端数据已经就绪,可以从这个缓冲获取数据/文件。

这个过程是异步的,请求的线程不用一直等待数据的返回。它在请求完毕以后,就直接返回了,这时它可以做其他的事情。

当请求数据被 CPU 内核获取,并且发送到指定的数据缓冲区时,请求的线程会接到“数据返回”的通知,然后就直接使用数据,不用自己去做取数据的操作。

异步请求处理,CPU 处理数据以后通知请求端

实现异步处理请求有两种模式,分别是:

Reactor

Proactor

Reactor 工作原理流水图

Reactor:通过 handle_events 事件循环处理请求。用户线程注册事件处理器之后,可以继续执行其他的工作(异步),而 Reactor 线程负责调用内核的 Select 函数检查 Socket 状态。

当有 Socket 被激活时(获取网络数据),则通知相应的用户线程,执行 handle_event 进行数据读取、处理的工作。

Proactor 工作原理流水图

Proactor:用户线程使用 CPU 内核提供的异步 IO 发起请求,请求发起以后立即返回。CPU 内核继续执行用户请求线程代码。

此时用户线程已将 AsynchronousOperation(异步处理)和 CompletionHandler(完成获取资源)注册到内核。之后操作系统开启独立的内核线程去处理 IO 操作。

当请求的数据到达时,由内核负责读取 Socket(网络请求)中的数据,并写入用户指定的缓冲区中。

最后内核将数据和用户线程注册的 CompletionHandler 分发给内部 Proactor,Proactor 将 IO 完成的信息通知给用户线程(一般通过调用用户线程注册的完成事件处理函数),完成异步 IO。

API 网关实现功能

说起对 API 网关的使用,我们还是对具体功能更加感兴趣。让我们一起来看看它实现了哪些功能。

负载均衡

当网关后面挂接同一应用的多个副本时,每次用户的请求都会通过网关的负载均衡算法,路由到对应的服务上面。例如:随机算法,权重算法,Hash 算法等等。

如果上游服务采取微服务的架构,也可以和注册中心合作实现动态的负载均衡。

当微服务动态挂载(动态扩容)的时候,可以通过服务注册中心获取微服务的注册信息,从而实现负载均衡。

 Nginx+Lua+服务注册中心实现动态负载均衡

路由选择

这个不言而喻,网关可以根据请求的 URL 地址解析,知道需要访问的服务。再通过路由表把请求路由到目标服务上去。

有时候因为网络原因,服务可能会暂时的不可用,这个时候我们希望可以再次对服务进行重试。

Zuul 作为 API 网关将请求路由到上游服务器

例如:Zuul 与 Spring Retry 合作完成路由重试。

#是否开启重试功能 

zuul.retryable=true 

#对当前服务的重试次数 

ribbon.MaxAutoRetries=2 

流量控制

限流是 API 网关常用的功能之一,当上游服务超出请求承载范围,或者服务因为某种原因无法正常使用,都会导致服务处理能力下滑。

这个时候,API 网关作为“看门人”,就可以限制流入的请求,让应用服务器免受冲击。

限流实际上就是限制流入请求的数量,其算法不少,有令牌桶算法,漏桶算法,连接数限制等等。这里我们就介绍三个常用的,一般通过 Nginx+Lua 来实现。

令牌桶限流

统一鉴权

访问应用服务器的请求都需要拥有一定权限,如果说每访问一个服务都需要验证一次权限,这个对效率是很大的影响。可以把权限认证放到 API 网关来进行。

目前比较常见的做法是,用户通过登录服务获取 Token,把它存放到客户端,在每次请求的时候把这个 Token 放入请求头,一起发送给服务器。

API 网关要做的事情就是解析这个 Token,知道访问者是谁(鉴定),他能做什么/访问什么(权限)。

说白了就是看访问者能够访问哪些 URL,这里根据权限/角色定义一个访问列表。

如果要实现多个系统的 OSS(Single Sign On 单点登录),API 网关需要和 CAS(Central Authentication Service 中心鉴权服务)做连接,来确定请求者的身份和权限。

熔断降级

当应用服务出现异常,不能继续提供服务的时候,也就是说应用服务不可用了。作为 API 网关需要做出处理,把请求导入到其他服务上。

或者对服务进行降级处理,例如:用兜底的服务数据返回客户端,或者提示服务暂时不可用。

同时通过服务注册中心,监听存在问题的服务,一旦服务恢复,随即恢复路由请求到该服务。

例如:Zuul 中提供了 ZuulFallbackProvider 接口来实现熔断,它提供两个方法,一个指明熔断拦截的服务 getRoute,一个指定返回内容 ClientHttpResponse。

public  interface ZuulFallbackProvider { 

   /** 

* The route this fallback will be usedfor. 

* @return The route the fallback will be  used for. 

     */ 

public String getRoute(); 


    /** 

     * Provides a fallback response. 

* @return The fallback response. 

     */ 

public  ClientHttpResponsefallbackResponse(); 

我们通过自定义的 Fallback 方法,并且将其指定给某个 Route 来实现该 Route 访问出问题的熔断处理。

主要继承 ZuulFallbackProvider 接口来实现,ZuulFallbackProvider 默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容。

API 网关熔断降级

发布测试

在发布版本的时候会采用:金丝雀发布和蓝绿发布。作为 API 网关可以使用路由选择和流量切换来协助上述行为。这里以金丝雀发布为例,看看 API 网关如何做路由转换的。

假设将 4 个服务从 V1 更新到 V2 版本,这 4 个服务的流量请求由 1 个 API 网关管理。

那么先将一台服务与 API 网关断开,部署 V2 版本的服务,然后 API 网关再将流量导入到 V2 版本的服务上。

这里流量的导入可以是逐步进行的,一旦 V2 版本的服务趋于稳定。再如法炮制,将其他服务替换成 V2 版本。

金丝雀发布一般先发 1 台,或者一个小比例,例如 2% 的服务器,主要做流量验证用,也称为金丝雀(Canary)测试(灰度测试)。

其来历是,旷工下矿洞前,先放一只金丝雀探查是否有毒气,金丝雀发布由此得名。

金丝雀测试需要完善的监控设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回滚的依据。

如果金丝测试通过,则把剩余的 V1 版本全部升级为 V2 版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。

缓存数据

我们可以在 API 网关缓存一些修改频率不高的数据。例如:用户信息,配置信息,通过服务定期刷新这个缓存就行了:

用户请求先访问 API 网关,如果发现有缓存信息,直接返回给用户。

如果没有发现缓存信息,回源到应用服务器获取信息。

另外,有一个缓存更新服务,定期把应用服务器中的信息更新到网关本地缓存中。

日志记录

通过 API 网关上的过滤器我们可以加入日志服务,记录请求和返回信息。同时可以建立一个管理员的界面去监控这些数据。

日志服务简图

日志记录了以后,可以做很多功能扩展。我们整理了以下几点供大家参考:

报表分析:针对服务访问情况,提供可视化展示。

实时查询:了解实时关键信息,例如:吞吐量,并发数。在秒杀活动的时候,会特别关注。

异常告警:针对关键参数进行监控,对于统计结果支持阈值报警,对接阿里云通知中心、短信、钉钉进行告警。

日志投递:将日志进行归档,存放到文件库或者数据仓库中,以便后期分析。

日志记录衍生的功能

4.API网关和SpringMVC的控制层的区别

问:感觉api 网关的功能和springmvc的controller的功能差不多啊;nginx+controller所在服务的集群可以负载均衡;controller可以实现登录和权限控制;controller可以实现服务路由

答:我的理解是 网关的目标是将权限控制,路由,负载均衡等所有的与业务开发无关的部分提炼出来。我们通常用spring开发java应用,在单应用的时代网关和业务代码杂糅在一起,问题不大。但是在分布式业务开发的场景下,我们的应用通常会部署在不同机房不同的机器上,每个应用可能会存在成百甚至上千的实例。这时候如果再将网关和应用绑定,二者之间的强耦合可能会大大降低应用的可维护性,比如网关的升级可能需要所有的应用实例也同时更新,这样明显非常不方便。因此我们会专门将网关部分的业务提炼出来,单独管理,单独维护。

核心思想:一切为了分布式的微服务架构解耦,控制层还是存在业务逻辑的,虽然像登录、路由、安全、防刷限流等功能都可以做在控制层,但是这些都是可以提炼出来的公用模块,耦合在一起,当公共部分需要修改上线,还要拉着业务工程一起上线,完全没有必要,所以分割出来网关,让控制层完全只做业务逻辑,协议转换后直接远程调用,可以做到解耦,并且达到为系统瘦身的目的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容