前言:在互联网应用中,特别是电商,高并发的场景非常多,比如:秒杀、抢购、双11等,在开始时间点会使流量爆发式地涌入,如果对网络流量不加控制很有可能造成后台实例资源耗尽。限流是指通过指定的策略削减流量,使到达后台实例的请求在合理范围内。本章将介绍spring cloud gateway如何实现限流。

前情回顾请参考:

Spring Cloud 微服务一:Consul注册中心

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限流的更多相关文章

  1. Spring Cloud微服务安全实战_3-3_API安全之流控

    这几篇将API安全的 流控.认证.审计.授权 简单的过一遍,对这些概念先有个初步印象.后边还会详细讲解. 本篇说API安全之流控~第一印象. 一.概念 流控,流量控制,只放系统能处理的请求的数量过去, ...

  2. Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结

    在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...

  3. Spring Cloud 微服务六:调用链跟踪Spring cloud sleuth +zipkin

    前言:随着微服务系统的增加,服务之间的调用关系变得会非常复杂,这给运维以及排查问题带来了很大的麻烦,这时服务调用监控就显得非常重要了.spring cloud sleuth实现了对分布式服务的监控解决 ...

  4. 微服务与Spring Cloud概述

    微服务与Spring Cloud随着互联网的快速发展, 云计算近十年也得到蓬勃发展, 企业的IT环境和IT架构也逐渐在发生变革,从过去的单体应用架构发展为至今广泛流行的微服务架构. 微服务是一种架构风 ...

  5. Spring Cloud 微服务三: API网关Spring cloud gateway

    前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...

  6. 只需五分钟-用Maven快速搭建Spring Cloud微服务

    Maven安装手册 1.准备安装包 安装包: apache-maven-3.5.4-bin.zip  (最好JDK 1.7及以上版本) 集成包: eclipse-maven3-plugin.zip 2 ...

  7. spring cloud微服务实践五

    本篇我们来看看怎么实现spring cloud的配置中心. 在分布式系统中,特别是微服务架构下,可能会存在许多的服务,每个服务都会存在一个或多个的配置文件.那怎么多的配置文件的管理就会成为一个大问题. ...

  8. Dubbo和Spring Cloud微服务架构'

    微服务架构是互联网很热门的话题,是互联网技术发展的必然结果.它提倡将单一应用程序划分成一组小的服务,服务之间互相协调.互相配合,为用户提供最终价值.虽然微服务架构没有公认的技术标准和规范或者草案,但业 ...

  9. 在阿里云容器服务上开发基于Docker的Spring Cloud微服务应用

    本文为阿里云容器服务Spring Cloud应用开发系列文章的第一篇. 一.在阿里云容器服务上开发Spring Cloud微服务应用(本文) 二.部署Spring Cloud应用示例 三.服务发现 四 ...

随机推荐

  1. Windows 8.1中WinRT的变化(二)——新增功能

    首先我们来看看现有控件中新增的功能: FlipView编程方式切换时支持平滑滚动: 在Windows8中,FlipView在用手触控翻页的时候是有动画效果的,但当我们使用键盘或代码编程翻页时,却没有这 ...

  2. 工作组模式下专用队列(Private Queue)如何引用远程队列路径

    查了N久资料,包括MSDN的官方文档,对于同一工作组下,不同机器之间如何利用Private Queue(专用队列)来发送/接收消息,关于Path的引用一说,无非都是MachineName\privat ...

  3. Delphi ParamStr 使用方法

    ParamStr(0) 代表程序的路径, ParamStr(1) 代表程序的设置的参数

  4. vs2010 sharepoint项目部署与查看

    1.选中sharepoint项目,视图→属性窗口,填写站点url ,我这里原来写81,但是81已经放了另外一个项目,所以要把它改为刚刚新增的82端口 不知道影不影响,反正我重新打开了一遍. 2.重新生 ...

  5. Android获取视频音频的时长的方法

    android当中获取视频音频的时长,我列举了三种. 1:获取视频URI后获取cursor cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore ...

  6. Unitity 常用工具类

    ylbtech-Unitity_C#: Unitity 常用代码 1.A,效果图返回顶部   1.B,源代码返回顶部 1,日期字符串 using System; using System.Xml; / ...

  7. Windows下cwRsyncServer双机连续同步部署

    下载cwRsyncServer服务器端与客户端的安装文件:服务端下载:cwRsyncServer_4.0.5_Installer.zip客户端下载:cwRsync_4.0.5_Installer.zi ...

  8. C语言:宽字符集操作函数

    C语言:宽字符集操作函数 (unicode编码) 字符分类: 宽字符函数普通C函数描述 iswalnum() isalnum() 测试字符是否为数字或字母 iswalpha() isalpha() 测 ...

  9. javascript另类写法

    今天来介绍一下javascript不一样的写法,很简单哦. 1.当条件成立时执行a方法,当条件失败是执行b方法 通常我们会这样写: var result; if(isOk){ result=funA( ...

  10. 转: Java 应用一般架构

    http://mp.weixin.qq.com/s?__biz=MzAwMzI3Njc1MA==&mid=2650192186&idx=1&sn=bd08fd3a89f9089 ...