文章目录
- 一. 概念
- 二. 常见网关对比
- 三. 流量网关与业务网关
- 四. 作用
- 路由转发- - 1. 模拟发送Http请求- 2. 实现过程- 2. 负载均衡- 3. 统一处理跨域- - 3.1 跨域的概念- 3.2 跨域带来的问题- 3.3 解决方案-配置式- 4. 接口保护- - 4.1 限制请求- 4.2 信息脱敏- 4.3 降级(熔断)- - 1. 概念- 2. 实现方式-配置式- - 2.1 引入依赖- 2.2 熔断配置- 2.3 返回友好提示- 4.4 限流- - 1. 概念- 2. 常见限流算法- - 2.1 漏桶算法- - 2.1.1 概念- 2.1.2 核心思想- 2.1.3 不足- 2.1.4 算法描述- 2.2 令牌桶算法- - 2.2.1 概念- 2.2.2 核心思想- 2.2.3 算法描述- 2.3 令牌桶和漏桶对比- 3. 基于Redis的限流方案- - 3.1 实现思路- 3.2 操作步骤- - 1. 引入依赖- 2. 配置KeyResolver-指定限流的 Key- 3. 配置限流的过滤器信息- 4. 测试结果- 5. Redis存储内容- 4.5 超时时间-连接超时和响应超时- - 1. 概念- 2. 实现方式-配置式- - 2.1 全局配置-为所有路由设置统一的超时标准- 2.2 路由配置-为特定的路由设置不同的超时参数,以满足不同服务的特定需求- 4.6 重试(业务保护)- - 1. 概念- 2. 实现方式-配置式- 4.7 访问控制- - 1. 概念- 2. 实现方式- 2. 安全认证-自定义全局过滤器 实现GlobalFilter接口
一. 概念
API网关:指系统的统一入口,对内部系统进行封装,所有请求都先经过网关,由网关将请求路由到合适的微服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、日志、路由转发等。
二. 常见网关对比
三. 流量网关与业务网关
流量网关业务网关代表NginxSpring Cloud Gateway定位主要是作为一个高性能的Web服务器和反向代理服务器,侧重于静态内容的高速分发、负载均衡、SSL终止为微服务架构设计,是API管理平台的一部分,提供更高级的API管理功能功能提供HTTP服务器功能,反向代理,负载均衡,简单的访问控制和静态内容缓存等。除了负载均衡、路由分发之外,还支持API聚合、协议转换、认证鉴权、限流熔断、监控日志等功能,特别适合微服务架构的复杂需求。配置配置基于文本的配置文件,灵活性和控制力强,但配置复杂度相对较高支持基于YAML或Java配置适用场景适用于需要高性能Web服务器、简单API路由、负载均衡的场景微服务架构中,特别是需要复杂API管理、安全控制、监控和动态路由的场景。总结Nginx作为前端的负载均衡器Gateway对后端服务进行更细粒度的API管理。
四. 作用
1. 路由转发
客户端或者sdk发送的http请求都是指向网关,再转发到实际的API接口。
1. 模拟发送Http请求
/**
* 获取随机文本
* @return
*/// 向网关服务发送请求publicStringgetRandomWork(){returnHttpRequest.get("http://localhost:8090/api/interface/random/word").addHeaders(getHeadMap("",accessKey,secretKey)).execute().body();}
2. 实现过程
- 微服务启动,将自己注册到Nacos,Nacos记录了各微服务实例的地址.
- 网关从Nacos读取服务列表,包括服务名称、服务地址等.
- 请求到达网关,网关将请求路由到具体的微服务.
- 通过网关配置文件中制定的路由规则
spring:application:name: api-gateway
cloud:nacos:discovery:server-addr: 127.0.0.1:8848# 网关路由配置gateway:routes:# 路由id,自定义,唯一即可。-id: api_backend
# 多种方式配置目标地址# uri: http:// 127.0.0.1:9001 http方式:固定地址uri: lb://api-backend #lb就是负载均衡,后面跟服务名称predicates:#路由断言,判断请求是否符合路由规则的条件- Path=/api/**# 以/api开头的请求就会被转发到api-backend服务
2. 负载均衡
在路由的基础上,将请求转发到集群A的某一台机器上,再调用机器上对应的接口
uri: lb://api-backend #lb就是负载均衡
3. 统一处理跨域
3.1 跨域的概念
如果一个请求的协议、主机或端口任意一个与当前页面的源(即协议、主机和端口)不同,则该请求就被认为是跨域请求。
3.2 跨域带来的问题
- AJAX请求被拒绝:浏览器会阻止在跨域请求中使用XMLHttpRequest对象进行通信。
- Cookie不可用:跨域请求默认不会发送源站的Cookie信息,导致无法验证用户身份。
- 访问被拒绝:跨域请求可能会受到服务器的访问控制策略阻止。
3.3 解决方案-配置式
spring:
cloud:
gateway:
globalcors:
corsConfigurations:'[/**]':
allowedOrigins:"*"
exposedHeaders:- content-type
allowedHeaders:- content-type
allowCredentials:true
allowedMethods:-GET-OPTIONS-PUT-DELETE-POST
4. 接口保护
4.1 限制请求
4.2 信息脱敏
4.3 降级(熔断)
1. 概念
熔断是一种防止故障扩散的策略。当一个服务出现故障或超时,熔断器会打开并快速失败,拒绝后续的请求,避免请求堆积和资源耗尽。熔断器会暂时屏蔽该服务,并在一段时间后尝试恢复。熔断器的状态变化可用于监控系统健康和提供告警信息。
2. 实现方式-配置式
2.1 引入依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
2.2 熔断配置
spring:cloud:gateway:routes:- id: your_route_id
uri: lb://your_service_id
filters:- name: Hystrix
args:name: fallback
fallbackUri: forward:/fallback # 当熔断发生时转发到的本地fallback处理逻辑
predicates:- Path=/api/** # 例如,匹配所有/api开头的路径
上面配置了一个 Hystrix 过滤器,该过滤器会使用 Hystrix 熔断与回退,原理是将请求包装成 RouteHystrixCommand 执行,RouteHystrixCommand 继承于 com.netflix.hystrix.HystrixObservableCommand。
fallbackUri 是发生熔断时回退的 URI 地址,目前只支持 forward 模式的 URI。如果服务被降级,该请求会被转发到该 URI 中。
2.3 返回友好提示
@RestController
publicclassFallbackController{
@GetMapping("/fallback")public String fallback(){thrownewRunTimeException("请稍后再试!");}}
4.4 限流
1. 概念
API 网关作为所有请求的入口,请求量大,我们可以通过对并发访问的请求进行限速来保护系统的可用性。
2. 常见限流算法
2.1 漏桶算法
2.1.1 概念
水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率
2.1.2 核心思想
可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。
2.1.3 不足
因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流量突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。
2.1.4 算法描述
1. 一个固定容量的漏桶,按照常量固定速率流出水滴;
2. 如果桶是空的,则不需流出水滴;
3. 可以以任意速率流入水滴到漏桶;
4. 如果流入水滴超出了桶的容量,则流入的水滴溢出了(被丢弃),而漏桶容量是不变的。
2.2 令牌桶算法
2.2.1 概念
系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token,如果桶已经满了就不再加了。新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务。
2.2.2 核心思想
令牌桶的核心是可以预先在令牌桶中存储一些Token,这样当流量激增的时候,可以并发处理这一批请求,而且一旦需要提高速率,则按需提高放入桶中的令牌的速率.
2.2.3 算法描述
- 假设限制2r/s,则按照500毫秒的固定速率往桶中添加令牌;
- 桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃或拒绝;
- 当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上;
- 如果桶中的令牌不足n个,则不会删除令牌,且该数据包将被限流(要么丢弃,要么缓冲区等待)。
2.3 令牌桶和漏桶对比
- 令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求;
- 漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝;
- 令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,支持一次拿3个令牌,4个令牌),并允许一定程度突发流量;
- 漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2),从而平滑突发流入速率;
- 令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率;
- 两个算法实现可以一样,但是方向是相反的,对于相同的参数得到的限流效果是一样的。
3. 基于Redis的限流方案
3.1 实现思路
spring cloud gateway默认基于redis令牌桶算法进行微服务的限流保护,采用RateLimter限流算法来实现。
3.2 操作步骤
1. 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId></dependency>
2. 配置KeyResolver-指定限流的 Key
importorg.springframework.cloud.gateway.filter.ratelimit.KeyResolver;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Primary;importreactor.core.publisher.Mono;/**
* 限流配置KeyResolver——有三种写法(接口限流/ip限流/用户限流)
*/@ConfigurationpublicclassRateLimiteConfig{/**
* 接口限流:根据请求路径限流
* 如果不使用@Primary注解,会报错
* @return
*/@Bean@PrimarypublicKeyResolverpathKeyResolver(){return exchange ->Mono.just(exchange.getRequest().getPath().toString());}/**
* 根据请求IP限流
* @return
*/@BeanpublicKeyResolveripKeyResolver(){return exchange ->Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}/**
* 根据请求参数中的userId进行限流
* 请求地址写法:http://localhost:8801/rate/123?userId=lisi
* @return
*/@BeanpublicKeyResolveruserKeyResolver(){return exchange ->Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));}}
3. 配置限流的过滤器信息
1. filter 名称必须是 RequestRateLimiter。
2. redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求。
3. redis-rate-limiter.burstCapacity:令牌桶的容量,允许在 1s 内完成的最大请求数。
4. key-resolver:使用 SpEL 按名称引用 bean。
spring:cloud:gateway:routes:-id: rate-limit-demo
uri: lb://mima-cloud-producer
predicates:#访问路径:http://localhost:8801/rate/123- Path=/rate/**filters:-name: RequestRateLimiter
args:# 令牌桶每秒填充平均速率, 允许用户每秒处理多少个请求。redis-rate-limiter.replenishRate:1# 令牌桶的容量,允许在1s内完成的最大请求数。redis-rate-limiter.burstCapacity:2# 使用SpEL表达式从Spring容器中获取Bean对象, 查看RateLimiteConfig实现类中的方法名key-resolver:"#{@pathKeyResolver}"#key-resolver: "#{@ipKeyResolver}"#key-resolver: "#{@userKeyResolver}"
4. 测试结果
多次调用请求,控制台打印结果
[开始]请求路径:/rate/123[应答]请求路径:/rate/123耗时:2ms
2024-09-0816:23:27.253DEBUG18512---[ioEventLoop-4-1] o.s.w.s.adapter.HttpWebHandlerAdapter :[62eb90e0] Completed 429TOO_MANY_REQUESTS2024-09-0816:23:27.394DEBUG18512---[ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter :[62eb90e0]HTTPGET"/rate/123"
corsFilter... run
[开始]请求路径:/rate/123[应答]请求路径:/rate/123耗时:2ms
2024-09-0816:23:27.397DEBUG18512---[ioEventLoop-4-1] o.s.w.s.adapter.HttpWebHandlerAdapter :[62eb90e0] Completed 429TOO_MANY_REQUESTS2024-09-0816:23:27.536DEBUG18512---[ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter :[62eb90e0]HTTPGET"/rate/123"
corsFilter... run
5. Redis存储内容
当发生限流时,会向redis中存储两个数据
127.0.0.1:6379> keys *1)"request_rate_limiter.{localhost}.timestamp"2)"request_rate_limiter.{localhost}.tokens"
大括号中就是我们的限流 Key,这里是 IP,本地的就是 localhost。
timestamp:存储的是当前时间的秒数,也就是 System.currentTimeMillis()/1000 或者 Instant.now().getEpochSecond()。
tokens:存储的是当前这秒钟对应的可用令牌数量。
4.5 超时时间-连接超时和响应超时
1. 概念
连接超时和响应超时是两种不同的超时机制,分别用于处理不同的网络通信问题。
连接超时(connect-timeout)
- 主要指的是在建立网络连接过程中所允许的最大等待时间。
- 如果在规定的时间内无法成功建立与服务端的连接,则认为连接超时。
- 在Spring Cloud Gateway中,连接超时用于确保在尝试与服务建立连接时,如果等待过长时间仍未成功,则放弃此次连接尝试,避免长时间占用资源。
响应超时(response-timeout)
- 是指在建立连接后,等待服务端响应的最大等待时间。
- 如果在规定的时间内服务端未返回响应,则认为响应超时。
- 这个设置用于确保在请求发送后,如果服务端在合理时间内未作出响应,网关能够及时释放资源,避免因等待过久而造成资源浪费或影响其他请求的处理。
2. 实现方式-配置式
2.1 全局配置-为所有路由设置统一的超时标准
spring:cloud:gateway:httpclient:connect-timeout:1000# 连接超时,单位是毫秒response-timeout: 5s # 响应超时,单位是秒
2.2 路由配置-为特定的路由设置不同的超时参数,以满足不同服务的特定需求
gateway:routes:# 路由id,自定义,唯一即可。-id: api_backend_route
# 多种方式配置目标地址# uri: http:// 127.0.0.1:9001 http方式:固定地址uri: lb://api-backend #lb就是负载均衡,后面跟服务名称predicates:#路由断言,判断请求是否符合路由规则的条件- Path=/api/**# 以/api开头的请求就会被转发到api-backend服务metadata:response-timeout:5000connect-timeout:2000
4.6 重试(业务保护)
1. 概念
当网关将请求转发到内部服务时,如果内部服务调用失败,我们可以尝试重新发送请求,从而保证系统的可靠性
2. 实现方式-配置式
filters:-name: Hystrix
args:name: fallback
fallbackUri: forward:/fallback # 当熔断发生时转发到的本地fallback处理逻辑-name: Retry # 配置重试过滤器args:retries:3# 重试次数,默认值是 3 次。series: SERVER_ERROR # 状态码配置(分段),符合某段状态码才会进行重试逻辑,默认值是 SERVER_ERROR,值是 5,也就是 5XX(5 开头的状态码)
4.7 访问控制
1. 概念
针对访问网关的请求进行限制;比如:特定IP才可以访问该请求-白名单;某个IP在短时间内发送大量请求,从而使得服务器资源耗尽,导致正常用户的合法请求失败-黑名单;
2. 实现方式
- 在网关的配置文件中添加请求的黑白名单.
request:white-list:- /api/v1/get/test
- api/v1/get/getUserInfo
black-list:- 127.0.0.1
- 通过配置类映射黑白名单信息到集合中
packagecom.monkey.gateway_template.config;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;importjava.util.List;/**
* 请求白名单.
*
*/@Component@ConfigurationProperties("request")publicclassRequestWhiteList{/**
* 白名单列表
*/List<String> whiteList;publicList<String>getWhiteList(){return whiteList;}publicvoidsetWhiteList(List<String> whiteList){this.whiteList = whiteList;}}
- 在自定义的全局过滤器中校验黑白名单,实现请求的放行与屏蔽
@Slf4j@ComponentpublicclassLoginGlobalFilterimplementsGlobalFilter,Ordered{@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){// 黑白名单InetSocketAddress localAddress = request.getLocalAddress();if(!"127.0.0.1".equals(localAddress.getHostString())){
response.setStatusCode(HttpStatus.FORBIDDEN);return response.setComplete();}}}
2. 安全认证-自定义全局过滤器 实现GlobalFilter接口
登录认证以及请求接口认证的方法在filter方法中实现
过滤器链
@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){// 登录认证以及请求接口认证的方法在filter方法中实现}
版权归原作者 三十六煩惱風 所有, 如有侵权,请联系我们删除。