手写RPC-令牌桶限流算法实现,以及常见限流算法

为什么需要服务限流、降级

        分布式架构下,不同服务之间频繁调用,对于某个具体的服务而言,可能会面临高并发场景。在这样的情况下,提供服务的每个服务节点就都可能由于访问量过大而引起一系列问题,比如业务处理耗时过长、CPU飘高、频繁Full GC以及服务进程直接宕机等。但是在生产环境中,要保证服务的稳定性和高可用性,这时就需要业务进行自我保护,从而保证在高访问量、高并发的场 景下,应用系统依然稳定,服务依然高可用。 我们再次借助 RPC 框架来分析,RPC 调用包括服务端和调用端。对于服务端来讲一般实现限流、降级算法;对于调用方来说一般实现熔断算法。

        加入服务调用方调用某个多服务节点的其中一个实现如下:

        此时对于特定的服务节点来说,可能存在多个不同调用者的调用,从而使得节点接收服务量超过其最大承载力。此时如果不采取某种策略进行调整,对应的具体服务可能由于过多调用而崩溃,无法对于提供服务能力。限流算法可以很好解决以上问题:当调用端发送请求过来时,服务端在执行业务逻辑之前先执行限流逻辑,如果发现访问量过大并 且超出了限流的阈值,就让服务端直接抛回给调用端一个限流异常,否则就执行正常的业务逻辑。

常见限流算法实现有哪些

        常见限流算法实现固定窗口计数器法、滑动窗口计数器法、漏桶算法、令牌桶算法。

令牌桶算法

        令牌桶是一个限流容器,容器有最大容量(最大处理能力),每秒或每100ms产生一个令牌(具体取决于业务实现以及机器的最大处理能力),当容器中令牌数量达到最大容量时,令牌数量此时不会增加,只有当请求过来时,才会使得令牌数量减少(只有获取到令牌的请求才会执行业务逻辑),才会不断的以一定的速率生成令牌。

         令牌桶限流范围:

        假设令牌桶最大容量为n ,每秒产生 r 个令牌
        平均速率:则随着时间推延,处理请求的平均速率越来越趋近于每秒处理r 个请求,说明令牌桶算法可以控制平均速率
        瞬时速率:如果在一瞬间有很多请求进来,此时来不及产生令牌,则在一瞬间最多只有n 个请求能获取到令牌执行业务逻辑,所以令牌桶算
法也可以控制瞬时速率
        在这里提下漏桶,漏桶由于出水量固定,所以无法应对突然的流量爆发访问,也就是没有保证瞬时速率的功能,但是可以保证平均速率

漏桶算法

        漏桶算法强调把服务调用比作水滴,当有调用(任务)发生时,将其加入桶中,随后采用某种机制(如:定时器)以一定的速率从桶中取出任务进行处理(相当于桶以一定的速率不断在漏水,也就是【漏桶】算法)

        漏桶算法的实现可以借助于Redis实现的消息队列和定时任务。

优点:

  • 实现简单、易于理解。
  • 可以控制限流速率,避免网络拥塞和系统过载。

缺点:

  • 无法应对突然激增的流量,因为只能以固定的速率处理请求,对系统资源利用不够友好。
  • 桶流入水(发请求)的速率如果一直大于桶流出水(处理请求)的速率的话,那么桶会一直是满的,一部分新的请求会被丢弃,导致服务质量下降。

        在实际业务场景中一般不适用漏桶算法,基于Redis实现的消息队列,其容量非常大,可以使用,其可以理解为容量无线的桶,在一定程度下不会发生消息丢失。

固定窗口计数器法

固定窗口其实就是时间窗口,其原理是将时间划分为固定大小的窗口,在每个窗口内限制请求的数量或速率,即固定窗口计数器算法规定了系统单位时间处理的请求数量。

假如我们规定系统中某个接口 1 分钟只能被访问 33 次的话,使用固定窗口计数器算法的实现思路如下:

  • 将时间划分固定大小窗口,这里是 1 分钟一个窗口。
  • 给定一个变量 counter 来记录当前接口处理的请求数量,初始值为 0(代表接口当前 1 分钟内还未处理请求)。
  • 1 分钟之内每处理一个请求之后就将 counter+1 ,当 counter=33 之后(也就是说在这 1 分钟内接口已经被访问 33 次的话),后续的请求就会被全部拒绝。
  • 等到 1 分钟结束后,将 counter 重置 0,重新开始计数。

