Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)
Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)
一、服务网关
1.1 什么是网关
在微服务架构中,服务网关是一个至关重要的组件。它作为系统的入口,负责接收客户端的请求,并将这些请求路由到相应的后端服务。API
网关是一个搭建在客户端和微服务之间的服务,可以在API
网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。API
网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到API
网关,由API
网关根据请求的标识信息将请求转发到微服务实例。Spring Cloud Gateway
是Spring Cloud
提供的一个强大的服务网关解决方案。
Spring Cloud Gateway
底层使用了高性能的通信框架Netty。Netty 是高性能中间件的通讯底座, rocketmq
、seata
、nacos
、sentinel
、redission
、dubbo
等太多、太多的的大名鼎鼎的中间件,无一例外都是基于netty
。
与 Spring Cloud Netflix Zuul
相比,Spring Cloud Gateway
具有更好的性能和更丰富的功能。例如,Gateway
基于WebFlux
构建,支持响应式编程,能够更好地处理高并发场景。同时,它的路由和过滤配置更加灵活和简洁。Spring Cloud Gateway
替换掉Zuul
的成本上是非常低的,几乎可以无缝切换。Spring Cloud Gateway
几乎包含了Zuul
的所有功能。随着时间的发展,Spring Cloud Netflix Zuul
会被Spring Cloud Gateway
取代,想学点新技术的小伙伴,就去玩转Spring Cloud Gateway
吧,别再死死抓住Zuul
不放了。
1.2 网关的作用
作用 | 说明 |
---|---|
路由 | 接口服务的统一代理,实现前端对接口服务的统一访问。 |
过滤 | 对用户请求进行拦截、过滤、用户鉴权、监控等。 |
限流 | 限制用户的访问流量。 |
1.3 常用的网关
网关名称 | 优点 | 缺点 |
---|---|---|
Spring Cloud Gateway | 1. 基于 Spring 框架,与 Spring 生态系统集成方便,如和 Spring Boot、Spring Cloud 等配合良好。 2. 支持多种路由匹配方式,包括路径、请求头、请求参数等,灵活性高。 3. 可以方便地通过 Java 代码实现自定义的过滤器,用于实现诸如安全认证、日志记录、请求修改等功能。 4. 具备较好的性能,能处理高并发请求。 | 1. 对于不熟悉 Spring 框架的开发者有一定的学习成本。 2. 配置相对复杂,尤其是大规模复杂场景下,路由和过滤器的配置可能变得繁琐。 |
Spring Cloud Netflix Zuul | 1. 是 Spring Cloud 早期的网关解决方案,和 Spring Cloud 生态融合度较好。 2. 支持动态路由、监控、弹性和安全等功能,能够方便地对请求进行路由和过滤。 3. 可以通过编写 Zuul Filter 来扩展功能。 | 1. 相比一些新兴的网关,性能在高并发场景下可能稍逊一筹。 2. 新功能更新速度相对较慢,社区活跃度不如一些其他网关。 |
Kong | 1. 开源的、轻量级的高性能 API 网关,基于 Nginx 和 OpenResty 构建。 2. 支持插件机制,可以轻松扩展功能,如身份验证、限流、日志记录等。 3. 可用于微服务架构中,对前后端分离的应用进行有效的请求转发和管理。 4. 提供了良好的可扩展性和分布式部署能力。 | 1. 文档在某些方面可能不够详细,对于初次使用者有一定的学习门槛。 2. 复杂的插件配置可能会影响性能,如果插件使用不当可能出现一些难以排查的问题。 |
Nginx + Lua | 1. Nginx 本身性能卓越,处理高并发能力强,可以高效地处理大量的网络请求。 2. Lua 脚本可以方便地嵌入到 Nginx 中实现自定义的业务逻辑,如动态路由、请求过滤等。 3. 可以灵活地进行配置和优化,适用于各种规模的网络架构。 | 1. 开发和维护需要对 Nginx 和 Lua 都有深入的了解,技术门槛较高。 2. Lua 脚本编写不当可能会导致内存泄漏等问题,影响系统的稳定性。 |
Traefik | 1. 自动发现后端服务,支持多种容器编排工具(如 Docker、Kubernetes 等),配置简单。 2. 具有动态配置更新能力,无需重启即可应用新的配置。 3. 提供了简洁直观的 Web UI 用于监控和管理。 4. 性能较好,能有效处理大规模流量。 | 1. 一些高级功能可能需要额外的配置和学习,对复杂场景的支持可能需要更多探索。 2. 在处理某些特殊的业务逻辑定制方面可能不如一些基于编程实现的网关灵活。 |
SpringCloud GateWay
的主要功能之一是转发请求,转发规则的定义主要包含三大核心概念
术语 | 功能 |
---|---|
Route(路由) | 路由是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发。 |
Predicate(谓语、断言) | 路由转发的判断条件,目前SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等,写法必须遵循 key=vlue的形式。 |
Filter(过滤器) | 过滤器是路由转发请求时所经过的过滤逻辑,可用于修改请求、响应内容。 |
二、SpringCloud Gateway路由
复制eurekaClient
工程,修改名称为hepGatewayEntrance
。
修改pom.xml
文件:
<artifactId>hepGatewayEntrance</artifactId>
<name>hepGatewayEntrance</name>
<description>hepGatewayEntrance</description>
引入以下依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
修改系统的hosts
,Windows10
的hosts
文件路径为:C:\Windows\System32\drivers\etc\hosts
。Linux
和macOS
的文件路径为/etc/hosts
。增加一行:127.0.0.1 hepGatewayEntrance
。
2.1 基础URI路由配置
修改application.yml
文件为:
server:port: 8005 # 端口号spring:main:web-application-type: reactivecloud:gateway:discovery:locator:enabled: trueroutes:- id: hep-api-userServiceuri: http://localhost:8000predicates:- Path=/**application:name: hepGatewayEntrance #Gateway名称eureka:instance:prefer-ip-address: falsehostname: hepGatewayEntrancelease-renewal-interval-in-seconds: 5lease-expiration-duration-in-seconds: 10client:healthcheck:enabled: truefetch-registry: trueregister-with-eureka: trueservice-url:defaultZone: http://eureka:eurekapwd@eurekaServer:8761/eureka/ registry-fetch-interval-seconds: 5
Spring Cloud Gateway
配置各字段含义如下:
-
id
:自定义的路由ID
,保持唯一 -
uri
:目标服务地址 -
Predicate
断言: 这是一个Java 8 Function Predicate
。输入类型是Spring Framework ServerWebExchange
。允许开发人员匹配来自HTTP请求的任何内容,例如Header
或参数。Predicate
接受一个输入参数,返回一个布尔值结果。Spring Cloud Gateway
内置了许多Predicate
,这些Predicate
的源码在org.springframework.cloud.gateway.handler.predicate
包中。
上面这段配置的意思是,配置了一个 id
为 hep-api-userService
的URI
代理规则,路由的规则为:当访问地址http://localhost:8005/getUserById
时,会路由到上游地址http://localhost:8000/getUserById
。
常见的 Predicate
断言如下
断言 | 示例 | 说明 |
---|---|---|
Path | - Path=/user/** | 当请求路径与 /user/** 匹配时,该请求才能被转发到 http://localhost:8000/ 上。 |
Before | - Before=2024-10-20T11:47:34.255+08:00[Asia/Shanghai] | 在 2024 年 10 月 20 日 11 时 47 分 34.255 秒之前的请求,才会被转发到 http://localhost:8000/ 上。 |
After | - After=2024-10-20T11:47:34.255+08:00[Asia/Shanghai] | 在 2024 年 10 月 20 日 11 时 47 分 34.255 秒之后的请求,才会被转发到http://localhost:8000/ 上。 |
Between | - Between=2024-10-20T15:18:33.226+08:00[Asia/Shanghai],2024-10-20T15:23:33.226+08:00[Asia/Shanghai] | 在 2024 年 10 月 20 日 15 时 18 分 33.226 秒 到 2024年 10 月 20 日 15 时 23 分 33.226 秒之间的请求,才会被转发到http://localhost:8000/ 服务器上。 |
Cookie | - Cookie=name,c.biancheng.net | 携带 Cookie 且 Cookie 的内容为 name=c.biancheng.net 的请求,才会被转发到http://localhost:8000/ 上。 |
Header | - Header=X-Request-Id,\d+ | 请求头上携带属性 X-Request-Id 且属性值为整数的请求,才会被转发到http://localhost:8000/ 上。 |
Method | - Method=GET | 只有 GET 请求才会被转发到http://localhost:8000/ 上。 |
当然我们也可以把EurekaClient
的接口修改一下,使其前面增加一个/user/
的路径
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getUserById")public String getUserById() throws Exception{return "{id:1,name:jason,age:23,sex: man}";}
}
在Spring Cloud Gateway
中也设置一下/user/
路径Path=/user/**
spring:main:web-application-type: reactivecloud:gateway:discovery:locator:enabled: trueroutes:- id: hep-api-userServiceuri: http://localhost:8000predicates:- Path=/user/**
当访问地址http://localhost:8005/user/getUserById
时,会路由到上游地址http://localhost:8000/user/getUserById
。
2.2 动态路由配置
Spring Cloud Gateway
会根据Eureka Server
服务注册中心中维护的服务列表,以服务名(spring.application.name)
作为路径创建动态路由进行转发,从而实现动态路由功能。
我们把Spring Cloud Gateway
的uri
修改为uri: lb://EUREKACLIENT
,其中lb
标识负载均衡,为uri
的协议,表示开启 Spring Cloud Gateway
的负载均衡功能,EUREKACLIENT
是服务的名称,注意一般是大写。
spring:main:web-application-type: reactivecloud:gateway:discovery:locator:enabled: trueroutes:- id: hep-api-userServiceuri: lb://EUREKACLIENTpredicates:- Path=/user/**
三、SpringCloud Gateway 过滤器
3.1 GatewayFilter 网关过滤器
我们来使用一下PrefixPath GatewayFilter
吧,当我们增加一项PrefixPath=/user
,并把Path中
的/user/
去掉,改成Path=/**
spring:main:web-application-type: reactivecloud:gateway:discovery:locator:enabled: trueroutes:- id: hep-api-userServiceuri: lb://EUREKACLIENTpredicates:- Path=/**filters:- PrefixPath=/user
所有匹配该路由的请求路径都会被添加/user
前缀。例如,一个原本请求/getUserById
的请求,经过该过滤器后,实际请求路径会变为/user/getUserById
,然后被转发到http://localhost:8000/user/getUserById
。
Spring Cloud Gateway
内置了多达 31 种 GatewayFilter
,下表中列举了几种常用的网关过滤器及其使用示例。
路由过滤器 | 描述 | 参数 | 使用示例 |
---|---|---|---|
AddRequestHeader | 拦截传入的请求,并在请求上添加一个指定的请求头参数。 | name:需要添加的请求头参数的 key; value:需要添加的请求头参数的 value。 | - AddRequestHeader=my-request-header,1024 |
AddRequestParameter | 拦截传入的请求,并在请求上添加一个指定的请求参数。 | name:需要添加的请求参数的 key; value:需要添加的请求参数的 value。 | - AddRequestParameter=my-request-param,c.biancheng.net |
AddResponseHeader | 拦截响应,并在响应上添加一个指定的响应头参数。 | name:需要添加的响应头的 key; value:需要添加的响应头的 value。 | - AddResponseHeader=my-response-header,c.biancheng.net |
PrefixPath | 拦截传入的请求,并在请求路径增加一个指定的前缀。 | prefix:需要增加的路径前缀。 | - PrefixPath=/consumer |
PreserveHostHeader | 转发请求时,保持客户端的 Host 信息不变,然后将它传递到提供具体服务的微服务中。 | 无 | - PreserveHostHeader |
RemoveRequestHeader | 移除请求头中指定的参数。 | name:需要移除的请求头的 key。 | - RemoveRequestHeader=my-request-header |
RemoveResponseHeader | 移除响应头中指定的参数。 | name:需要移除的响应头。 | - RemoveResponseHeader=my-response-header |
RemoveRequestParameter | 移除指定的请求参数。 | name:需要移除的请求参数。 | - RemoveRequestParameter=my-request-param |
RequestSize | 配置请求体的大小,当请求体过大时,将会返回 413 Payload Too Large。 | maxSize:请求体的大小。 | - name: RequestSize args: maxSize: 5000000 |
31 种 GatewayFilter
列表
1. AddRequestHeader 在请求头中添加参数
2. AddRequestParameter 添加请求参数
3. AddResponseHeader
4. The DedupeResponseHeader GatewayFilter Factory
5. The Hystrix GatewayFilter Factory
6. Spring Cloud CircuitBreaker GatewayFilter Factory
7. The FallbackHeaders GatewayFilter Factory
8. The MapRequestHeader GatewayFilter Factory
9. The PrefixPath GatewayFilter Factory
10. The PreserveHostHeader GatewayFilter Factory
11. The RequestRateLimiter GatewayFilter Factory
12. The RedirectTo GatewayFilter Factory
13. The RemoveRequestHeader GatewayFilter Factory
14. RemoveResponseHeader GatewayFilter Factory
15. The RemoveRequestParameter GatewayFilter Factory
16. The RewritePath GatewayFilter Factory
17. RewriteLocationResponseHeader GatewayFilter Factory
18. The RewriteResponseHeader GatewayFilter Factory
19. The SaveSession GatewayFilter Factory
20. The SecureHeaders GatewayFilter Factory
21. The SetPath GatewayFilter Factory
22. The SetRequestHeader GatewayFilter Factory
23. The SetResponseHeader GatewayFilter Factory
24. The SetStatus GatewayFilter Factory
25. The StripPrefix GatewayFilter Factory
26. The Retry GatewayFilter Factory
27. The RequestSize GatewayFilter Factory
28. The SetRequestHostHeader GatewayFilter Factory
29. Modify a Request Body GatewayFilter Factory
30. Modify a Response Body GatewayFilter Factory
31. Default Filters
3.2 GlobalFilter 全局过滤器
GlobalFilter
是一种作用于所有的路由上的全局过滤器,通过它,我们可以实现一些统一化的业务功能,例如权限认证、IP 访问限制等。当某个请求被路由匹配时,那么所有的 GlobalFilter
会和该路由自身配置的 GatewayFilter
组合成一个过滤器链。 GlobalFilter
全局过滤器有Gateway Metrics Filter
、Local Response Cache Filter
、Forward Routing Filter
、Netty Routing Filter
、Netty Write Response Filter
、ReactiveLoadBalancerClientFilter
、RouteToRequestUrl Filter
、Websocket Routing Filter
等。
3.3 GlobalFilter和GatewayFilter的区别
FilteringWebHandler
在处理请求时,会将GlobalFilter
装饰为GatewayFilter
,然后放到同一个过滤器链中,排序以后依次执行。
Spring Cloud Gateway
根据作用范围划分为 GatewayFilter
和 GlobalFilter
,二者区别如下:
GatewayFilter
:网关过滤器,需要通过 spring.cloud.routes.filters
配置在具体路由下,只作用在当前路由上或通过 spring.cloud.default-filters
配置在全局,作用在所有路由上。
GlobalFilter
:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter
包装成 GatewayFilterChain
可识别的过滤器,它为请求业务以及路由的 URI 转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
四、自定义过滤器
无论是GatewayFilter
还是GlobalFilter
都支持自定义,只不过编码方式、使用方式略有差别。
4.1 自定义GatewayFilter
自定义GatewayFilter
不是直接实现GatewayFilter
,而是实现AbstractGatewayFilterFactory
。最简单的方式是这样的:
@Component
public class PrintLogGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {@Overridepublic GatewayFilter apply(Object config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取请求ServerHttpRequest request = exchange.getRequest();// 编写过滤器逻辑System.out.println("PrintLog executed.");// 放行return chain.filter(exchange);}};}
}
注意:该类的名称一定要以GatewayFilterFactory
为后缀哈。
然后在yaml
配置中这样使用:
spring:cloud:gateway:default-filters:- PrintLog # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器
另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:
@Component
public class PrintLogGatewayFilterFactory // 父类泛型是内部类的Config类型extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> {@Overridepublic GatewayFilter apply(Config config) {// OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:// - GatewayFilter:过滤器// - int order值:值越小,过滤器执行优先级越高return new OrderedGatewayFilter(new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取config值String a = config.getA();String b = config.getB();String c = config.getC();// 编写过滤器逻辑System.out.println("a = " + a);System.out.println("b = " + b);System.out.println("c = " + c);// 放行return chain.filter(exchange);}}, 100);}// 自定义配置属性,成员变量名称很重要,下面会用到@Datastatic class Config{private String a;private String b;private String c;}// 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取@Overridepublic List<String> shortcutFieldOrder() {return List.of("a", "b", "c");}// 返回当前配置类的类型,也就是内部的Config@Overridepublic Class<Config> getConfigClass() {return Config.class;}}
然后在yaml
文件中使用:
spring:cloud:gateway:default-filters:- PrintAny=1,2,3 # 注意,这里多个参数以","隔开,将来会按照shortcutFieldOrder()方法返回的参数顺序依次复制
上面这种配置方式参数必须严格按照shortcutFieldOrder()
方法的返回参数名顺序来赋值。
还有一种用法,无需按照这个顺序,就是手动指定参数名:
spring:cloud:gateway:default-filters:- name: PrintAnyargs: # 手动指定参数名,无需按照参数顺序a: 1b: 2c: 3
4.2 自定义GlobalFilter
自定义GlobalFilter
则简单很多,直接实现GlobalFilter
即可,而且也无法设置动态参数:
@Component
public class PrintLogGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 编写过滤器逻辑System.out.println("未登录,无法访问");// 放行// return chain.filter(exchange);// 拦截ServerHttpResponse response = exchange.getResponse();response.setRawStatusCode(401);//设置401无法访问return response.setComplete();}@Overridepublic int getOrder() {// 过滤器执行顺序,值越小,优先级越高return 0;}
}
五、SpringCloud Gateway 限流
Gateway
是基于令牌桶算法,使用redis
作为“桶”结合过滤器实现了网关限流。
在pom.xml
文件中增加依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
5.1 IP限流
为了简便一点,我们就不单独创建一个Config
的java
类了,直接在启动类中创建一个ipKeyResolver
,并指定@Bean(name = "ipKeyResolver")
。
package cc.huerpu.eurekaclient;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Objects;@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {public static void main(String[] args) {SpringApplication.run(HepGatewayEntranceApplication.class, args);}@Bean(name = "ipKeyResolver")public KeyResolver ipKeyResolver() {return new KeyResolver() {@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {String hostName = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName();System.out.println("hostName:" + hostName);return Mono.just(hostName);}};}}
使用 RequestRateLimiter
过滤器可以实现限流功能。首先需要在配置文件中配置限流规则。在application.yml
文件中指定过滤器为RequestRateLimiter
,key-resolver
用于限流的键的解析器的Bean
对象的名字。它使用 SpEL
表达式根据#{@ipKeyResolver}
从 Spring
容器中获取Bean
对象,redis-rate-limiter.replenishRate
指定令牌桶每s的填充速度,redis-rate-limiter.burstCapacity
指定令牌桶容量,redis-rate-limiter.requestedTokens
指定每个请求消耗多少个令牌,当然还要配置好redis
相关信息。
server:port: 8005 # 端口号spring:main:web-application-type: reactivecloud:redis:host: 127.0.0.1port: 6379password: database: 0gateway:filter:request-rate-limiter:deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问discovery:locator:enabled: true #启用基于服务发现的路由routes:- id: hep-api-userServiceuri: lb://EUREKACLIENTpredicates:- Path=/**filters:- name: RequestRateLimiterargs:key-resolver: '#{@ipKeyResolver}'redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度redis-rate-limiter.burstCapacity: 2 #令牌桶容量redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌- PrefixPath=/userapplication:name: hepGatewayEntrance # Gateway名称
当限流的时候会返回429 Too Many Request
,而正当访问会返回正确的结果数据。
我们使用Postman
进行了100次的连续请求,可以看到有成功的,也有429 Too Many Request
的,这个限流的表象就跃然纸上了。当我们去Redis
服务器查看的时候,也可以看到配置的db0
数据库中有限流的相关数据信息。
5.2 用户限流
根据用户来做限流需要获取当前请求用户的userId,我们在启动类中创建一个userIdResolver
,并指定@Bean(name = "userIdResolver")
。
package cc.huerpu.eurekaclient;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Objects;@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {public static void main(String[] args) {SpringApplication.run(HepGatewayEntranceApplication.class, args);}@Bean(name = "userIdResolver")public KeyResolver userKeyResolver() {return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("userId")));}}
在application.yml
文件中指定key-resolver: '#{@userIdResolver}'
。
server:port: 8005 # 端口号spring:main:web-application-type: reactivecloud:redis:host: 127.0.0.1port: 6379password: database: 0gateway:filter:request-rate-limiter:deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问discovery:locator:enabled: true #启用基于服务发现的路由routes:- id: hep-api-userServiceuri: lb://EUREKACLIENTpredicates:- Path=/**filters:- name: RequestRateLimiterargs:key-resolver: '#{@userIdResolver}'redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度redis-rate-limiter.burstCapacity: 2 #令牌桶容量redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌- PrefixPath=/userapplication:name: hepGatewayEntrance # Gateway名称
我们在请求参数中增加userId参数并请求http://localhost:8005/getUserById?userId=1111
,可以看到当限流的时候会返回429 Too Many Request
,而正当访问会返回正确的结果数据。
5.3 接口限流
接口限流获取请求地址的uri
作为限流的key
,我们指定一个名为@Bean(name = "apiKeyResolver")
的Bean
。
package cc.huerpu.eurekaclient;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Objects;@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {public static void main(String[] args) {SpringApplication.run(HepGatewayEntranceApplication.class, args);}@Bean(name = "apiKeyResolver")public KeyResolver apiKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getPath().value());}}
在application.yml
文件中指定key-resolver: '#{@apiKeyResolver}'
。
server:port: 8005 # 端口号spring:main:web-application-type: reactivecloud:redis:host: 127.0.0.1port: 6379password: database: 0gateway:filter:request-rate-limiter:deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问discovery:locator:enabled: true #启用基于服务发现的路由routes:- id: hep-api-userServiceuri: lb://EUREKACLIENTpredicates:- Path=/**filters:- name: RequestRateLimiterargs:key-resolver: '#{@apiKeyResolver}'redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度redis-rate-limiter.burstCapacity: 2 #令牌桶容量redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌- PrefixPath=/userapplication:name: hepGatewayEntrance # Gateway名称
很简单的,这里就不截图了哈。
Reference:
代码共享地址:https://github.com/jinglisen/SpringCloud-Kilburn-2022/tree/master
Spring Cloud Gateway(Kilburn 2022.0.2版本)官方文档:https://docs.spring.io/spring-cloud-gateway/docs/4.0.9/reference/html/
Spring Cloud Gateway官方文档:https://cloud.spring.io/spring-cloud-gateway/reference/html/Spring Cloud Gateway中文文档:https://springdoc.cn/spring-cloud-gateway/
SpringCloud-Gateway搭建保姆级教程:https://www.cnblogs.com/sun-10387834/p/17719582.html
SpringCloud Gateway史上最全:https://www.cnblogs.com/crazymakercircle/p/11704077.html
深入探索Spring Cloud Gateway:微服务网关的最佳实践:https://blog.csdn.net/zhengzhaoyang122/article/details/142744233
Spring Cloud Gateway API网关组件,非常详细:https://c.biancheng.net/springcloud/gateway.html
spring cloud gateway 之限流篇:https://www.cnblogs.com/chengmr/p/13277824.html
spring cloud gateway网关使用JMeter进行限流测试与熔断:https://cloud.tencent.com/developer/article/2344888
ring Cloud Gateway官方文档:https://cloud.spring.io/spring-cloud-gateway/reference/html/Spring Cloud Gateway中文文档:https://springdoc.cn/spring-cloud-gateway/
SpringCloud-Gateway搭建保姆级教程:https://www.cnblogs.com/sun-10387834/p/17719582.html
SpringCloud Gateway史上最全:https://www.cnblogs.com/crazymakercircle/p/11704077.html
深入探索Spring Cloud Gateway:微服务网关的最佳实践:https://blog.csdn.net/zhengzhaoyang122/article/details/142744233
Spring Cloud Gateway API网关组件,非常详细:https://c.biancheng.net/springcloud/gateway.html
spring cloud gateway 之限流篇:https://www.cnblogs.com/chengmr/p/13277824.html
spring cloud gateway网关使用JMeter进行限流测试与熔断:https://cloud.tencent.com/developer/article/2344888
深入学习spring cloud gateway 限流熔断:https://zhuanlan.zhihu.com/p/520347258
相关文章:
Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)
Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway) 一、服务网关 1.1 什么是网关 在微服务架构中,服务网关是一个至关重要的组件。它作为系统的入口,负责接收客户端的请求,并将这些请求路由到相应的后端服务…...
40分钟学 Go 语言高并发:Go程序性能优化方法论
Go程序性能优化方法论 一、性能指标概述 指标类型关键指标重要程度优化目标CPU相关CPU使用率、线程数、上下文切换⭐⭐⭐⭐⭐降低CPU使用率,减少上下文切换内存相关内存使用量、GC频率、对象分配⭐⭐⭐⭐⭐减少内存分配,优化GC延迟指标响应时间、处理延…...
一文解析Kettle开源ETL工具!
ETL(Extract, Transform, Load)工具是用于数据抽取、转换和加载的软件工具,用于支持数据仓库和数据集成过程。Kettle作为传统的ETL工具备受用户推崇。本文就来详细说下Kettle。 一、Kettle是什么? Kettle 是一款开源的 ETL&#x…...
Tomcat新手成长之路:安装部署优化全解析(上)
文章目录 1.Tomcat简介2.Tomcat原理架构2.1.总体架构2.2.连接器2.2.1.具体功能2.2.2.IO模型2.2.3.逻辑处理流程2.2.4.内部处理流程 2.3.容器2.4.启动过程2.5.请求过程 3.Tomcat适用场景4.Tomcat与其他Web容器对比5.Tomcat安装和启动5.1.Java环境变量5.2.系统服务5.3.启动关闭 6…...
跟我学C++中级篇——通信的数据的传递形式
一、通信的数据传递 在开发程序中,无可避免的会进行数据的传递。这种传递方式有很多种,字节流、消息、Json、参数以及对象甚至可能的方法。那么在传递这些数据时,如何正确的采用更合适的方法,就成为了一个设计的首选的问题。 二…...
C语言 qsort及应用
qsort及应用 qsort:快速排序函数,需要引用stdlib.h文件. void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *, const void *) ); 参数: base:需要排序的数组 num:数据个数(数组长度) width:每个数据的字节数(sizeof(数据类型)) compa…...
【C语言】连接陷阱探秘(4):检查外部类型
目录 一、外部类型概述 1.1. 外部类型的重要性 1.2. 外部类型在C语言中的使用 1.3. 注意事项 二、常见的外部类型陷阱 2.1. 结构体和联合体的大小不匹配 2.1.1. 示例代码 2.1.2. 正确的做法 2.2. 枚举类型的值不匹配 2.3. 函数签名不一致 2.3.1. 函数签名不一致的问…...
打造双层环形图:基础与高级渐变效果的应用
在数据可视化领域,环形图因其独特的展示方式而广受欢迎。今天,我们将通过ECharts库来创建一个具有双层渐变效果的高级环形图。本文将详细介绍如何实现这种视觉效果。 1. 环形图基础 首先,我们需要了解环形图的基本构成。环形图由内外两个圆…...
【Git】Git 完全指南:从入门到精通
Git 完全指南:从入门到精通 Git 是现代软件开发中最重要的版本控制工具之一,它帮助开发者高效地管理项目,支持分布式协作和版本控制。无论是个人项目还是团队开发,Git 都能提供强大的功能来跟踪、管理代码变更,并保障…...
【mac】mac自动定时开关机和其他常用命令,管理电源设置的工具pmset
一、操作步骤 1、打开终端 2、pmset 是用于管理电源设置的强大工具,我们将使用这个命令 (1)查询当前任务 pmset -g sched查看到我当前的设置是 唤醒电源开启在 工作日的每天早上8点半 上班时不用手动开机了 (2)删…...
【Leecode】Leecode刷题之路第62天之不同路径
题目出处 62-不同路径-题目出处 题目描述 个人解法 思路: todo代码示例:(Java) todo复杂度分析 todo官方解法 62-不同路径-官方解法 方法1:动态规划 思路: 代码示例:(Java&…...
基于深度学习的手势识别算法
基于深度学习的手势识别算法 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文基于论文 [Simple Baselines for Human Pose Estimation and Tracking[1]](ECCV 2018 Open Access Repository (thecvf.com)) 实现手部姿态估计。 手部姿态估计是从图像或视频帧集中找到手…...
helm部署golang服务
Helm 是 Kubernetes 的一个包管理工具,类似于 Linux 中的 apt 或 yum。它使得在 Kubernetes 上部署和管理应用程序变得更加简单和高效。 安装 https://get.helm.sh/helm-v3.16.3-linux-amd64.tar.gz具体版本号可以在github上看到最新的版本号,然后替换上面链接来获取。gith…...
DreamCamera2相机预览变形的处理
最近遇到一个问题,相机更换了摄像头后,发现人像角度顺时针旋转了90度,待人像角度正常后,发现 预览时图像有挤压变形,最终解决。在此记录 一人像角度的修改 先放示意图 设备预览人像角度如图1所示,顺时针旋…...
Mysql误删表中数据与误删表的恢复方法
查看数据库是否开启binlog日志 mysql> show variables like %log_bin%; ------------------------------------------------------------------------ | Variable_name | Value | ------------------------------------…...
lapack、blas、solver库的区别和联系
LAPACK、BLAS、Solver 库 是数值计算领域的重要组成部分,它们各自的功能和设计目标有所不同,但也存在密切的联系。 1. 概述 库主要功能设计目标BLAS提供基础的线性代数操作,如向量运算、矩阵-向量乘法、矩阵-矩阵乘法等。提供高度优化的基础线性代数操作,作为更高级库的底层…...
deepin 安装 chrome 浏览器
deepin 安装 chrome 浏览器 最近好多小伙伴儿和我说 deepin 无法安装最新的谷歌浏览器 其实是因为最新的 谷歌浏览器 其中的一个依赖需要提前安装 提前安装依赖然后再安装谷歌浏览器就可以了 安装 fonts-liberationsudo apt -y install fonts-liberation安装 chrome 浏览器sudo…...
永久免费的PDF万能水印删除工具
永久免费的PDF万能水印删除工具 1.简介 PDF万能水印删除工具,可以去除99.9%的PDF水印。例如:XObject水印(含图片水印)、文本水印、绘图水印/曲线水印、注释水印、工件水印、剪切路径水印等等。本软件是永久免费,无有…...
Linux网络——NAT/代理服务器
一.NAT技术 1.NAT IP转换 之前我们讨论了, IPv4 协议中, IP 地址数量不充足的问题,NAT 技术就是当前解决 IP 地址不够用的主要手段, 是路由器的一个重要功能。 NAT 能够将私有 IP 对外通信时转为全局 IP. 也就是一种将私有 IP 和全局IP 相互转化的技术方法: 很…...
大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO,VOC,COCO格式标注,4070张图片的数据集
大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO,VOC,COCO格式标注,4070张图片的数据集 数据集分割 4070总图像数 训练组 87% 3551图片 有效集 9% 362图片 测试集 4% 157图片 预处理 自动定向…...
基于Java的小程序电商商城开源设计源码
近年来电商模式的发展越来越成熟,基于 Java 开发的小程序电商商城开源源码,为众多开发者和企业提供了构建个性化电商平台的有力工具。 基于Java的电子商城购物平台小程序的设计在手机上运行,可以实现管理员;首页、个人中心、用户…...
node.js基础学习-fs模块-文件操作(六)
一、前言 fs模块是 Node.js 内置的文件系统(File System)模块,它提供了一系列用于与文件系统进行交互的方法。通过fs模块,可以对文件或目录进行读取、写入、删除、重命名、查询状态等操作,这使得 Node.js 能够很好地处…...
设计模式:11、迭代器模式(游标)
目录 0、定义 1、迭代器模式的四种角色 2、迭代器模式的UML类图 3、示例代码 4、迭代器的next()方法与集合的get(int index)方法的效率对比(LinkedList为例) 0、定义 提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象…...
Oracle SCN与时间戳的映射关系
目录 一、基本概述 二、相关操作 三、参考文档 一、基本概述 Oracle 数据库中的 SYS.SMON_SCN_TIME 表是一个关键的内部表,主要用于记录过去时间段中SCN与具体的时间戳之间的映射关系。这种映射关系可以帮助用户将 SCN 值转换为可读性更强的时间戳,从而…...
【广告投放系统】头条可视化投放平台vue3+element-plus+vite落地历程和心得体会
前言 hallo,又是许久未见,昨天也是正式把公司内部的广告投放平台暂时落地,我也即将离开待了两年多的地方。言归正传,由于头条广告后台的升级改版,因此为了满足内部投放需求,做了一个可视化的投放平台&…...
Gazebo插件相机传感器(可订阅/camera/image_raw话题)
在仿真环境中使用相机传感器,通常需要结合Gazebo插件来实现。Gazebo是一个功能强大的机器人仿真工具,支持多种传感器模型,包括相机。下面是如何在Gazebo中使用相机传感器的详细步骤。 1. 修改Xacro文件以包含Gazebo插件 首先,修…...
华三(HCL)和华为(eNSP)模拟器共存安装手册
接上章叙述,解决同一台PC上同时部署华三(HCL)和华为(eNSP)模拟器。原因就是华三HCL 的老版本如v2及以下使用VirtualBox v5版本,可以直接和eNSP兼容Oracle VirtualBox,而其他版本均使用Oracle VirtualBox v6以上的版本,…...
信息学奥赛一本通 1448:【例题1】电路维修 | 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修
【题目链接】 ybt 1448:【例题1】电路维修 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修 【题目考点】 1. 双端队列广搜(0-1BFS) 【解题思路】 整个电路是由一个个的正方形的电路元件组成,每个正方形有四个…...
k8s删除网络组件错误
k8s集群删除calico网络组件重新部署flannel网络组件,再部署pod后出现报错不能分配ip地址 plugin type"calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized 出现该问题是因为删除网络组件后,网…...
MySQL之JDBC
我们在学习完了数据库的基本操作后,希望和我们的Java程序建立连接,那么我们今天就来一探究竟JDBC是如何让Java程序与数据库建立连接的 1. 什么是JDBC JDBC(Java Data Base Connectivity, Java数据库连接) 是Java程序和数据库之间…...
厦门营销型网站建设公司/东莞疫情最新消息今天新增病例
在实际的项目开发中会有非常多的对象,怎样高效、方便地管理对象,成为影响程序性能与可维护性的重要环节。Java 提供了集合框架来解决此类问题。线性表、链表、哈希表等是经常使用的数据结构,在进行 Java 开发时,JDK 已经为我们提供…...
无锡新吴区住房和建设交通局网站/电脑系统优化软件哪个好用
首先我们尝试构造一个乱码 第1步 我们可以在首页编写一个提交的表单,在web目录下创建form.jsp <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head><title>Title</title> </head…...
没有备案的网站怎么访问不了/职业培训学校
2019独角兽企业重金招聘Python工程师标准>>> 1、假如当前mysql密码为 nihao123! 写脚本检测mysql服务是否正常(比如 可以进入mysql 里 执行 show processlist),并检测当前mysql是主还是从,如果是从,则判断 它 的主是否正常,如果是主,则什么也不做&#…...
机械厂做网站到底有没有效果/磁力搜索器 磁力猫在线
在设置中搜索python.linting.pylintPath如下 如果使用的是anaconda,在anaconda文件夹中寻找pylint应用程序的安装位置,例如:E:\anaconda\new\pkgs\pylint-2.2.2-py37_0\Scripts 如果没有安装anaconda,先检查是否安装了pylint&am…...
互联网网站运营推广/seo赚钱方式
通常,我们并不直接使用数据库,而是根据用户输入,准备好SQL语句,然后将SQL语句发送给SQL Server执行。在这个过程中,总会发生一些我们“预料不到”,或者“即使预料到也无法处理”的问题。比如:SQ…...
整站wordpress下载/海洋网络推广效果
PXE(Preboot eXecution Environment)技术可以实现无盘工作站的网络启动。结合xCAT,可以实现大规模的无盘工作站自动化部署。本文主要介绍如何使用PXExCAT自动化部署oVirt Node系统。 xCAT通过TFTP,DHCP,FTP等服务,实现PXE无盘工作站的网络启动和自动化安装。xCAT管理节点上需要…...