云原生之深入解析亿级流量架构之服务限流思路与方法

一、限流思路

① 熔断

  • 系统在设计之初就把熔断措施考虑进去,当系统出现问题时,如果短时间内无法修复,系统要自动做出判断,开启熔断开关,拒绝流量访问,避免大流量对后端的过载请求。
  • 系统也应该能够动态监测后端程序的修复情况,当程序已恢复稳定时,可以关闭熔断开关,恢复正常服务。常见的熔断组件有 Hystrix 以及阿里的 Sentinel,两种互有优缺点,可以根据业务的实际情况进行选择。

在这里插入图片描述

② 服务降级

  • 将系统的所有功能服务进行一个分级,当系统出现问题需要紧急限流时,可将不是那么重要的功能进行降级处理,停止服务,这样可以释放出更多的资源供给核心功能的去用。
  • 例如在电商平台中,如果突发流量激增,可临时将商品评论、积分等非核心功能进行降级,停止这些服务,释放出机器和 CPU 等资源来保障用户正常下单,而这些降级的功能服务可以等整个系统恢复正常后,再来启动,进行补单/补偿处理。除了功能降级以外,还可以采用不直接操作数据库,而全部读缓存、写缓存的方式作为临时降级方案。

③ 延迟处理

  • 这个模式需要在系统的前端设置一个流量缓冲池,将所有的请求全部缓冲进这个池子,不立即处理。然后后端真正的业务处理程序从这个池子中取出请求依次处理,常见的可以用队列模式来实现。
  • 这就相当于用异步的方式去减少了后端的处理压力,但是当流量较大时,后端的处理能力有限,缓冲池里的请求可能处理不及时,会有一定程度延迟。

④ 特权处理

  • 这个模式需要将用户进行分类,通过预设的分类,让系统优先处理需要高保障的用户群体,其它用户群的请求就会延迟处理或者直接不处理。

⑤ 缓存、降级、限流区别

  • 缓存,是用来增加系统吞吐量,提升访问速度提供高并发。
  • 降级,是在系统某些服务组件不可用的时候、流量暴增、资源耗尽等情况下,暂时屏蔽掉出问题的服务,继续提供降级服务,给用户尽可能的友好提示,返回兜底数据,不会影响整体业务流程,待问题解决再重新上线服务
  • 限流,是指在使用缓存和降级无效的场景。比如当达到阈值后限制接口调用频率,访问次数,库存个数等,在出现服务不可用之前,提前把服务降级,只服务好一部分用户。

二、限流的算法

① 计数器算法

  • 简单粗暴,比如指定线程池大小,指定数据库连接池大小、nginx 连接数等,这都属于计数器算法。计数器算法是限流算法里最简单也是最容易实现的一种算法。
  • 举个例子,比如规定对于 A 接口,1 分钟的访问次数不能超过 100 个,那么就可以这么做:在一开始的时候,可以设置一个计数器 counter,每当一个请求过来的时候,counter 就加 1,如果 counter 的值大于 100 并且该请求与第一个请求的间隔时间还在 1 分钟之内,那么说明请求数过多,拒绝访问;如果该请求与第一个请求的间隔时间大于 1 分钟,且 counter 的值还在限流范围内,那么就重置 counter,就是这么简单粗暴。

在这里插入图片描述

② 漏桶算法

  • 漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会超过桶可接纳的容量时直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

在这里插入图片描述

  • 这样做的好处是:
    • 削峰:有大量流量进入时,会发生溢出,从而限流保护服务可用;
    • 缓冲:不至于直接请求到服务器,缓冲压力,消费速度固定,计算性能固定。

③ 令牌桶算法

  • 令牌桶与漏桶相似,不同的是令牌桶桶中放了一些令牌,服务请求到达后,要获取令牌之后才会得到服务。举个例子,我们平时去食堂吃饭,都是在食堂内窗口前排队的,这就好比是漏桶算法,大量的人员聚集在食堂内窗口外,以一定的速度享受服务,如果涌进来的人太多,食堂装不下了,可能就有一部分人站到食堂外了,这就没有享受到食堂的服务,称之为溢出,溢出可以继续请求,也就是继续排队,那么这样有什么问题呢?
  • 如果这时候有特殊情况,如有些赶时间的志愿者啦、或者高三要高考啦,这种情况就是突发情况,如果也用漏桶算法那也得慢慢排队,这也就没有解决我们的需求,对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如下图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

