限流与代理网关集成调研及应用

目录

一.限流相关问题概述

为什么使用限流?

限流场景:

限流的处理方式:

限流架构

限流算法

固定窗口算法

滑动窗口算法

漏桶算法

令牌桶算法

限流开源项目

Guava 的 RateLimiter

Bucket4j

Hystrix

Resilience4j

Sentinel限流

常用的限流技术调研对比

二.sentinel集成gateway

1.限流相关概念

2. sentinel介绍及集成gateway

(1)sentinel介绍

(2)sentinel和gateway集成


一.限流相关问题概述

为什么使用限流?

我们每个系统在做压测的时候,都有一个处理峰值,当接近峰值继续接受请求的时候,会导致整个系统响应缓慢;

为了保护系统,需要拒绝处理过载的请求,这就是我们下面介绍的限流,通过设定一个峰值阈值,限制请求达到这个峰值,以此来保护系统;

我们常见的一些中间件比如tomcat,mysql,redis等等都有类似的限制。

限流场景:

  • 限制某个接口一分钟内最多请求 100 次
  • 限制某个用户的下载速度最多 100KB/S
  • 限制某个用户同时只能对某个接口发起 5 路请求
  • 限制某个 IP 来源禁止访问任何请求
  • ...

根据不同的请求者和请求资源,可以组合出不同的限流规则。

可以根据请求者的 IP 来进行限流,或者根据请求对应的用户来限流,又或者根据某个特定的请求参数来限流。

而限流的对象可以是请求的频率,传输的速率,或者并发量等,其中最常见的两个限流对象是请求频率和并发量,他们对应的限流被称为 请求频率限流(Request rate limiting)和 并发量限流(Concurrent requests limiting)。

传输速率限流 在下载场景下比较常用,比如一些资源下载站会限制普通用户的下载速度,只有购买会员才能提速,这种限流的做法实际上和请求频率限流类似,只不过一个限制的是请求量的多少,一个限制的是请求数据报文的大小。

限流几项重要的系统指标

TPS(transport per second)

QPS (query per second)

吞吐量

RT

每秒处理的事务数量每秒的响应请求数系统在单位时间内处理请求的数量系统对请求做出响应的时间


关系:QPS(TPS)= 并发数/平均响应时间 或者 并发数 = QPS*平均响应时间

限流的处理方式:

一般我们有下面三种限流的处理方式:

拒绝服务
排队等待
服务降级

最简单的做法是拒绝服务,直接抛出异常,返回错误信息(比如返回 HTTP 状态码 429 Too Many Requests),或者给前端返回 302 重定向到一个错误页面,提示用户资源没有了或稍后再试。但是对于一些比较重要的接口不能直接拒绝,比如秒杀、下单等接口,我们既不希望用户请求太快,也不希望请求失败,这种情况一般会将请求放到一个消息队列中排队等待,消息队列可以起到削峰和限流的作用。第三种处理方式是服务降级,当触发限流条件时,直接返回兜底数据,比如查询商品库存的接口,可以默认返回有货。

限流的几种方式

熔断

服务降级

延迟处理

特权处理

拒绝流量访问,当系统恢复正常时在关闭熔断将次要服务降级,停止服务,将系统资源释放出来给核心功能在前端设置一个流程缓冲池,将所有的流程全部缓冲到这个池子不立即处理,常见队列缓模式处理,服务端处理不及时会丢失部分请求优先处理需要高保障的请求,其他请求丢去或者延迟处理

限流架构

单机模式的限流非常简单,可以直接基于内存就可以实现,而集群模式的限流必须依赖于某个“中心化”的组件,比如网关或 Redis,从而引出两种不同的限流架构:网关层限流 和 中间件限流。

网关作为整个分布式系统的入口,承担了所有的用户请求,所以在网关中进行限流是最合适不过的。网关层限流有时也被称为 接入层限流。

除了我们使用的 Spring Cloud Gateway,最常用的网关层组件还有 Nginx,可以通过它的 ngx_http_limit_req_module 模块,使用 limit_conn_zone、limit_req_zone、limit_rate 等指令很容易的实现并发量限流、请求频率限流和传输速率限流。

另一种限流架构是中间件限流,可以将限流的逻辑下沉到服务层。但是集群中的每个服务必须将自己的流量信息统一汇总到某个地方供其他服务读取,一般来说用 Redis 的比较多,Redis 提供的过期特性和 lua 脚本执行非常适合做限流。除了 Redis 这种中间件,还有很多类似的分布式缓存系统都可以使用,如 Hazelcast、Apache Ignite、Infinispan 等。我们可以更进一步扩展上面的架构,将网关改为集群模式,虽然这还是网关层限流架构,但是由于网关变成了集群模式,所以网关必须依赖于中间件进行限流,这和上面讨论的中间件限流没有区别。
 

限流算法

固定窗口算法

最简单的限流算法,根据限流的条件,将请求时间映射到一个时间窗口,使用计数器累加访问次数。

优点:实现简单

缺点:存在严重的临界问题,每过一个时间窗口,计数器会清零,限流效果不够平滑,恶意用户可以利用其绕过规则。在临界点前后发送请求,会使得阈值增加一倍。

