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应用示例 三.服务发现 四 ...
随机推荐
- android 代码覆盖率
背景 项目使用的是small插件.一个app分为main和多个插件,为了统计插件的代码覆盖率. 1 修改插件 修改插件build.gradle buildTypes { release { ... } ...
- JAVA常见算法题(十四)
package com.xiaowu.demo; /** * 输入某年某月某日,判断这一天是这一年的第几天? * * * @author WQ * */ public class Demo14 { p ...
- Linux下安装Eclipse的PHP插件(PHPEclipse)
下载: Eclipse: http://www.eclipse.org/downloads/ (本人用的Ubuntu,直接在SoftWare Center中下载的) (选择适合你系统的相应 ...
- linux 下查看硬件信息(mac,IP地址,硬盘型号,序列号等)
一.查看网卡mac地址 #安装lshw [root@server ~]# yum install lshw #使用方法 [root@rsync-server ~]# lshw -c network * ...
- IQueryable接口与IEnumberable 区别
总结一下: IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,t ...
- NetBean 远程开发的好文1 --> NetBeans的远程Linux C开发实践
from: http://blog.csdn.net/jacktan/article/details/9268535 一直以来总觉得NetBeans生活在Eclipse的阴影下,同样做为一款不错的基 ...
- eclipse黄色警告(finally block does not complete normally) ,不建议在finally中使用return语句
在eclipse中编写例如以下的代码,eclipse会给出黄色告警:finally block does not complete normally. public class Test { publ ...
- synchronized的功能拓展:重入锁(读书笔记)
重入锁可以完全代替synchronized关键字.在JDK5.0的早期版本中,重入锁的性能远远好于synchronized,但是从JDK6.0开始.JDK在synchronized上做了大量的优化. ...
- 动态添加Fragment
在Fragment简单用法的基础上做修改 一.新建:another_right_fragment.xml <LinearLayout xmlns:android="http://sch ...
- 推荐系统学习(2)——基于TF-IDF的改进
使用用户打标签次数*物品打标签次数做乘积的算法尽管简单.可是会造成热门物品推荐的情况.物品标签的权重是物品打过该标签的次数,用户标签的权重是用户使用过该标签的次数.从而导致个性化的推荐减少,而造成热门 ...