优点:实现简单,易于理解。

缺点:

  • 限流不够平滑。例如,我们限制某个接口每分钟只能访问 30 次,假设前 30 秒就有 30 个请求到达的话,那后续 30 秒将无法处理请求,这是不可取的,用户体验极差!
  • 无法保证限流速率,因而无法应对突然激增的流量。

        对于固定窗口计数器算法而言,存在非常严重的一个问题就是临界问题: 假设1min内服务器的负载能力为100,因此一个周期的访问量限制在100,然后在第一个周期的最后5s和下一个周期的开始5s时间段内,分别涌入了100的访问量,虽然没有超过每个周期的限制量,但是整体上10s内已经达到了200的访问量,远超服务器的承载能力。

滑动窗口计数器法

滑动窗口计数器算法 算的上是固定窗口计数器算法的升级版,限流的颗粒度更小。

滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:它把时间以一定比例分片

例如我们的接口限流每分钟处理 60 个请求,我们可以把 1 分钟分为 60 个窗口。每隔 1 秒移动一次,每个窗口一秒只能处理不大于 60(请求数)/60(窗口数) 的请求, 如果当前窗口的请求计数总和超过了限制的数量的话就不再处理其他请求。

        如下图,假设时间周期为1min,将1min再分为2个小周期,统计每个小周期的访问数量,则可以看到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,超过100的访问则被限流掉了 

        很显然, 当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。

优点:

  • 相比于固定窗口算法,滑动窗口计数器算法可以应对突然激增的流量。
  • 相比于固定窗口算法,滑动窗口计数器算法的颗粒度更小,可以提供更精确的限流控制。

缺点:

  • 与固定窗口计数器算法类似,滑动窗口计数器算法依然存在限流不够平滑的问题。
  • 相比较于固定窗口计数器算法,滑动窗口计数器算法实现和理解起来更复杂一些。

四种限流算法的比较 

令牌桶限流算法在RPC服务中的应用

        为了实现令牌桶算法,我们并不需要严格按照算法的定义多长时间产生一个令牌,我们只需要当桶中无令牌时,根据(当前系统时间 - 上次令牌生成时间之间的差值 )x 令牌生成速率,便可以得到这段时间应该生成的令牌总数,随后取其和容量CAPACITY的最小值即可。

        代码实现:

package main.version4.v1.server.rateLimit.impl;import lombok.extern.slf4j.Slf4j;
import main.version4.v1.server.rateLimit.RateLimit;/*** 令牌桶限流算法实现* CAPACITY为令牌桶的最大容量,curCAPACITY为当前令牌桶中令牌的数量,timeStamp为上一次请求获取令牌的时间,* 我们在这里并没有实现计数器每秒产生多少令牌放入容器中,而是记住了上一次请求到来的时间,和这次请求之间的时间差值* 进一步根据RATE计算出这段时间能够产生的令牌数量,取min(CAPACITY, CURCAPAITY)。*/
@Slf4j
public class TokenBucketRateLimitImpl implements RateLimit {// 令牌产生速率(单位ms)private static int RATE;// 桶容量private static int CAPACITY;// 当前桶容量private volatile static int curCapacity;// 时间戳private volatile long timeStamp = System.currentTimeMillis();public TokenBucketRateLimitImpl(int rate, int capacity){RATE = rate;CAPACITY = capacity;curCapacity = CAPACITY;}@Overridepublic synchronized boolean getToken() {// 如果当前桶有剩余,直接返回if(curCapacity > 0){curCapacity--;return true;}// 如果桶无剩余long currentTime = System.currentTimeMillis();// 如果距离上一次的请求的时间大于RATE的时间if(currentTime - timeStamp >= RATE){//计算这段时间间隔中生成的令牌,如果>2,桶容量加上(计算的令牌-1)//如果==1,就不做操作(因为这一次操作要消耗一个令牌)if((currentTime - timeStamp) / RATE >= 2){curCapacity += (int) (currentTime - timeStamp) / RATE - 1;}//保持桶内令牌容量<=CAPACITYif(curCapacity > CAPACITY){curCapacity = CAPACITY;}//刷新时间戳为本次请求timeStamp = currentTime;return true;}return false;}
}