滑动窗口算法

为了解决固定窗口算法的临界问题,可以将时间窗口划分成更小的时间窗口,然后随着时间的滑动删除相应的小窗口,而不是直接滑过一个大窗口,这就是滑动窗口算法。我们为每个小时间窗口都设置一个计数器,大时间窗口的总请求次数就是每个小时间窗口的计数器的和。如下图所示,我们的时间窗口是 5 秒,可以按秒进行划分,将其划分成 5 个小窗口,时间每过一秒,时间窗口就滑过一秒:每次处理请求时,都需要计算所有小时间窗口的计数器的和,考虑到性能问题,划分的小时间窗口不宜过多,譬如限流条件是每小时 N 个,可以按分钟划分为 60 个窗口,而不是按秒划分成 3600 个。当然如果不考虑性能问题,划分粒度越细,限流效果就越平滑。相反,如果划分粒度越粗,限流效果就越不精确,出现临界问题的可能性也就越大,当划分粒度为 1 时,滑动窗口算法就退化成了固定窗口算法。由于这两种算法都使用了计数器,所以也被称为 计数器算法(Counters)

进一步思考我们发现,如果划分粒度最粗,也就是只有一个时间窗口时,滑动窗口算法退化成了固定窗口算法;那如果我们把划分粒度调到最细,又会如何呢?那么怎样才能让划分的时间窗口最细呢?时间窗口细到一定地步时,意味着每个时间窗口中只能容纳一个请求,这样我们可以省略计数器,只记录每个请求的时间,然后统计一段时间内的请求数有多少个即可,Redis sorted set 技巧 和Sliding window log 算法。

漏桶算法

除了计数器算法,另一个很自然的限流思路是将所有的请求缓存到一个队列中,然后按某个固定的速度慢慢处理,这其实就是漏桶算法(Leaky Bucket)。漏桶算法假设将请求装到一个桶中,桶的容量为 M,当桶满时,请求被丢弃。在桶的底部有一个洞,桶中的请求像水一样按固定的速度(每秒 r 个)漏出来。我们用下面这个形象的图来表示漏桶算法:桶的上面是个水龙头,我们的请求从水龙头流到桶中,水龙头流出的水速不定,有时快有时慢,这种忽快忽慢的流量叫做 Bursty flow。如果桶中的水满了,多余的水就会溢出去,相当于请求被丢弃。从桶底部漏出的水速是固定不变的,可以看出漏桶算法可以平滑请求的速率。漏桶算法可以通过一个队列来实现,如下图所示:当请求到达时,不直接处理请求,而是将其放入一个队列,然后另一个线程以固定的速率从队列中读取请求并处理,从而达到限流的目的。注意的是这个队列可以有不同的实现方式,比如设置请求的存活时间,或将队列改造成 PriorityQueue,根据请求的优先级排序而不是先进先出。当然队列也有满的时候,如果队列已经满了,那么请求只能被丢弃了。漏桶算法有一个缺陷,在处理突发流量时效率很低,于是人们又想出了下面的令牌桶算法。

令牌桶算法

令牌桶算法(Token Bucket)是目前应用最广泛的一种限流算法,它的基本思想由两部分组成:生成令牌 和 消费令牌。


生成令牌:假设有一个装令牌的桶,最多能装 M 个,然后按某个固定的速度(每秒 r 个)往桶中放入令牌,桶满时不再放入;
消费令牌:我们的每次请求都需要从桶中拿一个令牌才能放行,当桶中没有令牌时即触发限流,这时可以将请求放入一个缓冲队列中排队等待,或者直接拒绝;

在实际的应用中,往往不会直接使用这种原始的令牌桶算法,

一般会在它的基础上作一些改进,比如,填充速率支持动态调整,令牌总数支持透支,基于 Redis 支持分布式限流等,不过总体来说还是符合令牌桶算法的整体框架,我们在后面学习一些开源项目时对此会有更深的体会。

限流开源项目

Guava 的 RateLimiter

Guava 的 RateLimiter 基于令牌桶算法实现,不过在传统的令牌桶算法基础上做了点改进,支持两种不同的限流方式:平滑突发限流(SmoothBursty) 和 平滑预热限流(SmoothWarmingUp)。

Bucket4j

Bucket4j是一个基于令牌桶算法实现的强大的限流库,它不仅支持单机限流,还支持通过诸如 Hazelcast、Ignite、Coherence、Infinispan 或其他兼容 JCache API (JSR 107) 规范的分布式缓存实现分布式限流

Hystrix

Hystrix是一个延迟和容错库,旨在隔离远程系统、服务和第三方库的访问点,停止级联故障,并在故障不可避免的复杂分布式系统中实现恢复能力。

Resilience4j

Resilience4j 是一款轻量级、易使用的高可用框架。用过 Spring Cloud 早期版本的同学肯定都听过 Netflix Hystrix,Resilience4j 的设计灵感就来自于它。自从 Hystrix 停止维护之后,官方也推荐大家使用 Resilience4j 来代替 Hystrix。

