SpringCloud zuul 网关限流分析
最近项目中 spring cloud zuul 运用到限流功能,打算配置一下就直接使用,不过在压测与调优过程中遇到一些没有预测到的问题,附上排查与解析结果
yml、pom配置
强烈推荐,按最新github上的文档配,可以避免搜到一些已经废弃不用的配置方式!
https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit
我的一些配置,可以直接套用:
zuul:
routes:
#路由、重试等zuul其他配置省略
#限流
ratelimit:
enabled: true # 开启限流功能
behind-proxy: true # 开启则限流与业务访问是异步的,相当于rateLimitFilter先放过;默认是false
repository: REDIS # 可选REDIS、CONSUL、JPA等,老版本还有本地内存可选
policy-list:
myProject1:
- limit: 5 # 这种配置方式相当于:10分钟内允许5个请求访问/api/test/info接口
refresh-interval: 10
type:
- url_pattern=/api/test/info
myProject2:
- limit: 3000
refresh-interval: 1 # 更常见的配置是这种,一秒允许3k个,相当于配qps限制
type:
- url_pattern=/api/test2/info
- limit: 300
refresh-interval: 1 # 如果同一个服务有多个需要限流的url,可以这样
type:
- url_pattern=/api/test2/info2
pom需要:
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>${latest-version}</version>
</dependency>
如果 repository 选择用 REDIS,还需要:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
启动,检查限流功能生效,并且不影响不限流的其他接口!至此解决了限流有无的问题!
返回处理
我们可能需要对触发限流的情况做监控、报警等,需要识别由限流导致的异常返回
- 推荐使用默认的 RateLimiterErrorHandler,直接写自己需要的处理就行
- zuul触发限流后会抛出 http 429,可以针对这个错误码对response包装
- 也可以在全局异常处理中,判断出现的异常是否是 RateLimitExceededException

其他配置方式
目前项目中只用到了对特定url的qps限流,zuul ratelimit 还提供对user、http method、url正则等
性能分析
限流配置之前,单实例压测,qps大概能到2500;配个2300的限流,开开心心启动服务,启动压测!

WTF!限流对性能的影响已经超过了限流配置本身。。一定是我哪里不对TAT
开始排查问题,查实现原理
zuul 限流的入口是zuul的 RateLimitPreFilter

其中 rateLimitKeyGenerator.key 所生成的redis key较长,规则为 前缀(默认为springBoot项目名) + : + zuul项目名 + : + matcher(和限流策略有关,这里是URL_PATTERN) + : + matcher(再来一遍)
如果项目名和url较长,可能出现key例如:my-test-project-gateway:my-sub-project:/api/test2/info2:/api/test2/info2
不过监控看redis暂不是短板,继续查
限流的实现,通过 rateLimiter.consume 方法

继续往下看,calcRemainingLimit 方法,内部调用了calcRemaining 方法:

原理不难,利用redis incr命令,每次计算当前过期窗口内还剩几次,来决定是否限流,安全又高效
但是,上一张图 rateLimiter.consume 方法增加了 synchornized,怀疑是这个原因
其中 redisTemplate.opsForValue().increment(key, usage) 已经没有并发问题了,这里感觉不用再 synchornized +_+*
发现也有同僚遇到了这个问题,建议是重写这个类,去掉synchornized
https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit/issues/96
讨论中有人主张去掉synchornized,有人主张保留

决定还是要去掉synchornized,压测