参考资料

 服务限流详解 | JavaGuide

常用4种限流算法介绍及比较-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/49578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware三种网络模式---巨细

文章目录 目录 ‘一.网络模式概述 二.桥接模式 二.NAT模式 三.仅主机模式 四.案例演示 防火墙配置&#xff1a; 虚拟电脑配置 前言 本文主要介绍VMware的三种网络模式 ‘一.网络模式概述 VMware中分为三种网络模式&#xff1a; 桥接模式&#xff1a;默认与宿主机VMnet0绑…

基于Java中的SSM框架实现商店积分管理系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现商店积分管理系统演示 摘要 随着时代的发展&#xff0c;信息化的管理手段已被普遍应用于企业的日常运作中。在当今竞争激烈的市场中&#xff0c;消费者的需求量日益增长&#xff0c;而商品信息的管理也变得越来越复杂&#xff0c;因此&#xff0c;实施…

14. Hibernate 一对多双向关联映射

1. 前言 本节课程和大家一起聊聊一对多关联映射。通过本节课程&#xff0c;你将了解到&#xff1a; 如何实现一对多关联映射&#xff1b; 如何实现双向一对多关联映射&#xff1b; 关联映射中的级联操作。 2. 一对多关联映射 关系型数据库中表与表中的数据存在一对多&…

深入理解Linux网络(八):内核如何发送网络包

深入理解Linux网络&#xff08;八&#xff09;&#xff1a;内核如何发送网络包 一、总览二、网卡启动准备三、ACCEPT 创建新 SOCKET四、开始发送数据send 系统调⽤实现传输层处理传输层拷贝传输层发送 网络层发送原理邻居⼦系统网络设备子系统软中断调度igb网卡驱动发送发送完成…

Python 实现PDF和TIFF图像之间的相互转换

PDF是数据文档管理领域常用格式之一&#xff0c;主要用于存储和共享包含文本、图像、表格、链接等的复杂文档。而TIFF&#xff08;Tagged Image File Format&#xff09;常见于图像处理领域&#xff0c;主要用于高质量的图像文件存储。 在实际应用中&#xff0c;我们可能有时需…

wefwefwe

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

在 ArkTS 中集成 C 语言模块来管理文件描述符

文章目录 前言ArkTS模块C语言模块C模块代码 总结 前言 在现代开发中&#xff0c;尤其是在处理文件操作时&#xff0c;使用文件描述符&#xff08;fd&#xff09;是一种常见的方法。ArkTS提供了一种强大的方式来与底层C代码交互&#xff0c;使我们能够利用C语言的性能优势来管理…

dsa加训

refs: OI Wiki - OI Wiki (oi-wiki.org) 1. 枚举 POJ 2811 熄灯问题 refs : OpenJudge - 2811:熄灯问题 如果要枚举每个灯开或者不开的情况&#xff0c;总计2^30种情况&#xff0c;显然T。 不过我们可以发现&#xff1a;若第i行的某个灯亮了&#xff0c;那么有且仅有第i行和第…

Win10使用VS Code远程连接Ubuntu服务器时遇到SSH公钥错误的解决方案

在使用Windows 10上的Visual Studio Code&#xff08;VS Code&#xff09;远程连接Ubuntu 20.04服务器时&#xff0c;遇到了以下错误&#xff1a; 错误的原因 这个错误消息表明&#xff0c;SSH 客户端检测到远程主机的 ECDSA 公钥已更改。可能是由于以下原因之一&#xff1a…

组蛋白乳酸化 | 调控蛋白Writers、Erasers和Readers

组蛋白修饰的调控可以被归类为三类蛋白&#xff1a;Writers&#xff08;写入者&#xff09;、Erasers&#xff08;擦除者&#xff09;和Readers&#xff08;读取者&#xff09;。Writers是负责在组蛋白上添加修饰基团的蛋白&#xff0c;包括乙酰化、甲基化等修饰。Erasers则是负…

学习记录——day17 数据结构 队列 链式队列

