《餐厅小故事》| 服务限流的实施

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 本文主要介绍 服务限流

服务限流 应当是每个并发程序都应该考虑的~!限流的目的不仅是为了控制访问的总并发量,而且还要尽量让访问的流量来的更均衡,这样才不会让系统的负载大起大落,因此又称为"流量整形"


当然在微服务盛行的时代,我们考虑到的 服务限流 不再单单应对 单体服务 ,而是更要清楚分布式场景下如何进行 服限流


一丶单体限流


网络异常,图片无法展示
|


以上三种是我们在 单体服务 中常见的限流算法,我们接下来分别认识一下!


1、计数器限流


计数器限流 是属于一种比较简单粗暴的方式!


设计思路如下:


我们会限制一秒钟内能够通过的请求数(比如 50),从第一个请求进来开始计数,在接下去的1s 内,每进来一个请求,我们就会把计数值加 1,如果累加的数字达到了 50,那么后续的请求就会被全部拒绝,等到 1s  过去之后,把计数恢复成 0,并重新开始计数


网络异常,图片无法展示
|


使用计数器可以用来限制一定时间内的总并发数,但说到底这是一种简单粗暴的限流方式,而不是平均速率限流,在某些场景下可以使用。但是遇到某些特殊的情况下,如果系统的负载量只有 50,在第59秒瞬间请求 50 次,并且在第 1:00 也请求了 50 次,那么这个程序在 1 秒内被请求了 100次,瞬间超过总负载,很有可能直接击垮我们的应用程序!


网络异常,图片无法展示
|


当然,事情都没有绝对的,我们可以使用 滑动窗口 的方式解决问题。说到 滑动窗口 有些小伙伴并不陌生,因为 TCP 协议 就有采用 滑动窗口来控制流量,不清楚的小伙伴往下看!


滑动窗口算法指的是以当前时间为截止时间,往前取一定的时间,比如取 60 秒时间,在这 60 秒之内运行的最大访问数为 50,此时算法的执行逻辑为:先清除 60 秒之前的所有请求记录,再计算当前集合内请求数量是否大于设定的最大请求数 50?如果大于则执行限流拒绝策略,否则插入本次请求记录并执行正常流程。


网络异常,图片无法展示
|


我们在上图可以看出,一个被红色线段圈起来的就可以认为是一个时间窗口(1分钟) ,然后我们将时间窗口进行划分为 5 小格子,也就相当于 1 个小格是 12 s,每超过 12 s ,时间窗口就会往前步移一格,每一格都有自己独立的计数器,假设第 35 秒的时候来了一个请求,那么 0:25~0:36 这个范围格子的计数值就会加 1 。


网络异常,图片无法展示
|


我们通过上图回顾下 计数器 限流会遇到的问题,当 0:59 来了 50 个请求时会落在上图紫色区域 中,如果 1:00 又来了 50 个请求,会落在上图的 粉色区域 中,因为时间窗口的移动,总共 100 个请求落在了同一个时间窗口中,就会被检测出从而触发限流。而这就是 滑动窗口 的思想,接下来我们可以借助 Redis 来简单演示下:


网络异常,图片无法展示
|


执行结果:


Thread-0  正常执行
Thread-2  正常执行
Thread-3  正常执行
Thread-6  正常执行
Thread-7  正常执行
Thread-10 正常执行
Thread-11 正常执行
Thread-14 正常执行
Thread-1  正常执行
Thread-4  正常执行
Thread-5  正常执行
Thread-8  超出最大的系统负载量, 执行限流
Thread-8  正常执行
Thread-9  超出最大的系统负载量, 执行限流
Thread-9  正常执行
Thread-12 超出最大的系统负载量, 执行限流
Thread-12 正常执行
Thread-13 超出最大的系统负载量, 执行限流
Thread-13 正常执行


这段简易的代码当然有许多漏洞,但是仅仅给你提供一个实现的思路!


2、漏桶算法


我们开头说到的 餐厅排号 其实就是一种类漏桶的实现方式,餐厅的容量就相当于是一个 桶容量,桶的容量是固定的,桶底的水会不断的流出(用餐结束的顾客),桶顶的水(待用餐的顾客)不断流入。如果流入的水量(请求量)超出了流出的桶流量(最大并发量),桶满后新流入的水会直接溢出,这就是限流应用中常用的漏桶算法。


网络异常,图片无法展示
|


其实 Java 就已经自带了一个很好实现漏桶算法的工具,那就是 Semaphore,它可以有效的控制服务的最大并发总数,防止服务过载。下面是 Semaphore 的典型用法:


网络异常,图片无法展示
|


通过上述例子我们不难发现,漏桶算法主要关注的是当前的并发总量(信号总量),只有某个资源被释放的信号发出(release操作),等待进入的请求才能获得“通行证”,有出才有进,我们通过这种方式同样可以保证系统的负载可控。


3、令牌桶算法


