分布式限流的主流方案

本文已收录至我的个人网站:程序员波特,主要记录Java相关技术系列教程,共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源,让想要学习的你,不再迷茫。

常见的分布式限流方案

前面我们了解了什么是分布式限流,这一节我们就来细数一下分布式限流都有哪些常见方案。

Guava乱入

说起Guava大家一定不陌生,它是Google出品的一款工具包(com.google.guava),我们经常用它做一些集合操作比如Lists.newArrayList(),它最早源于2007年的"Google Collections Library"项目。Guava不甘于将自己平凡的一生都耗费在Collctions上面,于是乎它开始了转型,慢慢扩展了自己在Java领域的影响力,从反射工具函数式编程、安全验证、数学运算等等方面,都提供了响应的工具包。

在限流这个领域中,Guava也贡献了一份绵薄之力,在其多线程模块下提供了以RateLimiter为首的几个限流支持类。我们前面提到了Guava是一个客户端组件,也就是说它的作用范围仅限于““当前” 这台服务器,不能对集群以内的其他服务器施加流量控制。

打个比方,目前我有2台服务器[Server1,Server 2],这两台服务器都部署了一个登陆服务,假如我希望对这两台机器的流量进行控制 ,比如将两台机器的访问量总和控制在每秒20以内,如果用Guava 来做,只能独立控制每台机器的访问量<=10。

尽管Guava不是面对分布式系统的解决方案,但是其作为一个简单轻量级的客户端限流组件,非常适合来讲解限流算法,稍后的章节我们将使用Guava做一个热身,让大家对限流的算法理论有了大致的了解以后,再学习其他的分布式限流方案。

网关层限流

在整个分布式系统中,如果有这么一个“一夫当关,万夫莫开”的角色,非网关层莫属。服务网关,作为整个分布式链路中的第一道关卡,承接了所有用户来访请求.

网关层限流的架构考量

漏斗是个好东西,不仅可以用来打香油,还可以应用在很多系统设计的领域,我们将系统流量的分布层次抽象成一个简单的漏斗模型来看

上面是一个最普通的流量模型,从上到下的路径依次是:

  1. 用户流量从网关层转发到后台服务
  2. 后台服务承接流量,调用缓存获取数据
  3. 缓存中无数据,则访问数据库

为什么说它是一个漏斗模型,因为流量自上而下是逐层递减的,在网关层聚集了最多最密集的用户访问请求,其次是后台服务。然后经过后台服务的验证逻辑之后,刷掉了一部分错误请求,剩下的请求落在缓存,上,如果缓存中没有数据才会请求漏斗最下方的数据库因此数据库层面请求数量最小(相比较其他组件来说数据库往往是并发量能力最差的一环,阿里系的MySQL即便经过了大量改造单机并发量也无法和RedisKafka之类的组件相比)

如果在上面这个漏斗模型中做流量限制,大家觉得在哪个环节最合适?五四三二一,揭晓答案-网关层,它首当其冲对不对?因为它是整个访问链路的源头,是所有流量途径的第一站。 目前主流的网关层有以软件为代表的Nginx,还有Spring Cloud中的GatewayZuul这类网关层组件,也有以硬件+软件为代表的F5 (F5价钱 贵到你怀疑人生)

中间件限流

开发团队的年轻人们都是很有控制欲的,网关层限流对他们来说貌似有点不那么受控,毕竟不像改个程序代码那么简单,搞不好还要求爷爷告奶奶去让运维团队或者NetOpts团队去操作。我们有没有一个解决方案,将限流下沉到业务层来,让开发团队可以自行控制?我们来思考一下如何在分布式环境中引入服务层限流。

对于分布式环境来说,无非是需要一个类似中心节点的地方存储限流数据。打个比方,如果我希望控制接口的访问速率为每秒100个请求,那么我就需要将当前1s内已经接收到的请求的数量保存在某个地方,并且可以让集群环境中所有节点都能访问。那我们可以用什么技术来存储这个临时数据呢?这个场景天然适合我们的中间件大显神威!而且还得需要支持超高并发的中间件,谁能堪此重任?

一并中间件这下起劲儿了,纷纷表示“选我选我选我”。数据库行不行?不行,并发量不够。Message Queue行不行?好像MQ的运作模式不太适合这个场景,而且并发量也就差强人意。Kafka行不行,嗯,并发量杠杠的,是个Option。那Redis呢?OMG,憋说话就你了!理由这就给足你!