队列介绍 1、队列也是操作受限的线性表:所有操作只能在端点处进行&#xff0c;其删除和插入必须在不同端进行 2、允许插入操作的一端称为队尾&#xff0c;允许删除操作的一端称为队头 3、特点:先进先出(FIFO) 4、分类&#xff1a; 顺序存储的栈称为顺序栈 链式存储的队列&a…

IP数据报结构详解:从基础到进阶

目录 IP数据报的格式 IP数据报首部的固定部分 IP数据报首部的可变部分 实例分析&#xff1a;数据报的分片 生存时间&#xff08;TTL&#xff09;与协议 首部检验和 总结 在网络通信中&#xff0c;IP数据报是至关重要的基本单元。本文将带您深入了解IP数据报的格式及其各个…

【Python】使用抓包Fiddler软件,网络查询 遇到“您的连接不是私密连接”的问题的解决方法

使用Fiddler抓包软件很久&#xff0c;忽然发现网络使用有问题&#xff0c;一点开浏览器就会出现类似下面的页面&#xff1a; 检查了网络情况发现不是网络的问题&#xff0c;也排除了封号的可能。发现只要把抓包软件Fiddler关闭以后就没问题了&#xff0c;就知道问题是出在软件…

国产光电耦合器2024年的机遇与挑战

随着科技的飞速发展&#xff0c;2024年对于国产光电耦合器行业来说&#xff0c;无疑是充满机遇与挑战的一年。本文将深入探讨该行业在技术创新、市场竞争、5G时代、新兴应用领域和国际市场拓展方面的现状及未来前景。 技术创新的黄金期 物联网和人工智能技术的迅猛发展&#x…

Java之集合底层-数据结构

Java集合之数据结构 1 概述 数据结构是计算机科学中研究数据组织、存储和操作的一门学科。它涉及了如何组织和存储数据以及如何设计和实现不同的数据操作算法和技术。常见的据结构有线性数据结构&#xff08;含数组、链表、栈和队列等&#xff09;&#xff0c;非线性数据结构…

睿考网:中级会计师考试各科分值是多少?

中级会计考试是会计领域的一个重要考核&#xff0c;考试题型包含多种&#xff1a;单选题、多选题、判断题、计算分析题和综合题。这些不同的题型不仅覆盖了广泛的知识点&#xff0c;而且各自的评分标准也是不一样的。为了帮助大家更全面地掌握各类题型的得分规则&#xff0c;睿…

解决:Nacos无法获取远程配置数据,导致项目启动各种配置异常

解决&#xff1a;Nacos无法获取远程配置数据&#xff0c;导致项目启动各种配置异常 一问题描述&#xff1a;1.项目pom依赖版本&#xff1a;2.bootstrap.yml配置信息3.远程配置&#xff1a;默认public命名空间4.启动报异常&#xff0c;显示没有配置数据源&#xff0c;实际远程已…

韦东山嵌入式linux系列-查询方式的按键驱动程序_编写框架

1 LED 驱动回顾 对于 LED&#xff0c; APP 调用 open 函数导致驱动程序的 led_open 函数被调用。在里面&#xff0c;把 GPIO 配置为输出引脚。安装驱动程序后并不意味着会使用对应的硬件&#xff0c;而 APP 要使用对应的硬件&#xff0c;必须先调用 open 函数。所以建议在驱动…

Adobe Character Animator (CH) 安装包软件下载

目录 一、软件简介 二、下载与安装 1. 下载 2. 安装 三、注意事项 1. 硬件要求 2. 兼容性 四、功能介绍 1. 实时面部捕捉 2. 实时语音同步 3. 动作捕捉 五、快捷键操作 CH 提供了一系列快捷键以方便用户快速操作。以下是一些常用的快捷键&#xff1a; 一、软件简介…

django电商用户消费数据分析系统-计算机毕业设计源码20891

摘 要 随着电子商务的快速发展&#xff0c;电商平台积累了大量的用户消费数据。为了更好地理解用户行为、优化商品结构和提升用户体验&#xff0c;本文设计并实现了一个基于Django框架的电商用户消费数据分析系统。 该系统包含后台首页、系统用户&#xff08;管理员&#xf…