完美!!!
再验证一下对无限流的接口是否无影响,确保可用
其他网关限流方式
目前刚开始接触,也还在探索中,可以一起讨论下
1. spring cloud gateway:
- 也是成熟的技术,并且大部分文章分析 Finchley版本的 gateway比 zuul 1.x系列的性能和功能整体要好
- 目前 spring cloud 没集成 Zuul 2.x,虽然zuul 2.x使用了异步无阻塞式的 API,性能改善明显
- 实现思想很简洁,令牌桶,只有50行lua,其中有4次redis调用
- 可以通过monitor命令看出:
request_rate_limiter.lua
测试配置为:
redis-rate-limiter.replenishRate: 500 允许每秒500个请求
redis-rate-limiter.burstCapacity: 5000 令牌桶容量5000
1. 查询当前桶里剩余令牌数
1590493327.354684 [0 lua] "get" "request_rate_limiter.{/app/test/info}.tokens"
2. 查询上次取牌的时间
注意:通过当前时间,和上次取牌的时间差,即可在lua中计算出这段时间内新补充进桶里的令牌数,不用每秒真正补充进桶
1590493327.354696 [0 lua] "get" "request_rate_limiter.{/app/test/info}.timestamp"
3. 把这次取的1个令牌,和这段时间内需要重新补充进桶的令牌整合,更新最新令牌数
注意:超时时间为 (brustCapacity/replenishRate)*2,感觉不乘2也行,只要保证超时时间 >= 桶重新装满的时间就够了,乘2是否完全是为了保险?
1590493327.354712 [0 lua] "setex" "request_rate_limiter.{/app/test/info}.tokens" "20" "4999"
4. 更新最新取牌时间
1590493327.354727 [0 lua] "setex" "request_rate_limiter.{/app/test/info}.timestamp" "20" "1590493327"
2. 自己用filter+redis、guava rate limiter等实现
可以做单机缓存、自己定制规则
总结
目前的测试是单机压测,集群下压测或许还会在别的地方遇到瓶颈
单实例配置、zuul进程数和其他配置、redis集群性能、业务代码,都有提升的空间
还需要继续排查与优化
SpringCloud zuul 网关限流分析的更多相关文章
- Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!
大家好,我是不才陈某~ 这是<Spring Cloud 进阶>第八篇文章,往期文章如下: 五十五张图告诉你微服务的灵魂摆渡者Nacos究竟有多强? openFeign夺命连环9问,这谁受得 ...
- Spring Cloud Gateway 网关限流
Spring Cloud Gateway 限流 一.背景 二.实现功能 三.网关层限流 1.使用默认的redis来限流 1.引入jar包 2.编写配置文件 3.网关正常响应 4.网关限流响应 2.自定 ...
- spring cloud网关通过Zuul RateLimit 限流配置
目录 引入依赖 配置信息 RateLimit源码简单分析 RateLimit详细的配置信息解读 在平常项目中为了防止一些没有token访问的API被大量无限的调用,需要对一些服务进行API限流.就好比 ...
- Spring Cloud alibaba网关 sentinel zuul 四 限流熔断
spring cloud alibaba 集成了 他内部开源的 Sentinel 熔断限流框架 Sentinel 介绍 官方网址 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentine ...
- Zuul【限流】
在项目中,大部分都会使用到hyrtrix做熔断机制,通过某个预定的阈值来对异常流量进行降级处理,除了做服务降级以外,还可以对服务进行限流,分流,排队等. 当然,zuul也能做到限流策略,最简单的方式就 ...
- SpringCloud Zuul网关的简单理解
Zuul网关功能 请求路由.服务路由.请求过滤 请求路由 参数配置如下所示,所有能够配置path规则的请求,都会被zuul网关转发到对应的url上. zuul.routes.user-service. ...
- 微服务架构spring cloud - gateway网关限流
1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...
- spring cloud gateway整合sentinel作网关限流
说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentine ...
- redis实现网关限流(限制API调用次数1000次/分)
添加maven依赖,使用springboot2.x版本 <dependency> <groupId>org.springframework.boot</groupId&g ...
随机推荐
- Github标星26k+!一个神奇的软件!1分钟即可打造了一个科幻风格的终端
Github掘金计划项目分类汇总(原创不易,若有帮助,欢迎分享/点赞): 编程基础 :精选编程基础如学习路线.编程语言相关的开源项目. 计算机基础:精选计算机基础(操作系统.计算机网络.算法.数据结构 ...
- Azure Service Bus(一)入门简介
一,引言 今天开始学习新的内容 Azure Service Bus(服务总线),其实也叫 "云消息服务",和 RabbitMQ,KafKa的一样都是作为消息通信服务,但是它们直接还 ...
- CentOs8安装redis与Linux安装GDI+图形
1.安装 yum install redis 2.编辑配置文件 vim /etc/redis.conf #requirepass那行并打开注释,在后面写自己的密码,如下 requirepass you ...
- .Net Core的简单单元测试基于Mock和自定义
首先创建 使用mock 外部依赖一般用Mock 模拟 下载包 例如 3.1:首先先要使用MOCk来模拟测试方法需要的参数,这一步为 Arrange; 简单的模拟 var mock = new Mock ...
- Blogs实现导航菜单
#1.隐藏默认导航菜单 #header{display:none;} /*在页面定制CSS里面最前面添加如下代码,最好添加在最前面*/ #2.添加页首html代码 <!-- 添加博客导航栏信息开 ...
- [Python] iupdatable包:Timer 类使用介绍
iudatable包是我对常用函数进行的封装后发布的一个python包,教程汇总目录: [Python] iupdatable包使用说明 安装 iupdatable 包 pip install iup ...
- 为什么会有kafka消息系统?小问题藏着大细节!
前言:老刘今天写这篇文章首先想对一些复制粘贴的博客表达不满:其次是想用通俗易懂的话解释消息系统:最后欢迎各位英雄好汉.女中豪杰前来battle. 1. 为什么有消息系统? 1.1 背景 今天复习kaf ...
- 两千星 .NET5 框架 Furion 亮点分析(一)
让 .NET 开发更简单,更通用,更流行. Furion 介绍 Furion 是基于 .NET5 平台下打造的现代化 Web 框架.旨在 让 .NET 开发更简单,更通用,更流行.. Furion 非 ...
- java 反射给字段重新赋值
1.获取实体的所有字段,遍历 2.获取字段类型 3.调用字段的get方法,判断字段值是否为空 4.如果字段值为空,调用字段的set方法,为字段赋值 Field[] field = model.getC ...
- [每日一题]面试官问:for in和for of 的区别和原理?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...