在这里插入图片描述

  • 令牌桶好处就是,如果某一瞬间访问量剧增或者有突发情况,可以通过改变桶中令牌数量来改变连接数,就好比那个食堂排队吃饭的问题,如果现在不是直接去窗口排队,而是先来楼外拿饭票然后再去排队,那么有高三的学生时可以将增加饭票数量或者优先将令牌给高三的学生,这样比漏桶算法更加灵活。

三、限流的方法

① 并发限流

  • 简单来说就是设置系统阈值总的 QPS 个数,这些也挺常见的,就拿 Tomcat 来说,很多参数就是出于这个考虑。例如:配置的 acceptCount 设置响应连接数,maxConnections 设置瞬时最大连接数,maxThreads 设置最大线程数,并发限流体现在下面几个方面:
    • 限制总并发数(如数据库连接池、线程池);
    • 限制瞬时并发数(nginx 的 limit_conn 模块,用来限制瞬时并发连接数);
    • 限制时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率);
    • 其他的还有限制远程接口调用速率、限制 MQ 的消费速率;
    • 另外还可以根据网络连接数、网络流量、CPU 或内存负载等来限流。
  • 有了并发限流,就意味着在处理高并发的时候多了一种保护机制,不用担心瞬间流量导致系统挂掉或雪崩,最终做到有损服务而不是不服务;但是限流需要评估好,不能乱用,否则一些正常流量出现一些奇怪的问题而导致用户体验很差造成用户流失。

② 接口限流

  • 接口限流分为两个部分,一是限制一段时间内接口调用次数,参照前面限流算法的计数器算法,二是设置滑动时间窗口算法。
  • 接口总数:控制一段时间内接口被调用的总数量,可以参考前面的计数器算法,不再赘述。
  • 接口时间窗口:固定时间窗口算法(也就是前面提到的计数器算法)的问题是统计区间太大,限流不够精确,而且在第二个统计区间时没有考虑与前一个统计区间的关系与影响(第一个区间后半段 + 第二个区间前半段也是一分钟)。为了解决上面提到的临界问题,可以尝试把每个统计区间分为更小的统计区间,更精确的统计计数。

在这里插入图片描述

  • 在上面的例子中,假设 QPS 可以接受 100 次查询/秒,前一分钟前 40 秒访问很低,后 20 秒突增,并且这个持续了一段时间,直到第二分钟的第 40 秒才开始降下来,根据前面的计数方法,前一秒的 QPS 为 94,后一秒的 QPS 为 92,那么没有超过设定参数。但是在中间区域,QPS 达到了 142,这明显超过了允许的服务请求数目,因此固定窗口计数器不太可靠,需要滑动窗口计数器。
  • 计数器算法其实就是固定窗口算法,只是它没有对时间窗口做进一步地划分,所以只有 1 格;由此可见,当滑动窗口的格子划分的越多,也就是将秒精确到毫秒或者纳秒,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。需要注意的是,消耗的空间就越多。

四、限流实现

① guava 实现

  • 引入包:
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>28.1-jre</version>
</dependency>
  • 核心代码:
LoadingCache<Long, AtomicLong> counter = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long secend) throws Exception {// TODO Auto-generated method stubreturn new AtomicLong(0);}});
counter.get(1l).incrementAndGet();

② 令牌桶实现

  • 稳定模式(SmoothBursty:令牌生成速度恒定):
public static void main(String[] args) {// RateLimiter.create(2)每秒产生的令牌数RateLimiter limiter = RateLimiter.create(2);// limiter.acquire() 阻塞的方式获取令牌System.out.println(limiter.acquire());;try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;
}
  • RateLimiter.create(2):容量和突发量,令牌桶算法允许将一段时间内没有消费的令牌暂存到令牌桶中,用来突发消费。
  • 渐进模式(SmoothWarmingUp:令牌生成速度缓慢提升直到维持在一个稳定值):
// 平滑限流,从冷启动速率(满的)到平均消费速率的时间间隔
RateLimiter limiter = RateLimiter.create(2,1000l,TimeUnit.MILLISECONDS);
System.out.println(limiter.acquire());;
try {Thread.sleep(2000);
} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();
}
System.out.println(limiter.acquire());;
System.out.println(limiter.acquire());;
System.out.println(limiter.acquire());;
System.out.println(limiter.acquire());;System.out.println(limiter.acquire());;
System.out.println(limiter.acquire());;
  • 超时:
