提交 6e77ea08 编写于 作者: G guide

[feat]api网关重构

上级 7af2d8a5
......@@ -273,8 +273,10 @@ Dubbo 是一款国产的 RPC 框架,由阿里开源。相关阅读:
网关主要用于请求转发、安全认证、协议转换、容灾。
1. [为什么要网关?你知道有哪些常见的网关系统?](docs/system-design/distributed-system/api-gateway/为什么要网站有哪些常见的网站系统.md)
2. [如何设计一个亿级网关(API Gateway)?](docs/system-design/distributed-system/api-gateway/如何设计一个亿级网关.md)
相关阅读:
- [为什么要网关?你知道有哪些常见的网关系统?](docs/system-design/distributed-system/api-gateway/api网关入门.md)
- [百亿规模API网关服务Shepherd的设计与实现](https://tech.meituan.com/2021/05/20/shepherd-api-gateway.html)
#### 分布式 id
......
## 何为网关?为什么要网关?
![微服务-网关](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javaguide/%E5%BE%AE%E6%9C%8D%E5%8A%A1-%E7%BD%91%E5%85%B3.png)
微服务背景下,一个系统被拆分为多个服务,但是像安全认证,流量控制,日志,监控等功能是每个服务都需要的,没有网关的话,我们就需要在每个服务中单独实现,这使得我们做了很多重复的事情并且没有一个全局的视图来统一管理这些功能。
综上:**一般情况下,网关都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。**
上面介绍了这么多功能,实际上,网关主要做了一件事情:**请求过滤**
## 有哪些常见的网关系统?
### Netflix Zuul
Zuul 是 Netflix 开发的一款提供动态路由、监控、弹性、安全的网关服务。
Zuul 主要通过过滤器(类似于 AOP)来过滤请求,从而实现网关必备的各种功能。
![Zuul架构](https://img-blog.csdnimg.cn/img_convert/865991e34f69f8cb345b4aff918e946e.png)
我们可以自定义过滤器来处理请求,并且,Zuul 生态本身就有很多现成的过滤器供我们使用。就比如限流可以直接用国外朋友写的 [spring-cloud-zuul-ratelimit](https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit) (这里只是举例说明,一般是配合 hystrix 来做限流):
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
```
Zuul 1.x 基于同步 IO,性能较差。Zuul 2.x 基于 Netty 实现了异步 IO,性能得到了大幅改进。
- Github 地址 : https://github.com/Netflix/zuul
- 官方 Wiki : https://github.com/Netflix/zuul/wiki
### Spring Cloud Gateway
SpringCloud Gateway 属于 Spring Cloud 生态系统中的网关,其诞生的目标是为了替代老牌网关 **Zuul **。准确点来说,应该是 Zuul 1.x。SpringCloud Gateway 起步要比 Zuul 2.x 更早。
为了提升网关的性能,SpringCloud Gateway 基于 Spring WebFlux 。Spring WebFlux 使用 Reactor 库来实现响应式编程模型,底层基于 Netty 实现异步 IO。
Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
Spring Cloud Gateway 和 Zuul 2.x 的差别不大,也是通过过滤器来处理请求。不过,目前更加推荐使用 Spring Cloud Gateway 而非 Zuul,Spring Cloud 生态对其支持更加友好。
- Github 地址 : https://github.com/spring-cloud/spring-cloud-gateway
- 官网 : https://spring.io/projects/spring-cloud-gateway
### Kong
Kong 是一款基于 [OpenResty](https://github.com/openresty/) 的高性能、云原生、可扩展的网关系统。
> OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
Kong 提供了插件机制来扩展其功能。比如、在服务上启用 Zipkin 插件
```shell
$ curl -X POST http://kong:8001/services/{service}/plugins \
--data "name=zipkin" \
--data "config.http_endpoint=http://your.zipkin.collector:9411/api/v2/spans" \
--data "config.sample_ratio=0.001"
```
- Github 地址: https://github.com/Kong/kong
- 官网地址 : https://konghq.com/kong
### APISIX
APISIX 是一款基于 Nginx 和 etcd 的高性能、云原生、可扩展的网关系统。
> *etcd*是使用 Go 语言开发的一个开源的、高可用的分布式 key-value 存储系统,使用 Raft 协议做分布式共识。
与传统 API 网关相比,APISIX 具有动态路由和插件热加载,特别适合微服务系统下的 API 管理。并且,APISIX 与 SkyWalking(分布式链路追踪系统)、Zipkin(分布式链路追踪系统)、Prometheus(监控系统) 等 DevOps 生态工具对接都十分方便。
![apisix架构图](https://img-blog.csdnimg.cn/img_convert/727732fad2e943bdd2c502b83ddb1b89.png)
作为 NGINX 和 Kong 的替代项目,APISIX 目前已经是 Apache 顶级开源项目,并且是最快毕业的国产开源项目。国内目前已经有很多知名企业(比如金山、有赞、爱奇艺、腾讯、贝壳)使用 APISIX 处理核心的业务流量。
根据官网介绍:“APISIX 已经生产可用,功能、性能、架构全面优于 Kong”。
- Github 地址 :https://github.com/apache/apisix
- 官网地址: https://apisix.apache.org/zh/
相关阅读:
- [有了 NGINX 和 Kong,为什么还需要 Apache APISIX](https://www.apiseven.com/zh/blog/why-we-need-Apache-APISIX)
- [APISIX 技术博客](https://www.apiseven.com/zh/blog)
- [APISIX 用户案例](https://www.apiseven.com/zh/usercases)
### Shenyu
Shenyu 是一款基于 WebFlux 的可扩展、高性能、响应式网关,Apache 顶级开源项目。
![Shenyu架构](https://img-blog.csdnimg.cn/1104eb413cba468cba4dce119165e84e.png)
Shenyu 通过插件扩展功能,插件是 ShenYu 的灵魂,并且插件也是可扩展和热插拔的。不同的插件实现不同的功能。Shenyu 自带了诸如限流、熔断、转发 、重写、重定向、和路由监控等插件。
- Github 地址: https://github.com/apache/incubator-shenyu
- 官网地址 : https://shenyu.apache.org/
### 为什么要网关?
微服务下一个系统被拆分为多个服务,但是像 安全认证,流量控制,日志,监控等功能是每个服务都需要的,没有网关的话,我们就需要在每个服务中单独实现,这使得我们做了很多重复的事情并且没有一个全局的视图来统一管理这些功能。
综上:**一般情况下,网关一般都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。**
上面介绍了这么多功能实际上网关主要做了一件事情:**请求过滤** 。权限校验、流量控制这些都可以通过过滤器实现,请求转发也是通过过滤器实现的。
### 你知道有哪些常见的网关系统?
我所了解的目前经常用到的开源 API 网关系统有:
1. Kong
2. Netflix zuul
下图来源:https://www.stackshare.io/stackups/kong-vs-zuul 。
![Kong vs Netflix zuul](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/kong-vs-zuul.jpg)
可以看出不论是社区活跃度还是 Star数, Kong 都是略胜一筹。总的来说,Kong 相比于 Zuul 更加强大并且简单易用。Kong 基于 Openresty ,Zuul 基于 Java。
> OpenResty(也称为 ngx_openresty)是一个全功能的 Web 应用服务器。它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。
>
> 通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种 Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。——OpenResty
另外, Kong 还提供了插件机制来扩展其功能。
比如、在服务上启用 Zipkin 插件
```shell
$ curl -X POST http://kong:8001/services/{service}/plugins \
--data "name=zipkin" \
--data "config.http_endpoint=http://your.zipkin.collector:9411/api/v2/spans" \
--data "config.sample_ratio=0.001"
```
ps:这里没有太深入去探讨,需要深入了解的话可以自行查阅相关资料。
> 点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
>
> 本文授权转载自:[https://github.com/javagrowing/JGrowing/blob/master/服务端开发/浅析如何设计一个亿级网关.md](https://github.com/javagrowing/JGrowing/blob/master/服务端开发/浅析如何设计一个亿级网关.md)。
# 1.背景
## 1.1 什么是API网关
API网关可以看做系统与外界联通的入口,我们可以在网关进行处理一些非业务逻辑的逻辑,比如权限验证,监控,缓存,请求路由等等。
## 1.2 为什么需要API网关
- RPC协议转成HTTP。
由于在内部开发中我们都是以RPC协议(thrift or dubbo)去做开发,暴露给内部服务,当外部服务需要使用这个接口的时候往往需要将RPC协议转换成HTTP协议。
- 请求路由
在我们的系统中由于同一个接口新老两套系统都在使用,我们需要根据请求上下文将请求路由到对应的接口。
- 统一鉴权
对于鉴权操作不涉及到业务逻辑,那么可以在网关层进行处理,不用下沉到业务逻辑。
- 统一监控
由于网关是外部服务的入口,所以我们可以在这里监控我们想要的数据,比如入参出参,链路时间。
- 流量控制,熔断降级
对于流量控制,熔断降级非业务逻辑可以统一放到网关层。
有很多业务都会自己去实现一层网关层,用来接入自己的服务,但是对于整个公司来说这还不够。
## 1.3 统一API网关
统一的API网关不仅有API网关的所有的特点,还有下面几个好处:
- 统一技术组件升级
在公司中如果有某个技术组件需要升级,那么是需要和每个业务线沟通,通常几个月都搞不定。举个例子如果对于入口的安全鉴权有重大安全隐患需要升级,如果速度还是这么慢肯定是不行,那么有了统一的网关升级是很快的。
- 统一服务接入
对于某个服务的接入也比较困难,比如公司已经研发出了比较稳定的服务组件,正在公司大力推广,这个周期肯定也特别漫长,由于有了统一网关,那么只需要统一网关统一接入。
- 节约资源
不同业务不同部门如果按照我们上面的做法应该会都自己搞一个网关层,用来做这个事,可以想象如果一个公司有100个这种业务,每个业务配备4台机器,那么就需要400台机器。并且每个业务的开发RD都需要去开发这个网关层,去随时去维护,增加人力。如果有了统一网关层,那么也许只需要50台机器就可以做这100个业务的网关层的事,并且业务RD不需要随时关注开发,上线的步骤。
# 2.统一网关的设计
## 2.1 异步化请求
对于我们自己实现的网关层,由于只有我们自己使用,对于吞吐量的要求并不高所以,我们一般同步请求调用即可。
对于我们统一的网关层,如何用少量的机器接入更多的服务,这就需要我们的异步,用来提高更多的吞吐量。对于异步化一般有下面两种策略:
- Tomcat/Jetty+NIO+servlet3
这种策略使用的比较普遍,京东,有赞,Zuul,都选取的是这个策略,这种策略比较适合HTTP。在Servlet3中可以开启异步。
- Netty+NIO
Netty为高并发而生,目前唯品会的网关使用这个策略,在唯品会的技术文章中在相同的情况下Netty是每秒30w+的吞吐量,Tomcat是13w+,可以看出是有一定的差距的,但是Netty需要自己处理HTTP协议,这一块比较麻烦。
对于网关是HTTP请求场景比较多的情况可以采用Servlet,毕竟有更加成熟的处理HTTP协议。如果更加重视吞吐量那么可以采用Netty。
#### 2.1.1 全链路异步
对于来的请求我们已经使用异步了,为了达到全链路异步所以我们需要对去的请求也进行异步处理,对于去的请求我们可以利用我们rpc的异步支持进行异步请求所以基本可以达到下图:
![](https://user-gold-cdn.xitu.io/2018/10/31/166c877315e557af?w=1300&h=480&f=png&s=69275)
由在web容器中开启servlet异步,然后进入到网关的业务线程池中进行业务处理,然后进行rpc的异步调用并注册需要回调的业务,最后在回调线程池中进行回调处理。
## 2.2 链式处理
在设计模式中有一个模式叫责任链模式,他的作用是避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。通过这种模式将请求的发送者和请求的处理者解耦了。在我们的各个框架中对此模式都有实现,比如servlet里面的filter,springmvc里面的Interceptor。
在Netflix Zuul中也应用了这种模式,如下图所示:
![](https://user-gold-cdn.xitu.io/2018/10/31/166c878240753735?w=960&h=720&f=png&s=49314)
这种模式在网关的设计中我们可以借鉴到自己的网关设计:
- preFilters:前置过滤器,用来处理一些公共的业务,比如统一鉴权,统一限流,熔断降级,缓存处理等,并且提供业务方扩展。
- routingFilters: 用来处理一些泛化调用,主要是做协议的转换,请求的路由工作。
- postFilters: 后置过滤器,主要用来做结果的处理,日志打点,记录时间等等。
- errorFilters: 错误过滤器,用来处理调用异常的情况。
这种设计在有赞的网关也有应用。
## 2.3 业务隔离
上面在全链路异步的情况下不同业务之间的影响很小,但是如果在提供的自定义Filter中进行了某些同步调用,一旦超时频繁那么就会对其他业务产生影响。所以我们需要采用隔离之术,降低业务之间的互相影响。
#### 2.3.1 信号量隔离
信号量隔离只是限制了总的并发数,服务还是主线程进行同步调用。这个隔离如果远程调用超时依然会影响主线程,从而会影响其他业务。因此,如果只是想限制某个服务的总并发调用量或者调用的服务不涉及远程调用的话,可以使用轻量级的信号量来实现。有赞的网关由于没有自定义filter所以选取的是信号量隔离。
#### 2.3.2 线程池隔离
最简单的就是不同业务之间通过不同的线程池进行隔离,就算业务接口出现了问题由于线程池已经进行了隔离那么也不会影响其他业务。在京东的网关实现之中就是采用的线程池隔离,比较重要的业务比如商品或者订单 都是单独的通过线程池去处理。但是由于是统一网关平台,如果业务线众多,大家都觉得自己的业务比较重要需要单独的线程池隔离,如果使用的是Java语言开发的话那么,在Java中线程是比较重的资源比较受限,如果需要隔离的线程池过多不是很适用。如果使用一些其他语言比如Golang进行开发网关的话,线程是比较轻的资源,所以比较适合使用线程池隔离。
#### 2.3.3 集群隔离
如果有某些业务就需要使用隔离但是统一网关又没有线程池隔离那么应该怎么办呢?那么可以使用集群隔离,如果你的某些业务真的很重要那么可以为这一系列业务单独申请一个集群或者多个集群,通过机器之间进行隔离。
## 2.4 请求限流
流量控制可以采用很多开源的实现,比如阿里最近开源的Sentinel和比较成熟的Hystrix。
一般限流分为集群限流和单机限流:
- 利用统一存储保存当前流量的情况,一般可以采用Redis,这个一般会有一些性能损耗。
- 单机限流:限流每台机器我们可以直接利用Guava的令牌桶去做,由于没有远程调用性能消耗较小。
## 2.5 熔断降级
这一块也可以参照开源的实现Sentinel和Hystrix,这里不是重点就不多提了。
## 2.6 泛化调用
泛化调用指的是一些通信协议的转换,比如将HTTP转换成Thrift。在一些开源的网关中比如Zuul是没有实现的,因为各个公司的内部服务通信协议都不同。比如在唯品会中支持HTTP1,HTTP2以及二进制的协议,然后转化成内部的协议,淘宝的支持HTTPS,HTTP1,HTTP2这些协议都可以转换成HTTP,HSF,Dubbo等协议。
#### 2.6.1泛化调用
如何去实现泛化调用呢?由于协议很难自动转换,那么其实每个协议对应的接口需要提供一种映射。简单来说就是把两个协议都能转换成共同语言,从而互相转换。
![](https://user-gold-cdn.xitu.io/2018/10/31/166c880ac8bdb575?w=1338&h=963&f=png&s=80170)
一般来说共同语言有三种方式指定:
- json:json数据格式比较简单,解析速度快,较轻量级。在Dubbo的生态中有一个HTTP转Dubbo的项目是用JsonRpc做的,将HTTP转化成JsonRpc再转化成Dubbo。
比如可以将一个 www.baidu.com/id = 1 GET 可以映射为json:
代码块
```json
{
"method": "getBaidu"
"param" : {
"id" : 1
}
}
```
- xml:xml数据比较重,解析比较困难,这里不过多讨论。
- 自定义描述语言:一般来说这个成本比较高需要自己定义语言来进行描述并进行解析,但是其扩展性,自定义个性化都是最高。例:spring自定义了一套自己的SPEL表达式语言
对于泛化调用如果要自己设计的话JSON基本可以满足,如果对于个性化的需要特别多的话倒是可以自己定义一套语言。
## 2.7 管理平台
上面介绍的都是如何实现一个网关的技术关键。这里需要介绍网关的一个业务关键。有了网关之后,需要一个管理平台如何去对我们上面所描述的技术关键进行配置,包括但不限于下面这些配置:
- 限流
- 熔断
- 缓存
- 日志
- 自定义filter
- 泛化调用
# 3.总结
最后一个合理的标准网关应该按照如下去实现:
![](https://user-gold-cdn.xitu.io/2018/10/31/166c88416c4cc227?w=2013&h=1007&f=png&s=152690)
---| 京东| 唯品会| 有赞| 阿里| Zuul
---|---|---|---|---|---
实现关键|servlet3.0|netty|servlet3.0|servlet3.0|servlet3.0
异步情况|servlet异步,rpc是否异步不清楚|全链路异步|全链路异步|全链路异步|Zuul1同步阻塞,Zuul2异步非阻塞
限流 |---|---|平滑限流。最初是codis,后续换到每个单机的令牌桶限流。|1.基本流控:基于API的QPS做限流。2.运营流控:支持APP流量包,APP+API+USER的流控33.大促流控:APP访问API的权重流控。阿里开源:Sentinel|提供了jar包:spring-cloud-zuul-ratelimit。1.对请求的目标URL进行限流(例如:某个URL每分钟只允许调用多少次)。2.对客户端的访问IP进行限流(例如:某个IP每分钟只允许请求多少次)3.对某些特定用户或者用户组进行限流(例如:非VIP用户限制每分钟只允许调用100次某个API等)4.多维度混合的限流。此时,就需要实现一些限流规则的编排机制。与、或、非等关系。支持四种存储方式ConcurrentHashMap,Consul,Redis,数据库。
熔断降级|---|---|Hystrix|---|只支持服务级别熔断,不支持URL级别。
隔离|线程池隔离|---|信号量隔离|---|线程池隔离,信号量隔离
缓存|redis|---|二级缓存,本地缓存+Codis|HDCC 本地缓存,远程缓存,数据库|需要自己开发
泛化调用|---|http,https,http1,http2,二进制|dubbo,http,nova|hsf,dubbo,http,https,http2,http1|只支持http
# 4.参考
- 京东:http://www.yunweipai.com/archives/23653.html
- 有赞网关:https://tech.youzan.com/api-gateway-in-practice/
- 唯品会:https://mp.weixin.qq.com/s/gREMe-G7nqNJJLzbZ3ed3A
- Zuul:http://www.scienjus.com/api-gateway-and-netflix-zuul/
## 公众号
如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
![我的公众号](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/167598cd2e17b8ec.png)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册