龙空技术网

27 | API网关:系统的门面要如何做呢?

架构修炼师 607

前言:

此时咱们对“nginx 黑白名单”大概比较注重,姐妹们都想要了解一些“nginx 黑白名单”的相关资讯。那么小编在网上搜集了一些对于“nginx 黑白名单””的相关知识,希望小伙伴们能喜欢,看官们快快来了解一下吧!

到目前为止,电商系统经过微服务化之后 ,运行了一段时间,扩展性得到很大提升,也能平稳度过高峰期流量了。

随着网站知名度上升系统迎来了不速之客,凌晨时候,商品搜索的调用量急剧上升。

这些搜索请求有一个共同特征是来自固定几台设备。当在搜索服务上加一个针对设备ID的限流功能之后,凌晨的高峰搜索请求就不见了。但是不久之后,用户服务也增加了大量爬取用户信息的请求,你不得不在这个服务上增加相同限流功能。

这样就出现了一个问题:不同的服务上使用同一种限流策略,代码上会有冗余,无法做到复用,如果其他服务出现相同的需求,再拷贝过去,显然有点不合适。

作为Java 程序员这时你就想到了把服务封装成 jar 供其他服务引用,但是 其他技术栈怎么办呢?

这时就引入我们今天的话题: API 网关。

API 网关起到的作用

API 网关(API Gateway)不是一个开源组件,而是一种架构模式,它将是一些服务共有的功能整合一起的,独立部署为单独的一层,用来解决一些服务治理的问题,你可以把它看做系统的边界,可以多出入系统的流量做一些统一的管控。

API 网关可以分为两类:一类叫做入口网关,一类叫做出口网关。

入口网关是我们经常使用的网关种类,他部署在负载均衡服务器和应用服务器之间,主要有以下作用:

提供客户端一个统一的接入地址,api 网关可以 将用户的请求动态路由到不同的服务上,并且做一些必要的协议转换工作。微服务对外暴露的协议可能不同,有些提供Http 服务;有些已经完成RPC改造,对外暴露RPC服务,有些遗留系统还暴露的Web Service 服务。API 网关可以屏蔽这些服务的部署地址及协议细节,给客户端调动带来极大的方便。在API 网关中,可以植入一些服务治理策略,比如服务熔断、降级、限流、分流等。客户端的认证和授权可以在API 实现,手机 APP 使用 Oauth 协议认证,HTML5 端和 Web 端使用 Cookie 认证,内部服务使用自研的 Token 认证方式。这些认证方式在 API 网关上可以得到统一处理,应用服务不需要了解认证的细节。API网关可以做一些黑白名单相关的事情,比如针对设备 ID、用户 IP、用户 ID 等维度的黑白名单。在 API 网关中也可以做一些日志记录的事情,比如记录 HTTP 请求的访问日志,我在25 讲中讲述分布式追踪系统时,提到的标记一次请求的 requestId 也可以在网关中来生成。

出口网关就没有这么丰富的功能和作用了。在系统的研发中会依赖很多的第三方系统,典型的例子:使用第三方支付工具,我们可以在第三方系统和应用服务之间部署出口网关,对调用外部的 API 做统一的认证、授权、审计以及访问控制。

以上就是关于 api 网关的作用,及使用场景,这样你面对一些业务场景设计就不会手足无措。

API 网关要如何实现

实现一个API网关首先要考虑的就是他的性能,入口网关承担客户端过来的所有流量,加入业务处理时间是10ms ,网关的耗时 1ms ,那么对于每个接口的响应时间增加了10%,对于性能的影响巨大的,而提升网关性能的关键还是在IO模型上。

而在 Zuul2.0 中,Netfix 团队将 servlet 改造成了一个 netty server(netty 服务),采用 I/O 多路复用的模型处理接入的 I/O 请求,并且将之前同步阻塞调用后端服务的方式,改造成使用 netty client(netty 客户端)非阻塞调用的方式。改造之后,Netfix 团队经过测试发现性能提升了 20% 左右。

除此之外,网关中执行的动作有些是预先定义好的,比如黑白名单,接口动态路由,有些则是需要业务方自身来定义,所以网关需要考虑扩展性,可以随时加入一些处理逻辑,也可以随时下掉一些逻辑。

所以一般来说,我们可以把每一个操作定义为一个 filter(过滤器),然后使用“责任链模式”将这些 filter 串起来。责任链可以动态地组织这些 filter,解耦 filter 之间的关系,无论是增加还是减少 filter,都不会对其他的 filter 有任何的影响。

Zuul 就是采用责任链模式,Zuul1 中将 filter 定义为三类:pre routing filter(路由前过滤器)、routing filter(路由过滤器)和 after routing filter(路由后过滤器)。每一个 filter 定义了执行的顺序,在 filter 注册时,会按照顺序插入到 filter chain(过滤器链)中。这样 Zuul 在接收到请求时,就会按照顺序依次执行插入到 filter chain 中的 filter 了。

为了提高网关的并行处理能力,我们还会增加线程池的处理,这里会有一种现象:如果商品服务的请求响应缓慢,线程被占用无法释放给w其他服务,所以我们需要考虑线程池隔离策略,有以下两种思路:

如果后端服务拆分的不多,可以针对不同的服务采用不同的线程池,这样就不会影响其他服务线程池内部可以针对不同的服务设置不同的线程数配额。

你在实际应用中也可以将这两种方式结合,比如说针对不同的服务使用不同的线程池,在线程池内部针对不同的接口设置配额。

那么有哪些值得借鉴的网关开源实现呢:

Kong是在 Nginx 中运行的 Lua 程序。得益于 Nginx 的性能优势,Kong 相比于其它的开源 API 网关来说,性能方面是最好的。由于大中型公司对于 Nginx 运维能力都比较强,所以选择 Kong 作为 API 网关,无论是在性能还是在运维的把控力上,都是比较好的选择;

Zuul是 Spring Cloud 全家桶中的成员,如果你已经使用了 Spring Cloud 中的其他组件,那么也可以考虑使用 Zuul 和它们无缝集成。不过,Zuul1 因为采用同步阻塞模型,所以在性能上并不是很高效,而 Zuul2 推出时间不长,难免会有坑。但是 Zuul 的代码简单易懂,可以很好地把控,并且你的系统的量级很可能达不到 Netfix 这样的级别,所以对于 Java 技术栈的团队,使用 Zuul 也是一个不错的选择;

Tyk是一种 Go 语言实现的轻量级 API 网关,有着丰富的插件资源,对于 Go 语言栈的团队来说,也是一种不错的选择。

如何在你的系统中引入 API 网关

首先将协议转换、限流、黑白名单等事情挪到 API 网关中来处理,形成独立的入口网关层;

而针对服务接口数据聚合的操作,一般有两种解决思路:

再独立出一组网关专门做服务聚合、超时控制方面的事情,我们一般把前一种网关叫做流量网关,后一种可以叫做业务网关;抽取独立的服务层,专门做接口聚合的操作。这样服务层就大概分为原子服务层和聚合服务层。

我认为,接口数据聚合是业务操作,与其放在通用的网关层来实现,不如放在更贴近业务的服务层来实现,所以,我更倾向于第二种方案。

标签: #nginx 黑白名单