boolean tryAcquire = limiter.tryAcquire(Duration.ofMillis(11));
  • 在 timeout 时间内是否能够获得令牌,异步执行。

③ 分布式系统限流

  • Nginx + Lua 实现,可以使用 resty.lock 保持原子特性,请求之间不会产生锁的重入,使用 lua_shared_dict 存储数据:
local locks = require "resty.lock"local function acquire()local lock =locks:new("locks")local elapsed, err =lock:lock("limit_key") --互斥锁 保证原子特性local limit_counter =ngx.shared.limit_counter --计数器local key = "ip:" ..os.time()local limit = 5 --限流大小local current =limit_counter:get(key)if current ~= nil and current + 1> limit then --如果超出限流大小lock:unlock()return 0endif current == nil thenlimit_counter:set(key, 1, 1) --第一次需要设置过期时间,设置key的值为1--过期时间为1elselimit_counter:incr(key, 1) --第二次开始加1即可endlock:unlock()return 1
end
ngx.print(acquire())

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

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

相关文章

【Vulnhub 靶场】【VulnCMS: 1】【简单】【20210613】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/vulncms-1,710/ 靶场下载&#xff1a;https://download.vulnhub.com/vulncms/VulnCMS.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月13日 文件大小&#xff1a;1.4 GB 靶场作者&#xff1a;to…

GoogLeNet(pytorch)

亮点与创新&#xff1a; 1. 引入Inception基础结构 2. 引入PW维度变换卷积&#xff0c;启迪后续参数量的优化 3. 丢弃全连接层&#xff0c;使用平均池化层&#xff08;大大减少模型参数&#xff09; 4. 添加两个辅助分类器帮助训练&#xff08;避免梯度消失&#xff0c;用于…

NXP应用随记(五):eMios功能点阅读随记

目录 1、概念点 2、eMios功能点 2.1、eMIOS - Single Action Input Capture (SAIC) 2.2、eMIOS - Single Action Output Compare (SAOC) 2.3、eMIOS - Double Action Output Compare (DAOC) 2.4、eMIOS - Pulse/Edge Counting (PEC) – Single Shot 2.5、eMIOS - Pulse/E…

K8S(五)—命名空间与资源配额

目录 命名空间(Namespace)命令计算资源配额创建命名空间绑定一个ResourceQuota资源将命名空间和资源限制对象进行绑定尝试创建第二个 Pod查看ResourceQuota 绑定第二个ResourceQuota为命名空间配置默认的 CPU 、memory请求和限制&#xff08;1&#xff09;Pod 中所有容器都没有…

[Verilog] 设计方法和设计流程

主页&#xff1a; 元存储博客 文章目录 1. 设计方法2. 设计流程 3 Vivado软件设计流程总结 1. 设计方法 Verilog 的设计多采用自上而下的设计方法&#xff08;top-down&#xff09;。设计流程是指从一个项目开始从项目需求分析&#xff0c;架构设计&#xff0c;功能验证&#…

智能客服的应用——政务领域

#本文来源清华大学数据治理研究中心政务热线数智化发展报告 &#xff0c;如有侵权&#xff0c;请联系删除。 面对地方政务热线发展所面临的挑战&#xff0c;数智化转型已经成为了热线系统突破当前发展瓶颈、实现整体提质增效的关键手段。《意见》中也明确指出&#xff0c;政务…

ChatGPT4 Excel 高级复杂函数案例实践

案例需求: 需求中需要判断多个条件进行操作。 可以让ChatGPT来实现这样的操作。 Prompt:有一个表格B2单元格为入职日期,C2单元格为员工等级(A,B,C),D2单元格为满意度分数(1,2,3,4,5)请给入职一年以上,员工等级为A级并且满意度在3分以上的人发4000元奖金,给入…

SoloLinker第一次使用记录,解决新手拿到板子的无所适从

本文目录 一、简介二、进群获取资料2.1 需要下载资料2.2 SDK 包解压 三、SDK 编译3.1 依赖安装3.2 编译配置3.3 启动编译3.4 编译后的固件目录 四、固件烧录4.1 RV1106 驱动安装4.2 打开烧录工具4.3 进入boot 模式&#xff08;烧录模式&#xff09;4.4 烧录启动固件4.5 烧录升级…

AntDesignBlazor示例——分页查询

本示例是AntDesign Blazor的入门示例&#xff0c;在学习的同时分享出来&#xff0c;以供新手参考。 示例代码仓库&#xff1a;https://gitee.com/known/BlazorDemo 1. 学习目标 分页查询框架天气数据分页功能表格自定义分页 2. 创建分页查询框架 Table组件分页默认为前端分…

1.electron之纯原生js/jquery的桌面应用程序(基础篇)

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

Mybatis-Plus——01搭建环境、快速入门(新注解、依赖)

搭建环境、快速入门 一、准备数据库二、创建项目三、导入依赖四、配置连接数据库五、编写实体类六、编写mapper接口七、主程序加MapperScan八、测试&#xff0c;输出查询结果————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏…

《科技风》期刊发表投稿方式、收稿方向

《科技风》杂志是经国家新闻出版总署批准&#xff0c;河北省科学技术协会主管&#xff0c;河北省科技咨询服务中心主办的国内公开发行的大型综合类科技期刊。 该刊集科技性、前瞻性、创新性和专业性于一体&#xff0c;始终以“把脉科技创新 引领发展风尚”为办刊宗旨&#xff…

设计模式-模板模式

设计模式专栏 模式介绍模式特点应用场景模板模式和工厂模式区别代码示例Java实现模板模式python实现模板模式 模板模式在spring中的应用 模式介绍 模板模式是一种行为型设计模式&#xff0c;它通过将算法的骨架抽象成一个模板方法&#xff0c;将具体的操作留给子类来实现。这种…

iPhone 与三星手机:哪一款最好?

三星比苹果好吗&#xff1f;还是苹果比三星更好&#xff1f; 小米公司如何称霸全球智能手机市场&#xff1f;小米公司&#xff0c;由雷军创立于2010年&#xff0c;是一家领先的电子巨头。以其MIUI系统和互联网服务闻名&#xff0c;小米公司在全球智能手机市场中稳居前列。小米…

网络(七)路由协议以及相关配置

目录 一、路由器的工作原理 二、路由表的形成 2.1 直连网段 2.2 非直连网 2.3 路由表解析 2.3.1 查看路由表 2.3.2 解析 三、静态路由和默认路由 1. 静态路由 1.1 定义 1.2 特点 2. 默认路由 2.1 定义 2.2 特点 四、静态路由和默认路由的配置 1. 静态路由配置…

[wp]第四届江西省赣网杯网络安全大赛-web 部分wp

第四届江西省赣网杯网络安全大赛&#xff08;gwb&#xff09;线上预选赛 因为学业繁忙 只玩了1小时&#xff0c;后续看看补一下这些 2023gwb-web1 九宫格拼图 2023gwb-web2 $filexxx;extract($_GET);if(isset($fun)){$contenttrim(file_get_contents($file));if($fun!&…

MLX:苹果 专为统一内存架构(UMA) 设计的机器学习框架

“晨兴理荒秽&#xff0c;带月荷锄归” 夜深闻讯&#xff0c;有点兴奋&#xff5e; 苹果为 UMA 设计的深度学习框架真的来了 统一内存架构 得益于 CPU 与 GPU 内存的共享&#xff0c;同时与 MacOS 和 M 芯片 交相辉映&#xff0c;在效率上&#xff0c;实现对其他框架的降维打…

uniapp之屏幕右侧出现滚动条去掉、隐藏、删除【好用!】

目录 问题解决大佬地址最后 问题 解决 在最外层view上加上class“content”;输入以下样式。注意&#xff1a;两个都必须存在在生效。 .content {/* 跟屏幕高度一样高,不管view中有没有内容,都撑开屏幕高的高度 */height: 100vh; overflow: auto; } .content::-webkit-scrollb…

【JavaWeb】往浏览器打印一个hello world

上集:建一个web项目 第一步&#xff1a;建好Servlet类的文件 右键src&#xff0c;建一个class 就行 第二步&#xff1a;编代码 可以直接复制粘贴 用来测试的类 import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; //↓是注解&#xff0…

Java 基础学习(十一)File类与I/O操作

1 File类 1.1 File类概述 1.1.1 什么是File类 File是java.io包下作为文件和目录的类。File类定义了一些与平台无关的方法来操作文件&#xff0c;通过调用File类中的方法可以得到文件和目录的描述信息&#xff0c;包括名称、所在路径、读写性和长度等&#xff0c;还可以对文件…