Resilience4j 的底层采用 Vavr,这是一个非常轻量级的 Java 函数式库,使得 Resilience4j 非常适合函数式编程。Resilience4j 以装饰器模式提供对函数式接口或 lambda 表达式的封装,提供了一波高可用机制:重试(Retry)、熔断(Circuit Breaker)、限流(Rate Limiter)、限时(Timer Limiter)、隔离(Bulkhead)、缓存(Caceh) 和 降级(Fallback)

还支持并发量限流。不过最大的遗憾是,Resilience4j 不支持分布式限流。

gateway网关的限流

网关自带了限流的功能,但是 Spring Cloud Gateway 自带的限流有很多限制,譬如不支持单机限流,不支持并发量限流,而且它的请求频率限流也是不尽人意,这些都需要我们自己动手来解决

Sentinel限流

强大的流量控制组件,为微服务提供可靠性、弹性和监控,面向云原生微服务的高可用流控防护组件。

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

易用的控制台:

常用的限流技术调研对比

Sentinel

Hystrix(维护状态)

Resilience4j(Spring推荐)

开发者alibabaNetflix独立
隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离
熔断降级策略基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间
实时统计实现滑动窗口(LeapArray)滑动窗口(基于 RxJava)Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点插件的形式接口的形式
基于注解的支持支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式不支持简单的 Rate Limiter 模式
系统自适应保护支持不支持不支持
控制台提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等简单的监控查看不提供控制台,可对接其它监控系统

二.sentinel集成gateway

1.限流相关概念

  • 熔断:停止访问某个下游依赖服务
  • 限流:希望限制请求我服务的流量
  • 切流:
    • 我是多活服务,希望故障时可以切换机房流量:
    • 我是单活服务,希望调整同机房不同集群的流量配比:
  • 开关:服务中某个功能是否开启的配置开关。在 911 平台,也作为一种熔断手段。
     
  • 自动降级
    • 希望报警时,能触发我的预案降级
    • 希望配置更灵活的自动降级预案:卡尔故障自愈平台

2. sentinel介绍及集成gateway

(1)sentinel介绍

sentinel官网:quick-start

sentinel限流介绍:Sentinel(哨兵) 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。

https://i-blog.csdnimg.cn/blog_migrate/82e1c76863c881c9e9027fc187a3c524.png

sentinel分为两个部分:
核心库(java客户端):不依赖任何框架,能够运行于所有java运行时环境,同时对dubbo、springCloud等框架也有较好的支持
控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器

sentinel源码:GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)

源码结构

sentinel-core 核心模块,限流、降级、系统保护等都在这里实现

sentinel-dashboard 控制台模块,可以对连接上的sentinel客户端实现可视化的管理

sentinel-transport 传输模块,提供了基本的监控服务端和客户端的API接口,以及一些基于不同库的实现

sentinel-extension 扩展模块,主要对DataSource进行了部分扩展实现

sentinel-adapter 适配器模块,主要实现了对一些常见框架的适配

sentinel-demo 样例模块,可参考怎么使用sentinel进行限流、降级等

sentinel-benchmark 基准测试模块,对核心代码的精确性提供基准测试

(2)sentinel和gateway集成

sentinel和gateway

sentinel支持spring cloud gateway,zuul等主流的API gateway进行限流

https://i-blog.csdnimg.cn/blog_migrate/a72e946dfcdf1c6103d827ffede64a7e.pngsentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑:

GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

网关流控实现原理
当通过 GatewayRuleManager 加载网关流控规则(GatewayFlowRule)时,无论是否针对请求属性进行限流,Sentinel 底层都会将网关流控规则转化为热点参数规则(ParamFlowRule),存储在 GatewayRuleManager 中,与正常的热点参数规则相隔离。转换时 Sentinel 会根据请求属性配置,为网关流控规则设置参数索引(idx),并同步到生成的热点参数规则中。

外部请求进入 API Gateway 时会经过 Sentinel 实现的 filter,其中会依次进行 路由/API 分组匹配、请求属性解析和参数组装。Sentinel 会根据配置的网关流控规则来解析请求属性,并依照参数索引顺序组装参数数组,最终传入 SphU.entry(res, args) 中。Sentinel API Gateway Adapter Common 模块向 Slot Chain 中添加了一个 GatewayFlowSlot,专门用来做网关规则的检查。GatewayFlowSlot 会从 GatewayRuleManager 中提取生成的热点参数规则,根据传入的参数依次进行规则检查。若某条规则不针对请求属性,则会在参数最后一个位置置入预设的常量,达到普通流控的效果。

在这里插入图片描述

参考文档

限流常见功能方案

实战 Spring Cloud Gateway 之限流篇_wx5acb795659485的技术博客_51CTO博客

sentinel配置说明

【微服务】(十二)—— Sentinel限流_机智兵的博客-CSDN博客_sentinel链路限流

限流技术调研对比

断路器对比Sentinel、Hystrix、resilience4j_lizz666的博客-CSDN博客_resilience4j和sentinel

sentinel与gateway集成

Sentinel系列(11) - Spring Cloud Gateway整合Sentinel实现网关限流_云烟成雨TD的博客-CSDN博客_sentinel整合gateway

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值