Redis简直就是为服务端限流量身打造的利器。利用Redis过期时间特性,我们可以轻松设置限流的时间跨度(比如每秒10个请求,或者每10秒10个请求)。同时Redis还有一个特殊技能-脚本编程,我们可以将限流逻辑编写成一段脚本植入到Redis中,这样就将限流的重任从服务层完全剥离出来,同时Redis强大的并发量特性以及高可用集群架构也可以很好的支持庞大集群的限流访问。

至于我们说到的Redis执行脚本的功能,可能很多同学用了多年Redis,至今还不知道有这么个隐藏技能。这回我就不剧透了,保留一点神秘感,在本章最后将介绍一种可以和Redis完美搭配的脚本语言,并且手把手教大家实现基于Redis的限流。

限流组件

除了上面介绍的几种方式以外,目前也有一些开源组件提供了类似的功能,比如Sentinel就是 -个不错的选择。Sentinel是阿里 出品的开源组件,并且包含在了Spring Cloud Alibaba组件库中。

从架构维度考虑限流设计

在真实的大型项目里,不会只使用一种限流手段,往往是几种方式互相搭配使用,让限流策略有-种层次感,达到资源的最大使用率在这个过程中,限流策略的设计也可以参考前面提到的漏斗模型上宽下紧,漏斗不同部位的限流方案设计要尽量关注当前组件的高可用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法实验】实验1

实验1-1 斐波那契数 【问题描述】斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。 定义&#xff1a;F(0) 0, F(1) 1, F(n) F(n-1) F(n-2) 其中n>1 要求计…

11.云原生存储之TIDB

云原生专栏大纲 文章目录 为什么使用TIDB后端视角运维视角基础架构视角 TiDB Operator 简介软件版本要求部署tidbTIDB工具helm常用命令TIDB学习推荐资料 为什么使用TIDB 从后端视角、运维视角和基础架构视角来看&#xff0c;使用 TiDB 作为数据库系统可以获得分布式架构、高可…

Unity 踩坑记录 项目启动时获取目标子UI的位置相同

检查是否使用了 LayoutGroup ui控件控制位置 因为项目刚启动的时候 控件还没有工作所以他们都挤在一个位置 延迟两秒钟获取 就可以获取到 子UI 的正确坐标位置

【HarmonyOS4.0】第七篇-ArkUI系统组件(二)

鸿蒙开发系统组件详细剖析 五、进度条组件 进度条也是UI开发最常用的组件之一&#xff0c;ArkUI开发框架提供了两种类型的进度条&#xff1a; Progress 和LoadingProgress &#xff0c;前者可以精准指定进度&#xff0c;后者表示正在加载的状态&#xff0c;我们接下来对它们分…

对Transformer的理解。

要理解Transformer&#xff0c;需要先理解注意力机制&#xff0c;下面大部分内容来自台大教授李宏毅老师讲课资料。 注意力机制 之前使用的MLP&#xff0c;CNN&#xff0c;RNN模型可以解决一些简单序列问题&#xff0c;但当序列长度太长容易失去效果&#xff0c;原因是看了新…

python 列表的高级应用

当前版本&#xff1a; Python 3.8.4 简介 列表&#xff08;list&#xff09;是Python编程语言中的基本数据类型之一&#xff0c;也是一个非常重要的通用序列。在其它编程语言中&#xff0c;它们通常被称为“数组”。可以存储多个元素&#xff0c;包括数字、字符串、甚至其他列…

python 字符串的详细处理方法

当前版本&#xff1a; Python 3.8.4 简介 字符串是由字符组成的序列&#xff0c;可以用单引号、双引号或三引号&#xff08;单引号或双引号的连续使用&#xff09;括起来。一般用来表示和处理文本信息&#xff0c;可以是字母、数字、标点符号以及其他特殊字符&#xff0c;用于…

力扣每日一练(24-1-14)

做过类似的题&#xff0c;一眼就是双指针&#xff0c;刚好也就是题解。 if not nums:return 0p1 0 for p2 in range(1, len(nums)):if nums[p2] ! nums[p1]:p1 1nums[p1] nums[p2]return p1 1 根据规律&#xff0c;重复的数字必定相连&#xff0c;那么只要下一个数字与上一…

WeNet2.0:提高端到端ASR的生产力