限流的另一种常用算法是令牌桶算法,它的实现原理为系统以恒定的速度往桶中放入令牌,请求需要从桶中获取令牌才能被处理,一旦桶中无令牌可取,则拒绝服务。


网络异常,图片无法展示
|


我们可以借助第三方工具实现该算法,如 Google Guava 的 RateLimiter组件则是采用令牌桶算法,以下是简单的使用示例:


网络异常,图片无法展示
|


OUTPUT:
Thread-1  2021-08-01 00:09:14
Thread-10 2021-08-01 00:09:14
Thread-9  2021-08-01 00:09:15
Thread-8  2021-08-01 00:09:15
Thread-6  2021-08-01 00:09:16
Thread-7  2021-08-01 00:09:16
Thread-5  2021-08-01 00:09:17
Thread-3  2021-08-01 00:09:17
Thread-4  2021-08-01 00:09:18
Thread-2  2021-08-01 00:09:18


从上面的结果上来看,令牌确实是 1 秒产生 2 个,而 acquire()  方法为阻塞等待令牌,它可以传递一个 int 类型的参数,用来指定获取令牌的个数,当然它还有一种替代方法 tryAcquire(),此方法在没有可用令牌的时候就会直接返回 false ,这样就不会阻塞等待了。当然 tryAcquire()可以设置超时事件,未超过最大等待事件会阻塞等待获取令牌,如果超过了最大等待时间还没有可用的令牌就会返回 false


网络异常,图片无法展示
|


OUTPUT:
limit
limit
limit
limit
limit
limit
limit
limit
Thread-10 2021-08-01 00:08:05
Thread-4  2021-08-01 00:08:05


通过以上例子我们可以总结:使用 RateLimiter实现的令牌桶算法不仅可以应对正常流量的限速,而且可以处理突发暴增的请求,实现平滑限流。


二丶分布式限流


单机限流场景下,各个服务节点负责各自机器的限流,不关注其他节点,更不关注集群的总调用量~!但是后台资源是有限的,在分布式的场景下,我们的关注点不能再集中于某个节点上,有时候虽然各个单节点的流量都没有超,但是各个节点的流量和却超过了后台资源的总承受量,所以必须控制服务在所有节点上的总流量,这就是 分布式限流


说到分布式,我们会想到 网关 的概念


相关阅读请空降:《吃透微服务》 - 服务网关之Gateway


当我们在了解完网关的概念与作用后,自然清楚总流量控制可以在网关层面进行限流,但是有种 P2P 直连模式的服务集群就没有网关的概念。这个时候要怎么办呢?


我们上面说到有时候单个节点没有超过总流量,但是节点流量和却超过了总流量。那我们不妨先汇总每个服务节点的流量,并将汇总后的流量与预设的总流量进行比较,如果超过了总流量就需要进行限流。


简单来说就是我们如果集群的承载量为 1000,但是汇总出来的总流量是 1200,这个时候超了 200,就需要进行限流!那我们这个时候就需要把流量降低到 ( 1 - (200/1200) ) = 0.83,而这个 0.83 就是个单机阈值,也就是我们的限流比例,每个节点都要将当前的流量降低这个比例。


网络异常,图片无法展示
|


通过限流比例算出各自的限流阈值,然后再根据各自的限流阈值去调用上面说到的单机限流几种算法去做单机限流。因此集群环境下的限流也是以单点的限流为基础,但是在流量判定上有所不同。上面说的是一种限流思路的方向,接下来说下两种具体的限流操作。


1、Redis + Lua


这个限流策略重点在于 Lua 脚本的编写,什么是 Lua 脚本?有些同学又不淡定了~了解分布式锁的同学应该清楚可以利用 Redis + Lua  实现分布式锁。


Lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序种,从而为程序提供灵活的扩展和定制功能。


既然 Lua 是核心,那我们先理清一下 Lua的逻辑实现:


网络异常,图片无法展示
|


看着流程图自然而然代码就出来了~


网络异常,图片无法展示
|


1、首先定义两个全局变量分别用来接收 Redis 应用中传递的键和限流大小


2、在应用端传递 KEYS  是一个数据列表,在 Lua 脚本中通过索引下标方式获取数组内的值


3、在应用端传递 ARGV 参数比较灵活,可以是一个或多个独立的参数,但对应到 Lua 脚本中统一使用 ARGV 这个数组接收,获取方式也是通过数组下标获取


编辑好 Lua 脚本后,我们就可以在 Java 中愉快的使用了:


网络异常,图片无法展示
|


在具体的业务场景中,我们可以自定义一个限流注解,配合 AOP  切面达到限流的效果!


2、Nginx + Lua


使用 Nginx + Lua 的方式对系统侵入性较低!我们直接看代码


Lua部分


可以参考 OpenResty 官方给出的限流示例,稍加修改即可


网络异常,图片无法展示
|


然后我们需要修改 nginx.conf 配置文件:


http 块中添加


网络异常,图片无法展示
|


然后在需要限流的 server 块中添加:


网络异常,图片无法展示
|


当然除了以上说到的两种实现思路外,我们还可以利用现成的中间件 HystrixSentinel


Sentinel 相关阅读请空降:《吃透微服务》 - 服务容错之Sentinel


说到最后


说完了两种场景的限流,当然只是在很粗浅的层面泛泛而谈!不妨再让我以一段骚话结尾:我们在习惯单应用服务的时候,会发现其实单纯的单点限流并不难,因为我们的关注点是 1 ,由 1 进行延伸,事态往往会变得不可控,如果说单应用服务的时候我们还有很多现成的组件可以选择,但是如果要考虑到整个分布式集群的限流方式,我们往往不知所措。我们需要考虑服务节点的调用监控,日志采集,日志聚合,计算分析,限流决策判断等等许多环节,但是不必恐惧,我们换个方向想想,当你考虑的越多,不正说明你提升也会越多,最怕的不是困难与挑战,而是你原地踏步不前的无知!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
dapp预约抢单排单互助系统开发逻辑详细/功能说明/案例分析/方案规则/源码出售
Allow users to register accounts and verify their identities to ensure that the identities of participants are valid and authentic.
|
2月前
|
存储 运维 分布式计算
用马斯克五步工作法重构支付宝商家账单
支付宝中国数据团队在过去的一年里应用马斯克的五步工作法重构了有 10 年历史之久的支付宝商家账单,整体复杂度减少 60%,时效性提升 1 小时,计存成本降低 30%,理解和运维成本大幅下降。复杂度是很多问题的根源,既会增加运维的成本,又降低了支撑业务的效率。账单重构的经验表明,相当大比例的复杂度是没有必要的,我们应该致力于把复杂的事情变简单,而不是倒过来做“防御性编程”。希望本文对想要降低系统复杂度的同学或者项目有所帮助。
用马斯克五步工作法重构支付宝商家账单
|
1月前
|
存储 NoSQL 前端开发
排队免单与链动:解决引流、复购、销售额、团队稳定性不足等痛点
将排队免单与链动3+1模式转化为可运行代码涉及后端开发、前端开发、数据库设计和安全性考虑。后端使用Node.js、Express.js和MongoDB等技术栈,实现用户管理、订单处理、排队免单和链动3+1模式的核心逻辑。前端采用React框架,提供用户注册、登录、商品展示、订单支付等功能。数据库设计合理存储用户、订单、奖励和团队结构数据,确保系统安全性和高性能。开发过程中需关注法律法规和平台政策,确保系统的合规性和可持续性。
|
1月前
|
前端开发 数据库 开发者
链动 3+1 模式与排队免单 5.0 模式:解决平台引流裂变持续性难题
本文介绍了链动3+1模式与排队免单5.0模式的实现细节,涵盖前端展示、后端逻辑、数据库设计、用户验证及奖励机制等方面。通过伪代码展示了用户注册登录、滑落机制、奖励计算、订单处理、排队排序、加速排队等核心功能的实现方式,旨在为开发者提供参考。
|
4月前
|
搜索推荐
酒吧霸屏系统开发规则逻辑分析
酒吧霸屏软件通过大屏幕显示器或投影设备,实时播放最新的音乐MV、时尚的视觉特效、有趣的互动游戏等多种元素,为顾客带来沉浸式的娱乐体验。这种新型的娱乐展示方式,不仅能够增加酒吧的吸引力和活跃度,还能够提升顾客的消费体验,吸引更多的顾客前来消费。
|
4月前
|
存储 搜索推荐
阿里商旅账单系统架构设计实践问题之差错处理(平账)的主要目的问题如何解决
阿里商旅账单系统架构设计实践问题之差错处理(平账)的主要目的问题如何解决
|
6月前
|
算法 决策智能
如何用算法规划完美的相亲假期 - 小美的春节排班挑战
排班是一个经典的组合优化问题,而相亲排班可谓是它的一种别出心裁的应用。小美的挑战在于,如何在有限的8天空闲时间内,安排至少12场有效的相亲,并且满足诸如“父母严选”和通勤时间等一系列复杂的条件。
|
6月前
|
区块链
NFT卡牌链游盲盒系统开发详情规则|技术方案
随着区块链技术的迅猛发展,智能合约逐渐成为人们关注的焦点
|
存储 运维 区块链
|
机器学习/深度学习 人工智能 数据可视化
量化交易搬砖套利机器人系统开发详情方案丨swap交易所搬砖套利机器人系统开发成熟技术/规则玩法/案例详细/源码部署
 顾名思义,就是借助数量化的方法进行交易。借助数量化的方法,进行技术面分析、基本面分析、流动性分析、宏观经济分析,都可以称之为“量化分析”。依托量化分析的结果进行交易,可以称之为“量化交易”。
下一篇
无影云桌面