06.ZUUL网关
https://www.cnblogs.com/duanxz/p/7527765.html
# 01.网关介绍
# 1.1 微服务架构-不足
现有架构介绍
- 我们使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现;
- 而服务间通过Ribbon或Feign实现服务的消费以及均衡负载;
- 通过Spring Cloud Config实现了应用多环境的外部化配置以及版本管理。
- 为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延。
在该架构中,我们的服务集群包含
- 内部服务Service A和Service B,他们都会注册与订阅服务至Eureka Server
- 而Open Service是一个对外的服务,通过均衡负载公开至服务调用方。
- 这里我们把焦点聚集在对外服务这块,这样的实现是否合理,或者是否有更好的实现方式呢?
# 1.2 上面架构问题
先来说说这样架构需要做的一些事儿以及存在的不足
- 第一,破坏了服务无状态特点
- 为了保证对外服务的安全性,我们需要实现
对服务访问的权限控制
,而开放服务的权限控制机制将会贯穿并污染整个开放服务的业务逻辑 - 这会带来的最直接问题是,破坏了服务集群中REST API无状态的特点。
- 从具体开发和测试的角度来说,在工作中除了要考虑实际的业务逻辑之外,还需要额外可续对接口访问的控制处理。
- 为了保证对外服务的安全性,我们需要实现
- 第二,无法直接复用既有接口
- 当我们需要对一个即有的集群内访问接口,实现外部服务访问时
- 我们不得不通过在原有接口上增加校验逻辑,或增加一个代理调用来实现权限控制,无法直接复用原有的接口。
让客户端直接与各个微服务通讯,会有以下的问题:
- 客户端会多次请求不同的微服务,增加了客户端的复杂性。
- 存在跨域请求,在一定场景下处理相对复杂。
- 认证复杂,每个服务都需要独立认证。
- 难以重构,随着项目的迭代,可能需要重新划分微服务。
- 例如,可能将多个服务合并成一个或者将一个服务拆分成多个。
- 如果客户端直接与微服务通讯,那么重构将会很难实施。
- 某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定困难。
# 1.3 网关主要功能
路由转发
之前说了「API网关」是内部微服务的对外唯一入口,所以外面全部的请求都会先发到这个「API网关」上
然后由「API网关」来根据不同的请求去路由到不同的微服务节点上。
例如
可以 根据路径 来转发、也可以 根据参数 来转发
。并且由于内部微服务实例也会随着业务调整不停的变更,增加或者删除节点
「API网关」可以与「服务注册」模块进行协同工作,保证将外部请求转发到最合适的微服务实例上面去。
负载均衡
- 既然「API网关」是内部微服务的单一入口,所以「API网关」在收到外部请求之后,还可以根据内部微服务每个实例的负荷情况进行动态的负载均衡调节。
- 一旦内部的某个微服务实例负载很高,甚至是不能及时响应,则「API网关」就通过负载均衡策略减少或停止向这个实例转发请求。
- 当所有的内部微服务实例都处理不过来的时候,「API网关」还可以采用限流或熔断的形式阻止外部请求,以保障整个系统的可用性。
安全认证
「API网关」就像是微服务的大门守卫,每一个请求进来之后,都必须先在「API网关」上进行身份验证
身份验证通过后才转发给后面的服务,转发的时候一般也会带上身份信息。
同时「API网关」也需要对每一个请求进行安全性检查,例如参数的安全性、传输的安全性等等。
日志记录
- 既然所有的请求都需要走「API网关」,那么我们就可以在「API网关」上统一集中的记录下这些行为日志。
- 这些日志既可以作为我们后续事件查询使用,也可以作为系统的性能监控使用。
数据转换
- 因为「API网关」对外是面向多种不同的客户端,不同的客户端所传输的数据类型可能是不一样的。
- 因此「API网关」还需要具备数据转换的功能,将不同客户端传输进来的数据转换成同一种类型再转发给内部微服务上
- 这样,兼容了这些请求的多样性,保证了微服务的灵活性。
# 1.4 开源网关服务
Zuul
Zuul 是由 Netflix 所开源的组件,基于JAVA技术栈开发的。
Zuul网关的使用热度非常高,并且也集成到了 Spring Cloud 全家桶中了,使用起来非常方便。
看到Zuul的一个简化结构,过滤器filter是整个Zuul的核心
- 分为前置过滤器(pre filter)
- 路由过滤器(routing filter)
- 后置过滤器(post filter)
- 错误过滤器(error filter)
一个请求过来,会先执行所有的 pre filter,然后再通过 routing filter 将请求转发给后端服务,后端服务进行结果响应之后,再执行 post filter,最后再响应给客户端。
在不同的filter里面可以执行不同的逻辑,比如安全检查、日志记录等等。
Tyk
- Tyk是一个基于GO编写的,轻量级、快速可伸缩的开源的API网关。
Kong
- Kong可以做到高性能、插件自定义、集群以及易于使用的Restful API管理。
# 02.zuul
# 2.1 Zuul与Nginx配合
- Nginx的作用是反向代理、负载均衡,Zuul的作用是保障微服务的安全访问,拦截微服务请求,校验合法性及负载均衡。
# 2.2 Zuul 1.0
Zuul网关的核心是一系列的过滤器,这些过滤器可以对请求或者响应结果做一系列过滤
Zuul 提供了一个框架可以支持动态加载,编译,运行这些过滤器
虽然Zuul 支持任何可以在jvm上跑的语言,但是目前zuul的过滤器只能使用Groovy脚本来编写
编写好的过滤器脚本一般放在zuul服务器的固定目录,zuul服务器会开启一个线程定时去轮询被修改或者新增的过滤器
然后动态进行编译,加载到内存,然后等后续有请求进来,新增或者修改后的过滤器就会生效了。
在zuul中过滤器分为四种:
PRE Filters(前置过滤器)
- 当请求会路由转发到具体后端服务器前执行的过滤器,比如鉴权过滤器,日志过滤器,还有路由选择过滤器
ROUTING Filters (路由过滤器)
- 该过滤器作用是把请求具体转发到后端服务器上,一般是通过Apache HttpClient 或者 Netflix Ribbon把请求发送到具体的后端服务器上
POST Filters(后置过滤器)
- 当把请求路由到具体后端服务器后执行的过滤器;
- 场景有添加标准http 响应头,收集一些统计数据(比如请求耗时等),写入请求结果到请求方等。
ERROR Filters(错误过滤器)
- 当上面任何一个类型过滤器执行出错时候执行该过滤器
# 2.3 Zuul 2.0新特性
- Netty作为高性能异步网络通讯框架,在dubbo,rocketmq,sofa等知名开源框架中都有使用
- netty server作为网关监听服务器监听客户端发来的请求,然后把请求转发到前置过滤器(inbound filters)进行处理
- 处理完毕后在把请求使用netty client代理到具体的后端服务器进行处理
- 处理完毕后在把结果交给后者过滤器(outbound filters)进行处理
- 然后把处理结果通过nettyServer写回客户端
- 特性说明
- 在zuul1.0时候客户端发起的请求后需要同步等待zuul网关返回,zuul网关这边对每个请求会分派一个线程来进行处理,这会导致并发请求数量有限。
- 而zuul2.0使用netty作为异步通讯,可以大大加大并发请求量。