Spring Cloud Alibaba 微服务框架 Spring Cloud Gateway:微服务网关
2022-05-21 12:12:12 5 举报
AI智能生成
Spring Cloud Alibaba 微服务框架 Spring Cloud Gateway 微服务网关
作者其他创作
大纲/内容
概要
没有API网关,客户端调用多个服务实现数据的获取存在的一些问题
客户端需要发起多次请求,增加了网络通信的成本及客户端处理的复杂性
服务的鉴权会分布在每个微服务中处理,客户端对于每个服务的调用都需要重复鉴权
在后端的微服务架构中,可能不同的服务采用的协议不同,比如有HTTP、RPC等。 客户端如果需要调用多个服务,需要对不同协议进行适配
API网关的作用
作用概要
所处位置示例图
图片
网关有点类似于门面,所有的外部请求都会先经过网关这一层
对所有请求进行统一鉴权、限流、熔断、日志
协议转化:针对后端多种不同的协议,在网关层统一处理后以HTTP对外提供服务
统一错误码处理
请求转发,并且可以基于网关实现内、外网隔离
统一认证鉴权
统一认证鉴权包含两部分
客户端身份认证:主要用于判断当前用户是否为合法用户,一般的做法是使用账号和密码进行验证。 当然,对于一些复杂的认证场景会采用加密算法来实现,比如公、私钥
访问权限控制:身份认证和访问权限一般是相互联系的,当身份认证通过后,就需要判断该用户是否有权限访问该资源, 或者该用户的访问权限是否被限制了
微服务鉴权存在的问题及解决方案
单体应用中的session方式已经无法用于微服务场景
解决方案:AccessToken、OAuth(开放API)
如何实现对每个微服务进行鉴权
解决方案:把鉴权的功能抽离出一个统一认证服务,所有的微服务在被访问之前,先访问该认证服务进行鉴权
方案缺陷:在实际应用中,一个业务场景中可能会调用多个微服务,就会造成一次请求需要进行多次鉴权操作,增加了网络通信开销
网关鉴权解决方案
网关鉴权架构图
图片
方案描述
在网关层进行请求拦截,获取请求中附带的用户身份信息
调用统一认证中心对请求进行身份认证
在确认了身份之后再检查是否有资源的访问权限
灰度发布
背景描述:当产品处在高频率的迭代模式下,往往会伴随着一些风险
新发布的代码出现兼容性问题
新的功能发布后,用户是否能够接受,如果不能,会造成用户流失
代码中存在隐藏的Bug,导致线上故障
灰度发布:指将要发布的功能先开放给一小部分用户使用,把影响范围控制在一个非常小的范围
A/B Test
属于一种灰度发布方式
即一部分用户继续使用A功能,另外一小部分用户使用新的B功能
通过对使用B功能的用户进行满意度调查,以及对新发布的代码的性能和稳定性指标进行评测,逐步放大该新版本的投放,直到全量或者回滚该版本
网关的灰度发布方案设计
架构图
图片
方案描述
在网关层可以通过灰度规则进行部分流量的路由,从而实现灰度发布
网关对请求进行拦截之后,会根据分流引擎配置的分流规则进行请求的路由
分流引擎
nexpion-discovery
spring-cloud-gray
网关的本质及技术选型
概要
网关的本质应该是对请求进行路由转发,以及对请求进行前置和后置的过滤
请求的转发和路由
接收客户端的所有请求,并将请求转发到后端的微服务中
因为微服务的粒度比较细,所以API网关又类似于门面模式,对多个微服务进行功能整合,提供唯一的业务接口给客户端
过滤:网关会拦截所有的请求来完成一系列的横切工作,比如鉴权、限流
OpenResty
由Nginx与Lua集成的一个高性能Web应用服务器,它的内部集成了大量优秀的Lua库、第三方模块
OpenResty团队自己研发了很多优秀的Nginx模块,开发人员可以使用Lua脚本来调用Nginx支持的C模块及Lua模块
本质上就是将Lua嵌入Nginx中,在每一个Nginx的进程中都嵌入了一个LuaJIT虚拟机来执行Lua脚本
Spring Cloud Zuul
Zuul是Netflix开源的微服务网关,它的主要功能是路由转发和过滤
Zuul的请求过滤链
图片
Zuul的4种标准类型过滤器
Pre Filters: 前置过滤器,请求被路由之前调用,可以用于处理鉴权、限流等。
Routing Filters: 路由过滤器,将请求路由到后端的微服务。
Post Filters:
后置过滤器,路由过滤器中远程调用结束后执行。可以用于做统计、监控、日志等。
Error Filters:
错误过滤器,任意一个过滤器出现异常或者远程服务调用超时会被调用。
Spring Cloud Gateway
Spring Cloud Gateway是Spring官方团队研发的API网关技术,它的目的是取代Zuul为微服务提供一种简单高效的API网关
取代Zuul的原因
Zuul 1.x 采用的是传统的thread per connection方式来处理请求,
也就是针对每一个请求,会为这个请求专门分配一个线程来进行处理,直到这个请求完成之后才会释放线程,
一旦后台服务器响应较慢,就会使得该线程被阻塞,所以它的性能不是很好
Zuul 1.x 本身存在的一些性能问题不适合于高并发的场景
Zuul 1.x 不支持长链接
Zuul 1.x 不支持WebSocket
Spring Cloud Gateway 特点
基于于Spring Boot 2.0、Spring WebFlux和Project Reactor等技术开发的网关(底层Netty)
不仅提供了统一的路由请求的方式,还基于过滤链的方式提供了网关最基本的功能
不依赖Tomcat,而是用NettyWebServer来启动一个服务监听
支持多种协调的转发:http、https、ws(客户端请求websocket)、wss(客户端请求websocket+TLS)
Spring Cloud Gateway网关实战
准备两个Spring Boot应用
spring-cloud-gateway-service,模拟一个微服务
spring-cloud-gateway-sample,独立的网关服务
spring-cloud-gateway-service
添加spring-boot-starter-web依赖
创建一个HelloController类发布一个接口并启动该应用
spring-cloud-gateway-sample
添加Spring Cloud Gateway依赖
在application.yml文件中添加Gateway的路由配置
配置说明
id:
自定义路由ID,保持唯一。
uri:
目标服务地址,支持普通URI及lb://应用注册服务名称,后者表示从注册中心获取集群服务地址。
predicates:
路由条件,根据匹配的结果决定是否执行该请求路由。
filters:
过滤规则,包含pre和post过滤。其中StripPrefix=1,表示Gateway根据该配置的值去掉URL路径中的部分前缀(这里去掉一个前缀,即在转发的目标URI中去掉gateway)
请求 http://localhost:8088/gateway/say 测试网关是否生效
Spring Cloud Gateway原理分析
请求处理流程图
图片
请求处理流程步骤
Gateway启动时基于Netty Server监听一个指定的端口(该端口可以通过server.port属性自定义)
当客户端发送一个请求到网关时,网关会根据一系列Predicate的匹配结果来决定访问哪个Route路由
然后根据过滤器链进行请求的处理
过滤器链可以在请求发送到后端服务器之前和之后执行
首先执行Pre过滤器链
然后将请求转发到后端服务器
最后执行Post过滤器链
重要的概念说明
路由(Route):它是网关的基本组件,由ID、目标URI、Predicate集合、Filter集合组成。
谓语(Predicate):它是Java 8中引入的函数式接口,提供了断言的功能。它可以匹配HTTP请求中的任何内容。
如果Predicate的聚合判断结果为true,则意味着该请求会被当前Router进行转发。 Gateway中的断言函数输入类型是Spring 5.0框架中的ServerWebExchange
过滤器(Filter):为请求提供前置和后置的过滤。
工作原理流程图
图片
Spring Cloud Gateway的启动容器目前只支持Netty
在配置路由的时候,如果不指定端口的话,http默认设置端口为80,https默认设置端口为443
通过虚线分割Filter的原因是,过滤器可以在转发请求之前处理或者接收到被代理服务的返回结果之后处理
工作原理流程描述
Gateway的客户端会向Spring Cloud Gateway发起请求
请求首先会被HttpWebHandlerAdapter进行提取组装成网关的上下文(ServerWebExchange)
然后网关的上下文会传递到DispatcherHandler分发请求
DispatcherHandler是所有请求的分发处理器
DispatcherHandler主要负责分发请求对应的处理器
比如将请求分发到对应RoutePredicateHandlerMapping(路由断言处理映射器)
路由断言处理映射器主要用于路由的查找,以及找到路由后返回对应的FilteringWebHandler
FilteringWebHandler主要负责组装Filter链表并调用Filter执行一系列的Filter处理
然后把请求转到后端对应的代理服务处理
处理完毕之后,将Response返回到Gateway客户端
底层实现机制
响应式编程是一种基于数据流和变化传递的声明式的编程范式(像vue.js的数据绑定)
基于WebFlux
基于Netty实现响应式编程
同步非阻塞
异步非阻塞
5种IO模型
阻塞IO
模型图
图片
描述:进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程。操作成功则进程获取到数据
典型应用:阻塞socket、Java BIO
特点
进程阻塞挂起不消耗CPU资源,及时响应每个操作;
实现难度低、开发应用较容易;
适用并发量小的网络应用开发;
不适用并发量大的应用:因为一个请求IO会阻塞进程,所以,得为每个请求分配一个处理进程(线程)以及时响应,系统开销大
非阻塞IO
模型图
图片
描述
进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;
进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。
典型应用:socket是非阻塞的方式(设置为NONBLOCK)
特点
进程轮询(重复)调用,消耗CPU的资源;
实现难度低、开发应用相对阻塞IO模式较难;
适用并发量较小、且不需要及时响应的网络应用开发;
对于上面的阻塞IO模型来说,内核数据没准备好需要进程阻塞的时候,就返回一个错误,以使得进程不被阻塞。
IO复用
模型图
图片
描述
多个的进程的IO可以注册到一个复用器(select)上,然后用一个进程调用该select,select会监听所有注册进来的IO;
如果select没有监听的IO在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一IO在内核缓冲区中有可数据时,select调用就会返回;
而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取IO,读取内核中准备好的数据。
可以看到,多个进程注册IO后,只有另一个select调用进程被阻塞。
典型应用:select、poll、epoll三种方案,nginx都可以选择使用这三个方案,Java NIO;
特点
专一进程解决多个进程IO的阻塞问题,性能好;Reactor模式;
实现、开发应用难度较大;
适用高并发服务应用开发:一个进程(线程)响应多个请求;
Linux中IO复用的实现方式:select、poll、epoll 区别
select:注册IO、阻塞扫描,监听的IO最大连接数不能多于FD_SIZE;
poll:原理和Select相似,没有数量限制,但IO数量大扫描线性性能下降;
epoll :事件驱动不阻塞,mmap实现内核与用户空间的消息传递,数量很大,Linux2.6后内核支持;
信号驱动IO
模型图
图片
描述
当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;
当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据。
特点
回调机制
实现、开发应用难度大
异步IO
模型图
图片
描述
当进程发起一个IO操作,进程返回(不阻塞),但也不能返回果结;
内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据。
典型应用:JAVA7 AIO、高性能服务器应用
特点
不阻塞,数据一步到位;Proactor模式;
需要操作系统的底层支持,LINUX 2.5 版本内核首现,2.6 版本产品的内核标准特性;
实现、开发应用难度大;
非常适合高性能高并发应用;
IO模型比较
图片
epoll的优点:https://blog.csdn.net/lsgqjh/article/details/86622532
通过Mono(返回0或1个元素)或者Flux(返回0-n个元素)返回数据
Mono和Flux 这两种数据模型是WebFlux的核心
采用Reactor响应式流库:https://projectreactor.io
reactor.netty
HttpServerRequest
HttpServerResponse
WebFlux 应用中,所有数据都应该以Mono、Flux的形式表示,这样才能带来最好的性能和高吞吐量
效率高
通过一个线程处理大量的用户请求(高吞吐量),Netty的IO多路复用机制
Tomcat需要为每一个用户请求开一个线程来处理(tomcat的nio2模式)
通过减少线程及线程之间的切换,获得更的资源利用率
Spring5提供了一整套响应式(非阻塞)的技术栈
图片
注意:当前还没有对常用数据库提供支持(如:MySQL),这样在查询DB数据时不能做到响应式而成变成阻塞点
WebFlux只是响应式编程中的一部分(在Web控制端)
响应式一般用Netty或者Servlet 3.1的容器(因为支持异步非阻塞)
Java Lambda 语法
Java Stream 编程:https://www.jianshu.com/p/11c925cdba50(待学习)
响应式流编程都是操作流
源码分析?
概要
HttpWebHandlerAdapter:构建组装网关请求的上下文(ServerWebExchange)。
DispatcherHandler:所有请求的分发处理器,负责分发请求到对应的处理器。
RoutePredicateHandlerMapping:路由断言处理映射器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理。
FilteringWebHandler:创建过滤器链,使用Filter链表处理请求。
Gateway中ServerWebExchange构建分析
DispatcherHandler源码分析
RoutePredicateHandlerMapping源码分析
FilteringWebHandler源码分析
执行Filter源码分析
Gateway Route Predicate Factories
概要
Predicate是Java 8提供的一个函数式接口,它允许接收一个参数并返回一个布尔值,可以用于条件过滤、请求参数的校验
Spring Cloud Gateway默认提供了很多
Route Predicate Factory
图片
这些Predicate会分别匹配HTTP请求的不同属性,并且多个Predicate可以通过and逻辑进行组合
官方自带路由断言工厂
请求时间规则匹配路由
三种时间规则路由
请求在指定日期之前:BeforeRoutePredicateFactory
请求在指定日期之后:AfterRoutePredicateFactory
请求在指定的两个日期之间:BetweenRoutePredicateFactory
示例
需求:希望在2020年6月1号之前发生的请求都路由到www.example.com
配置
图片
注意点
配置的日期时间必须满足ZonedDateTime的格式
ZonedDateTime格式说明
图片
Cookie匹配路由
实现类:CookieRoutePredicateFactory
判断请求中携带的Cookie是否匹配配置的规则
示例
需求:当前请求的cookie需要携带一个name=chocolate,并且value需要通过正则表达式匹配mic,才能路由到http://example.com
配置
图片
Header匹配路由
实现类:HeaderRoutePredicateFactory 判断请求中Header头消息对应的name和value与Predicate配置的值是否匹配,value也是正则匹配形式
示例
需求:请求中Header头中的name=X-Request-Id,并且value会根据正则表达式匹配\d+,也就是匹配1个以上的数字
配置
图片
Host匹配路由
实现类:HostRoutePredicateFactory
匹配请求中的Host字段进行路由
示例
需求:请求中Host的值符合**.somehost.com,**anotherhost.com时,将请求路由到http://example.com
配置
图片
说明
HTTP请求会携带一个Host字段,这个字段表示请求的服务器网址
Host可以配置一个列表,列表中的每个元素通过,分隔
路径命名及匹配规则支持Ant Path
Method匹配路由
实现类:MethodRoutePredicateFactory
根据HTTP请求的Method属性来匹配以实现路由
示例
需求:如果HTTP请求的方法是GET或POST,则路由到https://example.com
配置
图片
Path匹配路由
实现类:PathRoutePredicateFactory
根据请求路径规则匹配以实现路由
示例
需求:匹配请求的URI为/red/*、/blue/*时,转发到http://example.com
配置
图片
说明
${segment}是一种比较特殊的占位符
/*表示单层路径匹配,/**表示多层路径匹配
Query匹配路由
实现类:QueryRoutePredicateFactory
从请求中获取两个参数,将请求中参数和Query断言路由中的配置进行匹配
示例
RemoteAddr匹配路由
实现类:RemoteAddrRoutePredicateFactory
配置一个IPv4或IPv6网段的字符串或者IP。当请求IP地址在网段之内或者和配置的IP相同,则表示匹配成功,成功转发,否则不能转发
示例
权重匹配路由
实现类:WeightRoutePredicateFactory
对URL进行权重路由(灰度发布)
示例
场景:在线上灰度的时候,需要通过网关动态实时推送路由权重信息。比如95%的流量走服务V1版本,5%的流量走服务V2版本
在application.yml中配置权重路由信息
后端服务主要提供两个版本的服务接口
启动测试
自定义路由断言工厂
自定义路由断言工厂需要继承AbstractRoutePredicateFactory类,重写apply方法的逻辑
在apply方法中可以通过exchange.getRequest()拿到ServerHttpRequest对象,从而可以获取到请求的参数、请求方式、请求头等信息
apply方法的参数是自定义的配置类,在使用的时候配置参数,在apply方法中直接获取使用
命名需要以RoutePredicateFactory结尾,比如:CheckAuthRoutePredicateFactory,那么在使用的时候CheckAuth就是这个路由断言工厂的名称
代码示例
使用示例
Gateway Filter Factories
概要
Filter过滤器的两种类型
Pre类型:在请求转发到后端微服务之前执行,在Pre类型过滤器链中可以做鉴权、限流等操作
Post类型:在请求执行完之后、将结果返回给客户端之前执行
Filter过滤器的两种实现
GatewayFilter:只会应用到单个路由或者一个分组的路由上
GlobalFilter:会应用到所有的路由上
GatewayFilter 内置过滤说明
AddRequestParameterGatewayFilterFactory
作用:对所有匹配的请求添加一个查询参数
示例
图片
会对所有请求增加foo=bar这个参数
AddRequestHeaderGatewayFilterFactory
作用:对匹配上的请求加上header
示例
RemoveRequestHeaderGatewayFilterFactory
作用:在请求转发到后端服务之前进行Header的移除操作
示例
AddResponseHeaderGatewayFilterFactory
作用:对所有匹配的请求,在返回结果给客户端之前,在Header中添加相应的数据
示例
图片
会在Response中添加Header头,key=X-Response-Foo,Value=Bar
RequestRateLimiterGatewayFilterFactory
作用:对访问到当前网关的所有请求执行限流过滤,如果被限流,默认情况下会响应HTTP 429-Too Many Requests
说明
默认提供了RedisRateLimiter的限流实现,它采用令牌桶算法来实现限流功能
redis-rate-limiter过滤器有两个配置属性
replenishRate: 令牌桶中令牌的填充速度,代表允许每秒执行的请求数
burstCapacity: 令牌桶的容量,也就是令牌桶最多能够容纳的令牌数。表示每秒用户最大能够执行的请求数量
配置示例
图片
示例
需求:实现限制同一个IP的请求频次
实现步骤
添加jar包依赖,Redis的限流器基于Stripe实现
创建一个KeyResolver的实现类
KeyResolver接口主要用于设置限流请求的key,我们可以实现该接口来指定需要对当前请求中的哪些因素进行流量控制。在上述代码中我们设置了HostAddress,表示根据请求IP来限流
KeyResolver的默认实现是PrincipalNameKeyResolver,它会从ServerWebExchange检索Principal并调用Principal.getName
在默认情况下,如果KeyResolver没有获取到key,请求将被拒绝。我们可以通过这两个属性来调整
spring.cloud.gateway.filter.request-rate-limiter.denyEmptyKey,是否允许空的key
spring.cloud.gateway.filter.request-rate-limiter.emptyKeyStatus,当deny-empty-key=true时返回的HttpStatus,默认为FORBIDDEN(403,"Forbidden")
在application.yml中添加配置
图片
keyResolver采用的是SpEL表达式按照名称来引用Bean,#{@ipAddressKeyResolver}表示引用name=ipAddressKeyResolver的Bean
通过测试工具访问网关即可看到限流的效果,默认响应HTTP ERROR 429
登录Redis服务器,可以看到在Redis中会生成如下两个key
图片
自定义限流
Spring Cloud Gateway目前默认只实现了基于Redis的Ratelimiter限流方式
基于Ratelimiter扩展限流功能
创建自定义限流器,实现AbstractRateLimiter接口
指定自定义限流器,rateLimiter:#{@defineRateLimiter}
RewritePathGatewayFilterFactory
作用:使用RewritePath替换Zuul的StripPrefix功能,而且功能更强大
示例
StripPrefixGatewayFilterFactory
作用:对请求url前缀进行处理的filter工厂,用于去除前缀
示例
PrefixPathGatewayFilterFactory
作用:对请求url前缀进行处理的filter工厂,用于增加前缀
示例
SetStatusGatewayFilterFactory
作用:用于设置Http请求的响应码。它必须是有效的Spring Httpstatus(org.springframework.http.HttpStatus) 它可以是整数值404或枚举类型NOT_FOUND
示例
RedirectToGatewayFilterFactory
作用:用于重定向操作
示例
RetryGatewayFilterFactory
作用:为请求重试过滤器,当后端服务不可用时,网关会根据配置参数来发起重试请求
示例
图片
参数说明
retries:请求重试次数,默认值是3。
status: HTTP请求返回的状态码,针对指定状态码进行重试,比如,在上述配置中,当服务端返回的状态码是503时,才会发起重试,此处可以配置多个状态码。
methods:
指定HTTP请求中哪些方法类型需要进行重试,默认值是GET。
series: 配置错误码段,表示符合某段状态码才发起重试,默认值是SERVER_ERROR(5),表示5xx段的状态码都会发起重试。 如果series配置了错误码段,但是status没有配置,则仍然会匹配series进行重试。
HystrixGatewayFilterFactory
作用:提供路由层面的服务熔断和降级
集成步骤
添加jar包依赖:spring-cloud-starter-netflix-hystrix
在application.yml中配置Hystrix Filter的路由配置
创建fallbackUri
创建需要Fallback的后端服务
启动应用测试
GlobalFilter 内置过滤说明
全局过滤链的执行顺序说明
当Gateway接收到请求时,Filtering Web Handler处理器会将所有的GlobalFilter实例 及所有路由上所配置的GatewayFilter实例添加到一条过滤器链中
该过滤器链里的所有过滤器都会按照@Order注解所指定的数字大小进行排序
LoadBalancerClientFilter:整合Ribbon针对下游服务实现负载均衡
图片
如果URI配置的是lb://example_service,那么这个过滤器会识别到lb://,
并且使用Spring Cloud LoadBalancerClient将example_service名称解析成实际访问的主机和端口地址
GatewayMetricsFilter:提供监控指标
过滤器会添加name=gateway.requests的timer metrics,其中包含的数据
routeId:路由ID
routeUri:API网关将路由到的URI
outcome:返回的状态码段,值的枚举类定义在HttpStatus.Series中
status:返回给客户端的HTTP Status
httpStatusCode:返回给客户端的HttpStatusCode,如200
httpMethod:请求所使用的HTTP方法
获取timer metris 指标
添加Spring Boot Actuator依赖
在application.yml中开启监控管理Endpoint,并将所有断点暴露出来
访问gatewaymetric端点:http://ip:port/actuator/metrics/gateway.requests
将会获得指标数据(如果数据为空,可以先访问一次网关的接口)
在实际应用中,我们可以将这些信息发布到监控平台上,比如可以集成Prometheus,进行可视化监控
ForwardRoutingFilter:用于本地forward,请求不转发到下游服务器
NettyRoutingFilter:使用Netty的HttpClient转发HTTP、HTTPS请求
Gateway自定义过滤器
自定义GatewayFilter
创建一个自定义过滤器类GpDefineGatewayFilterFactory,继承AbstractGatewayFilterFactory
示例代码
图片
类名必须要统一以GatewayFilterFactory结尾,因为默认情况下过滤器的name会采用该自定义类的前缀。这里的name=GpDefine
在apply方法中,同时包含Pre和Post过滤。在then方法中是请求执行结束之后的后置处理
GpConfig是一个配置类,该类中只有一个属性name。这个属性可以在yml文件中使用
该类需要装载到Spring IoC容器,此处使用@Service注解实现
通过AbstractGatewayFilterFactory实现的局部过滤器没有指定order,它的默认值是0,如果想要设置多个过滤器的执行顺序,可以重写getOrder方法
在application.yml文件中配置该自定义过滤器
图片
name属性就是GpDefineGatewayFilterFactory的前缀
args中的name属性是GpConfig配置类中声明的属性
通过curl命令访问网关服务
图片
自定义GlobalFilter
只需要实现GlobalFilter接口,自动会过滤所有的Route
图片
getOrder表示该过滤器的执行顺序,值越小,执行优先级越高
自定义限流Filter
基于CPU的使用率进行限流
使用场景:在实际项目应用中对网关进行限流时。可能会根据网络请求连接数、请求流量、CPU使用率等流控。
实现原理
可以通过Spring Boot Actuator提供的Metrics获取当前CPU的使用情况,当CPU使用率高于某个阈值就开启限流,否则不开启限流。
在Actuator 2.x 里通过MetricsEndpoint来获取CPU的使用情况
实现步骤
添加 spring-boot-starter-actuator 依赖
自定义过滤器Filter并开启基于CPU使用情况的限流:GatewayRateLimitFilterByCpu.java
如果 GatewayRateLimitFilterByCpu 实现的是 GatewayFilter,则是对指定路由限流
如果 GatewayRateLimitFilterByCpu 实现的是 GlobalFilter,则是对全局路由限流
通过Java流式API的方式配置路由规则
基于请求IP数的令牌桶限流
添加 bucket4j 依赖
自定义过滤器对请求IP进行限流:GatewayRateLimitFilterByIp.java
通过Java流式API的方式配置路由规则
启动测试
Gateway集成Nacos实现请求负载均衡和动态路由
概要
利用Nacos注册中心功能实现请求负载均衡
利用Nacos配置中心功能实现请求动态路由
实现步骤
实现架构图
图片
spring-cloud-gateway-nacos-provider,提供REST服务,并将服务注册到Nacos上
添加相关jar包依赖
spring-cloud-starter-web
spring-cloud-alibaba-nacos-discovery
创建NacosController,提供一个/say接口
在application.yml中添加nacos服务注册地址的配置
将spring-cloud-gateway-nacos-provider部署两份,分别开放8080和8081端口
服务启动成功之后,进入Nacos Dashboard的服务列表
spring-cloud-gateway-nacos-consumer,提供网关路由,基于Nacos服务注册中心
添加nacos和网关的jar依赖
spring-cloud-starter-gateway
spring-cloud-alibaba-nacos-discovery
在application.yml中添加nacos和网关配置
图片
关键配置说明
spring.cloud.gateway.discovery.locator.enabled: 开启从注册中心动态创建路由的功能
spring.cloud.gateway.discovery.locator.lower-case-service-id: 是否使用service-id的小写,默认是大写
spring.cloud.gateway.routes.uri: 其中配置的lb://表示从注册中心获取服务,后面的spring-cloud-nacos-gateway-provider表示目标服务在注册中心上的服务名
多次通过网关访问http://localhost:8888/nacos/say接口实现对provider服务的请求负载均衡访问
注意:动态路由实现将 spring.cloud.gateway.routes 路由信息配置到nacos上,在nacos修改后实时生效实现动态路由
Gateway集成Sentinel实现网关限流
概要
Sentinel从1.6.0版本开始,提供了Spring Cloud Gateway Adapter模块来支持限流
两种资源维度的限流
Route维度
自定义API维度,可以利用提供的API来自定义API分组,然后针对这些分组维度进行限流
需要依赖 sentinel-spring-cloud-gateway-adapter
Route维度限流
添加一个配置类GatewayConfiguration
注入一个全局限流过滤器SentinelGatewayFilter
注入限流默认异常处理器
初始化限流规则,在当前的版本中,sentinel-spring-cloud-gateway-adapter还只能支持手动配置
GatewayFlowRule网关限流规则中属性说明
resource:资源名称,可以是网关中的route名称或者用户自定义的API分组名称。
resourceMode:资源模型
RESOURCE_MODE_ROUTE_ID:限流规则是针对API Gateway的route(默认)
RESOURCE_MODE_CUSTOM_API_NAME:限流规则是针对用户在Sentinel中定义的API分组
grade: 限流指标维度,同限流规则的grade字段。
count: 限流阈值。
intervalSec:统计时间窗口,单位是秒,默认是1秒。
controlBehavior: 流量整形的控制效果,同限流规则的controlBehavior字段
快速失败(默认)
匀速排队
burst:应对突发请求时额外允许的请求数目。
maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
paramItem: 参数限流配置
有值:则会转换成热点规则
无值:则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则
字段说明
parseStrategy: 从请求中提取参数的策略,目前支持四种模式。
提取来源IP:PARAM_PARSE_STRATEGY_CLIENT_IP
提取来源Host:PARAM_PARSE_STRATEGY_HOST
任意Header :PARAM_PARSE_STRATEGY_HEADER
任意URL参数:PARAM_PARSE_STRATEGY_URL_PARAM
fieldName: 若提取策略选择Header模式或URL参数模式,则需要指定对应的Header名称或URL参数名称。
pattern 和 matchStrategy: 为后续参数匹配特性预留,目前未实现。
网关限流规则的加载方式
通过GatewayRuleManager.loadRules(rules)的方式手动加载
通过GatewayRuleManager.register2Property(property)注册动态限流规则(建议方式)
Gateway的application.yml文件中的配置
访问http://localhsot:8888/nacos/say,当触发限流之后,会获得如下内容:
Blocked by Sentinel:ParamFlowException
自定义API分组限流
自定义API分组限流实际上就是让多个Route共用一个限流规则
有如图两个URI匹配规则,要求这两个路由共用同一个限流规则
图片
采用自定义API分组限流的方式来实现
将/foo/**和/baz/**进行统一分组,并提供一个name=first_customized_api
然后在初始化网关限流规则时,针对该name设置限流规则
同时,我们可以通过setMatchStrategy来设置不同path下的限流参数策略
注意:foo_route和baz_route这两个路由ID与first_customized_api都会标记为Sentinel的资源(限流资源标识)
自定义限流异常返回结果
实际应用中,一般都以JSON格式进行异常数据的返回
实现步骤
创建一个自定义限流异常处理器GpSentinelGatewayBlockExceptionHandler(实现WebExceptionHandler接口)
在配置类GatewayConfiguration中注入自定义限流异常处理器
通过测试工具访问网关地址,如果被限流,将会获得如下异常:
{" code":999, "msg" :"访问人数过多"}
网关流控控制台
网关接入Sentinel Dashboard控制台好处
可以在Sentinel控制台上查看API Gateway实时的Route和自定义API分组的监控
可以在控制台上管理网关的流控规则和API分组配置
网关接入Sentinel Dashboard控制台步骤
添加sentinel dashboard的jar包依赖:sentinel-transport-simple-http
在application.yml中添加sentinel dashboard地址(推荐)
或者在Gateway启动时指定sentinel dashboard地址
Gateway启动时添加参数:-Dcsp.sentinel.app.type=1(Sentinel Dashboard会针对Gateway提供一个定制化的界面)
在sentinel dashboard对网关相关接口做流控
网关限流原理
实现原理
图片
流程解析
在外部请求进入API网关时,会先经过SentinelGatewayFilter,在该过滤器中依次进行Route ID/API分组匹配、请求属性解析和参数组装。
Sentinel根据配置的网关限流规则来解析请求属性,并依照参数索引顺序组装参数数组,最终传入SphU.entry(name,args)中。
在Sentinel API Gateway Adapter Common模块中在Slot Chain中添加了一个GatewayFlowSlot,专门用来处理网关限流规则的检查。
如果当前限流规则并没有指定限流参数,则Sentinel会在参数的最后一个位置置入一个预设的常量$D,最终实现普通限流。
在网关限流中,我们所配置的网关限流规则最终都会转化为参数限流规则,通过ParamFlowChecker.passCheck进行参数限流规则检查
通过GatewayRuleManager加载网关限流规则GatewayFlowRule时,无论是否针对请求属性进行限流
Sentinel底层都会将网关流控规则GatewayFlowRule转化为热点参数规则ParamFlowRule存储在GatewayFlowManager中, 与正常的热点参数规则相互隔离
在转化时,Sentinel会根据请求属性配置,为网关流控规则设置参数索引(idx),并添加到生成的热点参数规则中
如果导图对您有用,请在右上角给点个赞吧
0 条评论
下一页