Spring Cloud Gateway 原生支持接口限流该怎么玩

关于pig:

基于Spring Cloud、oAuth2.0开发基于Vue前后分离的开发平台,支持账号、短信、SSO等多种登录,提供配套视频开发教程。

码云地址:https://gitee.com/log4j/pig

关于 Spring Cloud Gateway

SpringCloudGateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring云网关旨在提供一种简单而有效的路由API的方法。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

zuul如何实现多维度限流请参考我的博客

Zuul:构建高可用网关之多维度限流

开始Gateway 限流

POM 依赖

<!--spring cloud gateway依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--基于 reactive stream 的redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

配置按照请求IP 的限流

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: lb://pigx-upms
        order: 10000
        predicates:
        - Path=/admin/**
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1  # 令牌桶的容积
            redis-rate-limiter.burstCapacity: 3  # 流速 每秒
            key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean
        - StripPrefix=1

配置bean,多维度限流量的入口

/**
* 自定义限流标志的key,多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息,用户信息等
*/
@Bean
KeyResolver remoteAddrKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

OK 完成。

压力测试

并发5个线程。

image

Redis 数据变化

我们使用redis的monitor 命令,实时查看redis 的操作情况。

会发现在redis中会操作两个key

  • request_rate_limiter.{xxx}.timestamp
  • request_rate_limiter.{xxx}.tokens
    image
    实现原理
    image

Spring Cloud Gateway 默认实现 Redis限流,如果扩展只需要实现ratelimter接口即可。

RedisRateLimter 的核心代码,判断是否取到令牌的实现,通过调用 redis的LUA 脚本。

public Mono<Response> isAllowed(String routeId, String id) {
	Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig);
	int replenishRate = routeConfig.getReplenishRate();
	int burstCapacity = routeConfig.getBurstCapacity();

	try {
		List<String> keys = getKeys(id);
		returns unixtime in seconds.
		List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",
				Instant.now().getEpochSecond() + "", "1");
		// 这里是核心,执行redis 的LUA 脚本。
		Flux<List<Long>> flux =
		this.redisTemplate.execute(this.script, keys, scriptArgs);
		return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))
				.reduce(new ArrayList<Long>(), (longs, l) -> {
					longs.addAll(l);
					return longs;
				}) .map(results -> {
					boolean allowed = results.get(0) == 1L;
					Long tokensLeft = results.get(1);

					Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft));

					if (log.isDebugEnabled()) {
						log.debug("response: " + response);
					}
					return response;
				});
	}
	catch (Exception e) {
		log.error("Error determining if user allowed from redis", e);
	}
	return Mono.just(new Response(true, getHeaders(routeConfig, -1L)));
}

LUA 脚本

image

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏西枫里博客

ASP防止站外提交表单数据

防止站外提交数据函数,搭配使用验证码可以杜绝大多数的灌水机程序的自动发布。更严格的还应该从字段格式限制等全方面考虑。

311
来自专栏伪君子的梦呓

网络安全实验室(基础关) writeup~上

因为参加了一个比赛(网鼎杯),所以要快速入门一下信息安全,没想到赛制是线上采用 CTF 的赛制,所以就找了点题目做了一下。

1211
来自专栏Kirito的技术分享

JAVA拾遗--关于SPI机制

JDK提供的SPI(Service Provider Interface)机制,可能很多人不太熟悉,因为这个机制是针对厂商或者插件的,也可以在一些框架的扩展中看...

30311
来自专栏blackpiglet

Ceph 磁盘损坏现象和解决方法

对于存储系统,磁盘是消耗品,损坏是很常见的,所以这篇文章记录一下 Ceph 中出现磁盘损坏时的现象,以及如何定位和更换损坏的磁盘。

712
来自专栏一个会写诗的程序员的博客

《Springboot极简教程》使用Spring Boot, JPA, Mysql, ThymeLeaf,gradle, Kotlin快速构建一个CRUD Web App

使用Spring Boot, JPA, Mysql, ThymeLeaf,gradle, Kotlin快速构建一个CRUD Web App

732
来自专栏惨绿少年

分布式文件系统---GlusterFS

1.1 分布式文件系统 1.1.1 什么是分布式文件系统   相对于本机端的文件系统而言,分布式文件系统(英语:Distributed file system,...

3497
来自专栏程序猿DD

使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控

由于最近在做监控方面的工作,因此也读了不少相关的经验分享。其中有这样一篇文章总结了一些基于Spring Boot的监控方案,因此翻译了一下,希望可以对大家有所帮...

33010
来自专栏坚毅的PHP

PHP码农在Golang压力下的生存之道-PHP性能优化实践

随着国内Golang的火爆,phper的生存压力越来越大,在一次内部技术讨论中,gopher甚至提出,要什么php,写php的全部开掉,唉,码农何苦为难码农。 ...

7708
来自专栏逸鹏说道

Python3 与 C# 并发编程之~ 上篇

其实逆天现在Coding已经是80%变成Python了,20%才是Net,也不确定是否一直在Net界干下去,所以只能尽可能的在说新知识的同时,尽量把脑子里面Ne...

1004
来自专栏haifeiWu与他朋友们的专栏

阿里 RPC 框架 DUBBO 初体验

最近研究了一下阿里开源的分布式RPC框架dubbo,楼主写了一个 demo,体验了一下dubbo的功能。

892

扫码关注云+社区