分布式系统架构5:限流设计模式
wptr33 2025-01-21 21:57 29 浏览
这是小卷对分布式系统架构学习的第5篇文章,今天来学习限流器和限流设计模式
1.为什么要限流?
任何一个系统的运算、存储、网络资源都不是无限的,当系统资源不足以支撑外部超过预期的突发流量时,就应该要有取舍,建立面对超额流量自我保护的机制,而这个机制就是微服务中常说的“限流”
2.四种限流设计模式
说到限流,大家直接的想法就是Sentinel,但是Sentinel限流的原理可能很多人没去深入理解,或者限流到底是怎么做的?具体如何进行限流,业界内也有一些常见设计模式。
2.1流量计数器模式
流量计数器是一种最简单的限流方式,通过记录固定时间窗口内的请求次数来判断是否达到限流阈值。如果请求次数超过限制值,则拒绝后续请求。
实现方式:
- 将时间划分为固定的时间窗口(如 1 秒、1 分钟)。
- 每个窗口维护一个计数器,记录当前时间窗口内的请求次数。
- 如果计数器值超过限流阈值,直接拒绝请求;否则增加计数器。
固定窗口边界问题:
- 在窗口边界的两端,可能存在短时间内超量请求的“临界问题”
比如场景设定:一秒内的TPS大于80时,就限流。
存在问题:即使每一秒的统计流量都没有超过 80 TPS,也不能说明系统没有遇到过大于 80 TPS 的流量压力。比如说系统在连续2秒内都收到60TPS的请求,但是请求发生的时间分别在第1秒的后0.5秒,以及第2秒的前0.5秒。这样系统实际曾在1秒内发生超过80 TPS的请求。
- 即使连续若干秒统计流量超过阈值,也不能说明流量压力一定超过系统承受能力
假设 10 秒的时间片段中,前 3 秒的 TPS 平均值到了 100,而后 7 秒的平均值是 30 左右,此时系统是否能够处理完这些请求而不产生超时失败?答案是可以的
存在缺陷:造成上面2个问题得原因是流量计数器模式是对时间点进行离散的统计
2.2滑动窗口模式
概念:时间轴上,一个固定大小的窗口随时间平滑滚动。任何时刻,静态地通过窗口内观察到的信息,都等价于一段长度与窗口大小相等的信息。主要是通过记录多个较小时间窗口(子窗口)的请求次数,实现更精细化的限流控制。
假设:准备观察的时间片段为 10 秒,以 1 秒作为统计精度,那可以得到一个长度为 10 的数组。设定限流阈值是最近 10 秒内收到的请求不超过 500 个,那么就需要统计10个子数组的请求总数,是否超过阈值。
优点:
- 解决了固定窗口边界问题
缺点:
- 只适用于否决式限流,超过阈值的流量就必须失败
2.3漏桶模式
漏桶可以简单的理解:小学水池应用题,一个水池,每秒以 X 升速度注水,同时又以 Y 升速度出水,问水池啥时候装满。
概念:将请求视为流入漏桶的水,漏桶以固定速率“漏水”。当请求流量超过漏桶的处理能力时,多余的请求会被丢弃或排队。其核心思想是平滑请求流量
实现方式:
- 维护一个队列(或计数器),用来模拟漏桶。
- 新请求到来时,将请求放入桶中。
- 按固定速率处理桶中的请求。
- 如果桶已满,则拒绝新请求。
缺点:
- 比较难确定桶的大小和水流出的速度
2.4令牌桶算法
和漏桶一样是基于缓冲区的限流算法,简单理解就是去银行办事时在排队机号取号的场景。
概念:通过固定速率向桶中添加令牌,请求到来时需要先消耗令牌才能被处理。如果桶中没有足够的令牌,请求会被拒绝。与漏桶算法不同,令牌桶允许一定的突发流量。
实现方式
- 维护一个桶,桶中存储令牌。
- 按固定速率(比如限流是1秒100次请求,那么间隔10ms时间放入令牌)向桶中添加令牌,直到桶满为止。
- 请求到来时从桶中取出令牌,如果没有令牌就马上失败或者进入降级逻辑。
实际开发的时候,不需要专门做放令牌到桶里这件事,只需要在获取令牌前,比较一下时间戳与当前时间,就能算出需要放入多少令牌,下面是示例代码:
private long lastTime = System.currentTimeMillis();
private int tokens = 0; // 当前令牌数
private static final int LIMIT = 100; // 桶容量
private static final int REFILL_RATE = 10; // 令牌添加速率(令牌/秒)
public synchronized boolean tryAcquire() {
long now = System.currentTimeMillis();
// 添加令牌
tokens = Math.min(LIMIT, tokens + (int) ((now - lastTime) / 1000) * REFILL_RATE);
lastTime = now;
if (tokens > 0) {
tokens--;
return true;
}
return false;
}
3.分布式限流
上面介绍的4种限流算法都只适用于单机限流,或者把系统当做整体来限流。实际应用中仍然需要精细的每个服务的限流。
概念:过将限流逻辑分散到多个节点,同时使用一致性算法保证全局限流的一致性。它结合了本地限流和集中式限流的优点。
实现方式
- 基于 Redis + Lua 脚本使用 Redis 脚本实现分布式限流,在 Redis 中存储全局的请求计数器
- 基于一致性算法使用分布式一致性算法(如 Raft、Paxos)维护全局流量状态
- 分布式网关通过 API 网关(如 Kong、Nginx、Spring Cloud Gateway)实现流量的统一调度和限流。
缺点:
- 实现复杂度高,且网络通信和一致性操作带来额外延迟。当流量大时,限流本身会降低系统处理能力
总结
今天学习了4种限流设计模式:流量计数器模式、滑动窗口模式、漏桶模式、令牌桶模式,后面2种都是基于缓冲区的限流算法。简单了解了下分布式限流的概念。限流本身是有代价的,实际开发中需要权衡方案的代价和收益。后续有时间补充Sentinel的限流原理和其中用了哪些设计模式。
相关推荐
- MySQL进阶五之自动读写分离mysql-proxy
-
自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...
- 3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?
-
引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...
- 一文由浅入深带你完全掌握MySQL的锁机制原理与应用
-
本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...
- 验证Mysql中联合索引的最左匹配原则
-
后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...
- MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)
-
目录1.索引基础...
- 你会看 MySQL 的执行计划(EXPLAIN)吗?
-
SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...
- MySQL 从入门到精通(四)之索引结构
-
索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...
- mysql总结——面试中最常问到的知识点
-
mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...
- mysql总结——面试中最常问到的知识点(2)
-
首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...
- MySQL基础全知全解!超详细无废话!轻松上手~
-
本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...
- 深入剖析 MySQL 中的锁机制原理_mysql 锁详解
-
在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...
- Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析
-
引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...
- MySQL基础篇:DQL数据查询操作_mysql 查
-
一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...
- MySql:索引的基本使用_mysql索引的使用和原理
-
一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
程序员的开源月刊《HelloGitHub》第 71 期
-
详细介绍一下Redis的Watch机制,可以利用Watch机制来做什么?
-
假如有100W个用户抢一张票,除了负载均衡办法,怎么支持高并发?
-
Java面试必考问题:什么是乐观锁与悲观锁
-
如何将AI助手接入微信(打开ai手机助手)
-
SparkSQL——DataFrame的创建与使用
-
redission YYDS spring boot redission 使用
-
一文带你了解Redis与Memcached? redis与memcached的区别
-
如何利用Redis进行事务处理呢? 如何利用redis进行事务处理呢英文
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)