网关解决的问题
- API网关,就是指系统的统一入口,提供内部服务的一个路由中转,为客户端提供统一服务,在网关模块中,是流量统一入口,因此我们可以在网关中进行
- 统一鉴权,限流,日志,缓存。
- 统一错误处理
- 请求转发,并且可以基于网关实现内,外网隔离。
网关对比
-
Zuul 1.x
- Netfix开业的网关,基于Servlet框架构建,用java开发,易于二次开发,问题:一个线程处理一个请求,这种方式在内部延迟严重,当接口延迟较多情况下会引起存活的连接增多和线程增加的情况
-
Zuul 2.x
- Zuul 2 采用了Netty实现异步非阻塞编程模型,每一个CPU核心对应一个线程,处理所有请求和响应,请求和响应的生命周期是通过事件和回调处理的,减少了线程数量,因此开销更少
-
Nginx + lua
- 使用nginxx 的方向代理 + 负载均衡也可以实现对APi服务器的负载均衡和高可用,lua是脚本语言,可以用来编写简单逻辑,nginx支持lua脚本,问题:无法融入到微服务架构中。
-
gateway
- 基于Spring Boot2.x,Spring WebFlux,和project Reactor,目的在于为微服务提供一种简单有效的统一api理由管理方式,他目标是替代Netlix zuul,不仅提供统一路由,而且基于Filter 链提供网关基本功能。
- 性能强:是zuul的1.6倍
- 功能强:内置很多实用功能,例如转发,监控,限流
- 设计优雅,容易扩展
gateway 原理分析
- spring cloud gateway 请求处理过程有几个非常重要概念:
- 路由(route):他说网关基本组件,由ID,目标URL,Predicate集合,Filter集合组成
- 断言(Predicate):Javam8引入的函数时接口,提供断言功能,可以匹配Http请求中任何内容,如果断言Predicate判断结果为true才可以继续转发,可以同时定义多个
- 过滤器(Filter):为请求提供前置或者后置过滤。
Route Predicate Factories
- spring cloud gateway 中predicate提供了路由匹配规则,如下代码中,通过Path匹配Url前缀是server的请求
predicates: # 断言
- Path=/server/**
-
gateway提供了很多类型的 Predicate,比如,Cookie,Header,Method,Path等,在gateway中可以自定义这些规则来达到一些规则判断的目的。
-
指定时间规则匹配路由:更具配置的时间来匹配路由规则,
- BeforeRoutePredicateFactory,在指定时间之前路由生效
- AfterRoutePredicateFactory,请求在指定日期之后
- BetweenRoutePredicateFactory,在指定日期之间
-
Cookie匹配路由
- 判断携带的Cookie中是否有匹配规则的数据
-
Header匹配路由
- 判断Header中对应的name和value于匹配规则是否一致,支持正则
-
Host匹配路由:
- Http请求会携带一个Host,表示请求的服务器地址,这个规则可以匹配请求Host路由来做筛选
-
Method,请求方法匹配路由:
- Http请求的Method属性,比如POST,GET等
-
Path,路由匹配,用的最多的:
- 利用通配符等匹配现有业务的一些URL来做转发筛选
Gatewy Filter Factories
- Gateway内置的Filter生命周期分两种: pre(业务逻辑之前),post(业务逻辑之后)
- Gateway本身自带的Filter分两种,GateWayFilter(单一,只对配置的路由生效),GlobalFilter(全局,对所有请求生效)
- Gateway中自定义了比较多的Filter,单一的有32,全局9个
- 用的比较多的:
- LoadBalanceClientFilter: 实现请求负载均衡过滤器
- Retry GatewayFilter:请求重试过滤器,当后台服务不可用,网关会根据配置发起重试。
自定义Filter
- 自定义Filter 用的才是最多的,需要实现Ordered,GlobalFilter,在使用中用到的一些处理
- RewritePathGatewayFilterFactory:
- 因为对于spring-cloud-gateway来说, 请求: //foo/* 跟请求 /foo/* 是不一样的. 而实际上一般web服务的处理都会把多个斜杠等同为一个斜杠, 包括之前的老网关的zuul就是这么处理的.而我们的应用中确实有某些请求是用了两个斜杠的.
- AccessLoggingGatewayFilterFactory:
- 日志处理
- CacheRequestBodyGlobalFilter:
- 因为spring-cloud-gateway存在一个坑: request里面body只能读取一次, 如果某个filter, 读取了一次body,将导致后面的filter无法再次读取, 转发的filter无法读取就无法正常转发. 在某些情况下, 我们的headUa是放在body的form表单里面的, 为了读取headUa, 就必须读取body.为了解决这个问题, 需要把body先copy一份并cache起来, 读取的时候直接用cache的body.
- DeviceFingerprintValidatorGatewayFilterFactory:
- 请求验证过滤器, 主要验证设备指纹信息, 或获取指纹列表
- IpListInterceptorGatewayFilterFactory:
- IP名单过滤
- RequestValidatorGatewayFilterFactory:
- 请求验证过滤器, 主要验证HeadUa的签名,exp:mobile/5.6.0/18/8.4.1/iPhone/0f607264fc6318a92b9e13c65db7cd3c/902684/2/0/1334/750/6F212B1F-4FFF-4189-82ED-B657E62F2084/3/e7ea59f18379035f386f883f0a59ac10adcf664c/test
- Retry2GatewayFilterFactory:
- 请求重试
- TokenValidatorGatewayFilterFactory:
- 主要验证token格式是否正确,例如环境信息,za的token会带环境信息test or online,带appid
gateway 集成Sentinel网关限流
- 原理:
- 通过GatewayRuleManager加载网关限流规则GatewayFlowRule时候,无论是否针对请求属性限流,Sentinel底层都会将网关流控规则GatewayFlowRule 转为热点参数规则ParamFlowRule存储到GatewayFlowManager中,于正常热点参数规则相互隔离。转化时候,Sentinel会根据请求属性配置,为网关流控规则设置参数索引,并添加到深处的热点参数规则中。
-
外部请求进入api网关,经过SentinelGatewayFilter,子过滤器中依次进行Route ID/api分组匹配,请求属性解析,参数组装
-
Sentinel更具配置的网关限流规则来解析请求属性,并按照参数索引顺序组装参数数组,最终传入SphU.entry中
-
在Snetinel Api gateway Adapter common 模块中slot chain中添加了一个GatewayFlowSlot,专门用来处理网关限流规则的检查
-
如果当前限流规则并没有指定限流参数,Sentinelhi会在参数最后一个位置设置一个预设的常量$D最终实现普通限流
-
实际上,网关限流,我们所配置的规则最终都会转为热点参数限流规则,通过ParamFlowChecker.passCheck进行热点参数限流规则检查。