Spring Cloud 微服务五:Spring cloud gateway限流
前言:在互联网应用中,特别是电商,高并发的场景非常多,比如:秒杀、抢购、双11等,在开始时间点会使流量爆发式地涌入,如果对网络流量不加控制很有可能造成后台实例资源耗尽。限流是指通过指定的策略削减流量,使到达后台实例的请求在合理范围内。本章将介绍spring cloud gateway如何实现限流。
前情回顾请参考:
Spring Cloud 微服务二:API网关spring cloud zuul
Spring Cloud 微服务三: API网关Spring cloud gateway
Spring Cloud 微服务四:熔断器Spring cloud hystrix
- 限流算法
- 主流的限流算法有两种:漏桶(leaky bucket)和令牌桶(token bucket)。漏桶算法 有一个固定容量的桶,对于流入的水无法预计速率,流出的水以固定速率,当水满之后会溢出。

令牌桶算法,有一个固定容量的桶,桶里存放着令牌(token)。桶最开始是空的,token以一个固定速率向桶中填充,直到达到桶的容量,多余的token会被丢弃。每当一个请求过来时,都先去桶里取一个token,如果没有token的话请求无法通过。

两种算法的最主要区别是令牌桶算法允许一定流量的突发,因为令牌桶算法中取走token是不需要时间的,即桶内有多少个token都可以瞬时拿走。基于这个特点令牌桶算法在互联网企业中应用比较广泛,我们在实现限流的时候也会基于这个算法。
- gateway如何实现限流
方法1:Spring cloud gateway实现限流的方式主要是通过添加自定义filter来实现,自定义filter需要实现GatewayFilter和Ordered接口。本章将结合开源的Bucket4j来实现,Bucket4j是基于令牌桶算法实现,Bucket4j代码参考:https://github.com/vladimir-bukhtoyarov/bucket4j
- 首先修改api-gateway module,pom中添加Bucket4j依赖,最新版本是4.3.0,工程的版本已经在父工程中定义好了
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
</dependency>
第二步,添加filter实现GatewayFilter和Ordered,添加相应的参数,并使用一个ConcurrentHashMap存储ip以及bucket,实现filter方法,对客户端访问ip进行过滤
public class LimitFilter implements GatewayFilter, Ordered {
private static final Logger logger = LoggerFactory.getLogger(LimitFilter.class);
private int capacity;
private int refillTokens;
private Duration refillDuration;
public LimitFilter(int capacity, int refillTokens, Duration refillDuration) {
this.capacity = capacity;
this.refillTokens = refillTokens;
this.refillDuration = refillDuration;
}
private static final Map<String, Bucket> CACHE = new ConcurrentHashMap<>();
private Bucket createNewBucket() {
Refill refill = Refill.greedy(refillTokens, refillDuration);
Bandwidth limit = Bandwidth.classic(capacity, refill);
return Bucket4j.builder().addLimit(limit).build();
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
Bucket bucket = CACHE.computeIfAbsent(ip, k -> createNewBucket());
logger.info("IP: "+ip+", available tokens :"+bucket.getAvailableTokens());
if (bucket.tryConsume(1L)) {
return chain.filter(exchange);
}
logger.info("IP: "+ip+", available tokens :"+bucket.getAvailableTokens()+" too many requests");
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return 0;
}
}
第三步,添加自定义路由,添加配置类,RouteLocator构造器中添加filter以及相应的地址信息,设置同一ip同时只能访问一次,多余的将被忽略。另外,由于我们在程序中配置了路由,需要将application.yml中的gateway相关属性删除。
@Configuration
public class RouteLocatorConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
System.out.println("============================RouteLocatorConfig "+ builder.routes());
return builder
.routes()
.route(r -> r.path("/*")
.filters(f -> f.filter(new LimitFilter(1,
1, Duration.ofSeconds(1))))
.uri("http://localhost:10080/")
.order(0)
.id("user_route"))
.build();
}
}
最后,测试,重启api-gateway,访问http://localhost:8088/users,第一次访问成功,频繁刷新会出现空白页,控制台会输出相关信息
方法2:使用spring cloud 原生的redis方式
第一步,搭建redis服务器,具体方法参考redis官网
第二步,pom中添加redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
自定义resolver
@Configuration
public class CustomResolver {
@Bean
public KeyResolver ipKeyResolver(){
System.out.println("##############ipKeyResolver########################");
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
第三步,修改application.yml配置
routes:
- id: user_route
uri: http://localhost:10080
predicates:
- Path=/*
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 1
key-resolver: "#{@ipKeyResolver}
最后做测试,并使用monitor命令监控redis
Spring Cloud 微服务五:Spring cloud gateway限流的更多相关文章
- Spring Cloud微服务安全实战_3-3_API安全之流控
这几篇将API安全的 流控.认证.审计.授权 简单的过一遍,对这些概念先有个初步印象.后边还会详细讲解. 本篇说API安全之流控~第一印象. 一.概念 流控,流量控制,只放系统能处理的请求的数量过去, ...
- Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结
在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...
- Spring Cloud 微服务六:调用链跟踪Spring cloud sleuth +zipkin
前言:随着微服务系统的增加,服务之间的调用关系变得会非常复杂,这给运维以及排查问题带来了很大的麻烦,这时服务调用监控就显得非常重要了.spring cloud sleuth实现了对分布式服务的监控解决 ...
- 微服务与Spring Cloud概述
微服务与Spring Cloud随着互联网的快速发展, 云计算近十年也得到蓬勃发展, 企业的IT环境和IT架构也逐渐在发生变革,从过去的单体应用架构发展为至今广泛流行的微服务架构. 微服务是一种架构风 ...
- Spring Cloud 微服务三: API网关Spring cloud gateway
前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...
- 只需五分钟-用Maven快速搭建Spring Cloud微服务
Maven安装手册 1.准备安装包 安装包: apache-maven-3.5.4-bin.zip (最好JDK 1.7及以上版本) 集成包: eclipse-maven3-plugin.zip 2 ...
- spring cloud微服务实践五
本篇我们来看看怎么实现spring cloud的配置中心. 在分布式系统中,特别是微服务架构下,可能会存在许多的服务,每个服务都会存在一个或多个的配置文件.那怎么多的配置文件的管理就会成为一个大问题. ...
- Dubbo和Spring Cloud微服务架构'
微服务架构是互联网很热门的话题,是互联网技术发展的必然结果.它提倡将单一应用程序划分成一组小的服务,服务之间互相协调.互相配合,为用户提供最终价值.虽然微服务架构没有公认的技术标准和规范或者草案,但业 ...
- 在阿里云容器服务上开发基于Docker的Spring Cloud微服务应用
本文为阿里云容器服务Spring Cloud应用开发系列文章的第一篇. 一.在阿里云容器服务上开发Spring Cloud微服务应用(本文) 二.部署Spring Cloud应用示例 三.服务发现 四 ...
随机推荐
- 事件溯源模式(Event Sourcing Pattern)
此文翻译自msdn,侵删. 原文地址:https://msdn.microsoft.com/en-us/library/dn589792.aspx 本文介绍了一种有利于物化(materialize)领 ...
- linux的file指令
显示文件的类型,用命令 file 可以使你知道某个文件究竟是ELF格式的可执行文件, 还是shell script文 件或是其他的什么格式 例如:#file startx 语 法:file [-beL ...
- appium_v1.4.16版本自动化适配android7.0系统
https://www.cnblogs.com/imlvbu/p/7127940.html 要解决的问题:appium在androidV7.0系统上运行时报错 Failure [INSTALL_FAI ...
- linux 多线程那点事
说明:对多线程与相互排斥锁不熟悉的请參考其他 #include <pthread.h> #include <stdio.h> #include <stdlib.h> ...
- ES6里关于函数的拓展(一)
一.形参默认值 Javascript函数有一个特别的地方,无论在函数定义中声明了多少形参,都可以传入任意数量的参数,也可以在定义函数时添加针对参数数量的处理逻辑,当已定义的形参无对应的传入参数时为其指 ...
- 以lstm+ctc对汉字识别为例对tensorflow 中的lstm,ctc loss的调试
#-*-coding:utf8-*- __author = "buyizhiyou" __date = "2017-11-21" ''' 单步调试,结合汉字的识 ...
- 跟我一起透彻理解template模板模式
#include <iostream> using namespace std; //template模式. class Base { public: void DealWhat() { ...
- Laravel一些功能的简单总结
一.事件/广播 1.命令(事件在目录Events中, 监听器在Listeners中)artisan make:event 或 artisan event:generate前者创建一个事件,后者根据pr ...
- 图解HTTP第六章:HTTP首部
学习HTTP首部的结构和首部中各字段的用法. HTTP首部字段 使用首部字段是为了给浏览器和server提供报文主体大小.所使用的语言.认证信息等内容. 首部字段相应单个HTTP首部能够有多个值.假设 ...
- Cocos2d-X中创建菜单项
Cocos2d-X中创建菜单的类: CCMenuItemFont:创建纯文本的菜单项 CCMenuItemAtlasFont:创建带有艺术字体的菜单项 CCMenuItemImage:用图片创建菜单项 ...