摘要 最近&#xff0c;我们提供了 WeNet [1]&#xff0c;这是一个面向生产&#xff08;工业生产环境需求&#xff09;的端到端语音识别工具包&#xff0c;在单个模型中&#xff0c;它引入了统一的两次two-pass (U2) 框架和内置运行时&#xff08;built-in runtime&#xff09;…

SpringCloud.04.熔断器Hystrix( Spring Cloud Alibaba 熔断(Sentinel))

目录 熔断器概述 使用Sentinel工具 什么是Sentinel 微服务集成Sentinel 配置provider文件&#xff0c;在里面加入有关控制台的配置 实现一个接口的限流 基本概念 重要功能 Sentinel规则 流控规则 简单配置 配置流控模式 配置流控效果 降级规则 SentinelResource…

Linux/Traverxec

Enumeration nmap 使用nmap快速扫描目标&#xff0c;发现对外开放了22和80&#xff0c;第一个问题就是问80端口运行的是什么服务&#xff0c;针对这两个端口扫描对应的详细信息后就能得到答案 Nostromo 从nmap的扫描结果可以看到&#xff0c;目标开启了80端口&#xff0c;且…

一二三应用开发平台文件处理设计与实现系列之5——MinIO技术预研

背景 上篇介绍了文件读写框架设计与实现&#xff0c;同时顺便说明了本地磁盘存储模式的实现模式。 今天来说下基于文件读写框架&#xff0c;如何集成对象存储组件minio&#xff0c;集成之前&#xff0c;需要对minio进行必要的了解&#xff0c;本篇是minio的技术预研。 minio简…

Python - 深夜数据结构与算法之 AVL 树 红黑树

目录 一.引言 二.高级树的简介 1.树 2.二叉树 3.二叉搜索树 4.平衡二叉树 三.AVL 树 ◆ 插入节点 ◆ 左旋 ◆ 右旋 ◆ 左右旋 ◆ 右左旋 ◆ 一般形式 ◆ 实际操作 ◆ 总结 四.红黑树 ◆ 概念 ◆ 示例 ◆ 对比 五.总结 一.引言 前面我们介绍了二叉树、二叉…

论文阅读 Self-Supervised Burst Super-Resolution

这是一篇 ICCV 2023 的文章&#xff0c;主要介绍的是用自监督的方式进行多帧超分的学习 Abstract 这篇文章介绍了一种基于自监督的学习方式来进行多帧超分的任务&#xff0c;这种方法只需要原始的带噪的低分辨率的图。它不需要利用模拟退化的方法来构造数据&#xff0c;而且模…

爬虫验证码分析

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 本文只做简单的验证码分析&#xff0c;不涉及扣代码等逆向 一、常见得验证码平台 易盾&#xff1a;https://dun.163.com/pr…

重学Java 5 idea详细使用和运算符

慢点跑&#xff0c;前面的路不好走 ——24.1.14 一、IDEA的使用 1.idea的介绍 1.概述&#xff1a;开发工具 2.特点&#xff1a; a、idea是java写的&#xff0c;所以本地上必须有正确的jdk环境 b、idea自动保存 c、不用我们打开dos命令窗口执行javac和java命令 d、idea有强大的…

数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)一

第四部分、字符串&#xff0c;数据结构中的串存储结构 串存储结构&#xff0c;也就是存储字符串的数据结构。 很明显&#xff0c;字符串之间的逻辑关系也是“一对一”&#xff0c;用线性表的思维不难想出&#xff0c;串存储结构也有顺序存储和链式存储。 提到字符串&#xff…

Python 自学(八) 之模块

目录 1. import语句导入模块 P206 2. from ... import 语句导入模块 P207 3. 模块的搜索目录 sys.path P209 4. 以主程序的形式执行 __name__ P212 5. python中的包 P213 1. import语句导入模块 P206 同一目录下&…

【MATLAB】 SSA奇异谱分析信号分解算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 SSA奇异谱分析&#xff08;Singular Spectrum Analysis&#xff09;是一种处理非线性时间序列数据的方法&#xff0c;可以对时间序列进行分析和预测。 它基于构造在时间序列上的特定矩阵的奇异值分解&#…

12AOP面向切面编程/GoF之代理模式

先看一个例子&#xff1a; 声明一个接口&#xff1a; // - * / 运算的标准接口! public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }实现该接口&#xff1a; package com.sunsplanter.prox…