

限流10万QPS、跨域、过滤器、令牌桶算法-网关Gateway内容都在这儿
source link: https://mp.weixin.qq.com/s?__biz=MzU1MzE4OTU0OQ%3D%3D&%3Bmid=2247487943&%3Bidx=1&%3Bsn=2b613440442fbdc61a19aafcef42b1cf
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、微服务网关Spring Cloud Gateway
1.1 导引
文中内容包含:微服务网关限流10万QPS、跨域、过滤器、令牌桶算法。
在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuul,到现在的Spring Cloud Gateway,网关我们用的不可少。
今天我就将沉淀下来的所有与网关相关的知识,用一篇文章总结清楚,希望对爱学习的小伙伴们有所帮助。
本篇文章主要介绍网关跨域配置,网关过滤器编写,网关的令牌桶算法限流【每秒10万QPS】
首先我们来看什么是网关
1.2 什么是微服务网关Gateway?
This project provides a library for building an API Gateway on top of Spring WebFlux.
gateway官网:
https://spring.io/projects/spring-cloud-gateway
实现微服务网关的技术有很多,
nginx Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务
zuul ,Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器。
spring-cloud-gateway, 是spring 出品的 基于spring 的网关项目,集成断路器,路径重写,性能比Zuul好。
我们使用gateway这个网关技术,无缝衔接到基于spring cloud的微服务开发中来。
1.3 微服务为什么要使用网关呢?
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
客户端会多次请求不同的微服务,增加了客户端的复杂性
存在跨域请求,在一定场景下处理相对复杂
认证复杂,每个服务都需要独立认证
难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难
以上这些问题可以借助网关解决。
网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:
1.4 微服务网关优点
安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
减少了客户端与各个微服务之间的交互次数
易于统一授权。
1.5 总结
微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。历史文章:200期阶段汇总
二、微服务网关搭建及配置
2.1 微服务网关微服务搭建
由于我们开发的系统 有包括前台系统和后台系统,后台的系统给管理员使用。那么也需要调用各种微服务,所以我们针对管理后台搭建一个网关微服务。分析如下:
搭建步骤:
(1)依赖坐标pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
(2)启动引导类:GatewayApplication
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
(3)在resources下创建application.yml
spring:
application:
name: apigateway
cloud:
gateway:
routes:
- id: open
uri: lb://open
predicates:
- Path=/open/**
filters:
- StripPrefix= 1
- id: system
uri: lb://system
predicates:
- Path=/system/**
filters:
- StripPrefix= 1
server:
port: 9999
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true
参考官方手册:
https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html#_stripprefix_gatewayfilter_factory
2.2 微服务网关跨域
在启动类GatewayApplication中,加入跨域配置代码如下
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");//支持所有方法
config.addAllowedOrigin("*");//跨域处理 允许所有的域
config.addAllowedHeader("*");//支持所有请求头
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);//匹配所有请求
return new CorsWebFilter(source);
}
三、微服务网关过滤器
我们可以通过网关过滤器,实现一些逻辑的处理,比如ip黑白名单拦截、特定地址的拦截等。下面的代码中做了两个过滤器,并且设定的先后顺序。
(1)在网关微服务中创建IpFilter,无需配置其他,注册到Spring容器即可生效
@Component
public class IpFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
InetSocketAddress remoteAddress = request.getRemoteAddress();
//TODO 设置ip白名单
System.out.println("ip:"+remoteAddress.getHostName());
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
(2)在网关微服务中创建UrlFilter,无需配置其他,注册到Spring容器即可生效
@Component
public class UrlFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String url = request.getURI().getPath();
//TODO 拦截特定URL地址
System.out.println("url:"+url);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
四、网关限流每秒10万请求
我们之前说过,网关可以做很多的事情,比如,限流,当我们的系统 被频繁的请求的时候,就有可能 将系统压垮,所以 为了解决这个问题,需要在每一个微服务中做限流操作,但是如果有了网关,那么就可以在网关系统做限流,因为所有的请求都需要先通过网关系统才能路由到微服务中。
4.1 限流实现思路分析
看图就完了,非常简单!
4.2 令牌桶算法 介绍
令牌桶算法是比较常见的限流算法之一,大概描述如下:
1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流
这个算法的实现,有很多技术,Guava(读音: 瓜哇)是其中之一,redis客户端也有其实现。历史文章:200期阶段汇总
4.3 网关限流代码实现
需求:每个ip地址1秒内只能发送10万请求,多出来的请求返回429错误。
代码实现:
(1)spring cloud gateway 默认使用redis的RateLimter限流算法来实现。所以我们要使用首先需要引入redis的依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
(2)定义KeyResolver
在GatewayApplicatioin引导类中添加如下代码,KeyResolver用于计算某一个类型的限流的KEY也就是说,可以通过KeyResolver来指定限流的Key。
//定义一个KeyResolver
@Bean
public KeyResolver ipKeyResolver() {
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
};
}
(3)修改application.yml中配置项,指定限制流量的配置以及REDIS的配置,修改后最终配置如下:
spring:
application:
name: apigateway
cloud:
gateway:
routes:
- id: open
uri: lb://open
predicates:
- Path=/open/**
filters:
- StripPrefix= 1
- name: RequestRateLimiter #请求数限流 名字不能随便写
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 1
- id: system
uri: lb://system
predicates:
- Path=/system/**
filters:
- StripPrefix= 1
# 配置Redis 127.0.0.1可以省略配置
redis:
host: 101.57.2.128
port: 6379
server:
port: 9999
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:100/eureka
instance:
prefer-ip-address: true
burstCapacity:令牌桶总容量。
replenishRate:令牌桶每秒填充平均速率。
key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
通过在replenishRate
和中设置相同的值来实现稳定的速率burstCapacity
。设置burstCapacity
高于时,可以允许临时突发replenishRate
。在这种情况下,需要在突发之间允许速率限制器一段时间(根据replenishRate
),因为2次连续突发将导致请求被丢弃(HTTP 429 - Too Many Requests
)
key-resolver: "#{@userKeyResolver}" 用于通过SPEL表达式来指定使用哪一个KeyResolver.
如上配置:
表示 一秒内,允许 一个请求通过,令牌桶的填充速率也是一秒钟添加一个令牌。
最大突发状况 也只允许 一秒内有一次请求,可以根据业务来调整 。
(4)测试时需要注意服务启动顺序,这里需要依赖于Redis,所以首先要启动redis
启动redis
启动注册中心
启动商品微服务
启动gateway网关
打开浏览器 http://localhost:9999/open
快速刷新,当1秒内发送超过10万次请求,就会返回429错误。
那么问题来了:怎么发送10万次请求呢? 知道的同学,请在留言区评论。
Recommend
-
22
限流又称为流量控制(流控),通常是指限制到达系统的并发请求数,本文列举了常见的限流策略,并以gin框架为例演示了如何为项目添加限流组件。 限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数。...
-
35
限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数。 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为 8 万人;沙河地铁站早高峰通过站外排队逐一放行的...
-
7
常用限流策略——漏桶与令牌桶介绍 2020年9月13日 |
-
11
为Spring Cloud Gateway加上全局过滤器,并使用其内部自带的令牌桶算法实现(Redis)来进行限流既然是一个网关。那么全局过滤器肯定是少不了的一个存在。像是鉴权、认证啥的不可能每个服务都做一次,一般都是在网关处就搞定了。Zuul他就有很强大...
-
17
分布式系统为了保证系统稳定性,在服务治理的限流中会根据不同场景进行限流操作,常见的限流算法有: 令牌桶:可容...
-
9
Go可用性(二) 限流1: 令牌桶原理及使用Go可用性(二) 限流1: 令牌桶原理及使用 2021年3月29日 凌晨 2.4k 字 33 分钟本系列为 Go 进阶训练营 笔记,预计 2021Q2 完成更新,访问
-
17
ASP.NET Core中使用令牌桶限流 在限流时...
-
5
限流算法之漏桶与令牌桶 发表于 2021-05-30 ...
-
2
Go 分布式令牌桶限流 + 兜底策略 上篇文章提到固定时间窗口限流无法处理突然请求洪峰情况,本文讲述的令牌桶线路算法则可以比较好的处理此场景。 单位时间按照一定速率匀速的生产 token 放入桶内,直到达到桶容量上限。 ...
-
2
golang.org/x/time/rate 提供了一个使用令牌桶 Token Bucket 算法实现的限流器。 创建限流器 func NewLimiter(r Limit, b int) *Limiter r - 每秒令牌桶中...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK