最近项目中 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>

启动,检查限流功能生效,并且不影响不限流的其他接口!至此解决了限流有无的问题!

返回处理

我们可能需要对触发限流的情况做监控、报警等,需要识别由限流导致的异常返回

  1. 推荐使用默认的 RateLimiterErrorHandler,直接写自己需要的处理就行
  2. zuul触发限流后会抛出 http 429,可以针对这个错误码对response包装
  3. 也可以在全局异常处理中,判断出现的异常是否是 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 网关限流分析的更多相关文章

  1. Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!

    大家好,我是不才陈某~ 这是<Spring Cloud 进阶>第八篇文章,往期文章如下: 五十五张图告诉你微服务的灵魂摆渡者Nacos究竟有多强? openFeign夺命连环9问,这谁受得 ...

  2. Spring Cloud Gateway 网关限流

    Spring Cloud Gateway 限流 一.背景 二.实现功能 三.网关层限流 1.使用默认的redis来限流 1.引入jar包 2.编写配置文件 3.网关正常响应 4.网关限流响应 2.自定 ...

  3. spring cloud网关通过Zuul RateLimit 限流配置

    目录 引入依赖 配置信息 RateLimit源码简单分析 RateLimit详细的配置信息解读 在平常项目中为了防止一些没有token访问的API被大量无限的调用,需要对一些服务进行API限流.就好比 ...

  4. Spring Cloud alibaba网关 sentinel zuul 四 限流熔断

    spring cloud alibaba 集成了 他内部开源的 Sentinel 熔断限流框架 Sentinel 介绍 官方网址 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentine ...

  5. Zuul【限流】

    在项目中,大部分都会使用到hyrtrix做熔断机制,通过某个预定的阈值来对异常流量进行降级处理,除了做服务降级以外,还可以对服务进行限流,分流,排队等. 当然,zuul也能做到限流策略,最简单的方式就 ...

  6. SpringCloud Zuul网关的简单理解

    Zuul网关功能 请求路由.服务路由.请求过滤 请求路由 参数配置如下所示,所有能够配置path规则的请求,都会被zuul网关转发到对应的url上. zuul.routes.user-service. ...

  7. 微服务架构spring cloud - gateway网关限流

    1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...

  8. spring cloud gateway整合sentinel作网关限流

    说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentine ...

  9. redis实现网关限流(限制API调用次数1000次/分)

    添加maven依赖,使用springboot2.x版本 <dependency> <groupId>org.springframework.boot</groupId&g ...

随机推荐

  1. 管理Windows上的路由表

    路由器获取目录帮助手册: route /? 修改路由的时候最高以管理员运行cmd程序 默认路由只是临时生效的,只要管理员禁用在启用网卡,默认路由就消失了(重启计算机默认路由也会消失),可以在后面添加一 ...

  2. 实验2 C语言表达式编程应用及输入输出函数( 后附炫彩小人:) )

    实验任务一 #include <stdio.h> int main (){ int a=5,b=7,c=100,d,e,f; d=a/b*c; e=a*c/b; f=c/b*a; prin ...

  3. 要多用Java帮助文档

    从第一次接触Java到现在,大概两年了吧,间断断续续的学习.毕竟还在上课,其他课程也挺耗时间,但更多的还是自己不自律,很多时间都在玩. 平时用的有eclipse和IDEA,使用快捷方式有时看看源码,也 ...

  4. 详解Vue中的插槽

    作者: 小土豆 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/2436173500265335 什么是插槽 在日常的项目 ...

  5. Kubernetes官方java客户端之一:准备

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. esx.problem.hyperthreading.unmitigated

    是因为VMware新发布的一个漏洞补丁导致的具体解释可参阅VMware官方kb,有详细解释和版本说明. 可选择屏蔽该问题告警 选中主机>配置>高级系统设置>编辑>修改" ...

  7. devops持续集成

    目录 Devops 版本控制系统 Git安装 Git使用 git四种状态 git基础命令 git分支 git合并冲突 git标签 git命令总结 Github使用 创建仓库 HTTP协议 SSH协议 ...

  8. 云计算之2---KVM

    介绍 KVM KVM:就是Keyboard Video Mouse的缩写.KVM 交换机通过直接连接键盘.视频和鼠标 (KVM) 端口,让您能够访问和控制计算机.KVM 技术无需目标服务器修改软件.这 ...

  9. mysql数据库限制多次登录失败,限定用户重试时间

    前言 最近的项目开始进行安全测试,其中有一个安全问题是这样的. 应该增加用户登录失败处理功能,限制非法登录次数. 建议是增加mysql数据库的登陆失败的锁定功能. 相信大家也都会遇到这样的问题,在这里 ...

  10. Kafka知识总结及面试题

    目录 概念 Kafka基础概念 命令行 Kafka 数据存储设计 kafka在zookeeper中存储结构 生产者 生产者设计 消费者 消费者设计 面试题 kafka设计 请说明什么是Apache K ...