SaaS 电商设计 (十一) 那些高并发电商系统的限流方案设计

目录

  • 一.什么是限流
  • 二.怎么做限流呢
    • 2.1 有哪些常见的系统限流算法
      • 2.1.1 固定窗口
      • 2.1.1 滑动窗口
      • 2.1.2 令牌桶
      • 2.1.3 漏桶算法
    • 2.2 常见的限流方式
      • 2.2.1 单机限流&集群限流
      • 2.2.2 前置限流&后置限流
    • 2.3 实际落地是怎么做的
      • 2.3.1 流量链路
      • 2.3.2 各链路限流
        • 2.3.2.1 网关层
        • 2.3.2.2 nginx 层
        • 2.3.3.3 服务本身的限流

一.什么是限流

应用系统在自身有限资源下,在面对流量突发场景下的自我保护.这可能是最初的一个目标.在此之上,怎么在有限的资源下去完成系统的最好的性能表现.
那么总结下其实有两个原则.

- 系统保护(主要目标)
- 有限资源下的系统最佳吞吐(理想目标)

有了这两个原则,那么其实我们后续关注的就是如何友好的落地这些点.

二.怎么做限流呢

2.1 有哪些常见的系统限流算法

2.1.1 固定窗口

描述:这是一种简单的限流算法,它根据一个固定的时间窗口来控制流量.在给定时间窗口内,它允许固定数量的请求通过,超出的请求将被丢弃.

实现步骤:

  • 初始化一个计数器(counter)为0,并设置一个固定的时间窗口(window).
  • 当收到一个请求时,检查计数器的值.
  • 如果计数器小于限制的请求数量(limit),则允许请求通过并增加计数器的值.
  • 如果计数器已经达到限制的请求数量,丢弃请求或者返回一个错误.
  • 如果请求的时间超过了时间窗口的结束时间,重置计数器为1,并更新时间窗口为当前时间窗口.
limit = 100  # 限制的请求数量
window = 60  # 时间窗口为60秒def handle_request():global counter, window_start_time//开始时间current_time = time.time()//60 秒的窗口if current_time > window_start_time + window:counter = 0//重置开始时间window_start_time = current_timeif counter < limit:counter += 1# 处理请求else:# 丢弃请求或返回错误

相比之下 固定窗口算法的问题在于,无法应对在流量在突发场景下的冲击.在固定窗口下.el:10:00:00 - 10:00:01 时间窗口 60s. 限流值为 1w.
现实过程可能是如下这种场景.
在这里插入图片描述

这种场景对于固定窗口算法来说,造成的问题就是大量的请求都集中在固定窗口的某一段小窗口时间,导致窗口的 pass count 快速被消耗.这样即使后续的平滑流量甚至小
流量都难以继续通过窗口.

2.1.1 滑动窗口

描述:这是一种基于固定窗口算法优化之后的限流算法,在固定窗口算法的基础上引入了滑动窗口的概念.它允许窗口内的请求速率平滑地变化,而不仅仅是在固定窗口内进行限制.

实现步骤:

  • 初始化一个计数器(counter)为0,并设置一个滑动窗口的时间长度(window)和一个固定时间间隔(interval).
  • 当收到一个请求时,检查计数器的值.
  • 如果计数器小于限制的请求数量(limit),则允许请求通过并增加计数器的值.
  • 如果计数器已经达到限制的请求数量,丢弃请求或者返回一个错误.
  • 每隔固定时间间隔,将计数器的值减去窗口内的请求数量,并更新窗口内的请求数量.
limit = 100  # 限制的请求数量
window = 60  # 滑动窗口的时间长度为60秒
interval = 10  # 固定时间间隔为10秒def handle_request():global counter, window_start_time, window_requestscurrent_time = time.time()if current_time > window_start_time + window:counter -= window_requests.pop(0)window_requests.append(0)window_start_time = current_timeif counter < limit:counter += 1window_requests[-1] += 1# 处理请求else:# 丢弃请求或返回错误

2.1.2 令牌桶

描述:原理是系统以恒定的速率产生令牌,并将这些令牌放入一个桶中.当有请求到达时,需要从桶中获取一个令牌才能继续处理该请求.如果桶中没有足够的令牌,则请求被拒绝.

特点:既能够面对突发的流量峰值,也能处理平滑的系统请求.

具体来说,令牌桶算法的实现包括两个关键参数:令牌生成速率(rate)和桶的容量(capacity).令牌生成速率确定了每秒产生的令牌数量,桶的容量确定了桶中最多可以存放多少个令牌.

import timeclass TokenBucket:def __init__(self, rate, capacity):self.rate = rate  # 令牌生成速率(令牌/秒)self.capacity = capacity  # 桶的容量(令牌数量)self.tokens = 0  # 当前桶中的令牌数量self.last_time = time.time()  # 上次令牌生成时间def get_token(self):now = time.time()elapsed = now - self.last_time  # 计算时间间隔self.last_time = nowself.tokens = min(self.tokens + elapsed * self.rate, self.capacity)  # 生成令牌if self.tokens >= 1:self.tokens -= 1return Trueelse:return False# 示例用法
bucket = TokenBucket(rate=1, capacity=5)  # 令牌生成速率为1个/秒,桶的容量为5个令牌
for i in range(10):if bucket.get_token():print(f"请求 {i+1} 被处理")else:print(f"请求 {i+1} 被限流")time.sleep(1)  # 等待1秒再重新尝试获取令牌

2.1.3 漏桶算法

漏桶算法(Leaky Bucket Algorithm)是一种流量控制算法,用于平滑网络流量.它模拟了一个漏桶,当网络流量超过桶的容量时,多余的流量会被丢弃或者缓存,以保持流量的稳定性.

漏桶算法的原理是,维护一个固定容量的漏桶,每次流量到达时,先将流量放入漏桶中.如果漏桶已满,则丢弃超出容量的流量;如果漏桶未满,则将流量处理完成.然后,漏桶以固定速率漏水,即以固定速度释放流量.这样,即使流量突然增大,漏桶也可以平滑地处理流量.

class LeakyBucket:def __init__(self, capacity, rate):self.capacity = capacity  # 漏桶容量self.rate = rate  # 漏水速率self.water = 0  # 当前水量self.last_leak_time = time.time()  # 上次漏水时间def process(self, amount):current_time = time.time()time_passed = current_time - self.last_leak_timeself.water = max(0, self.water - self.rate * time_passed)  # 漏水if self.water + amount <= self.capacity:self.water += amountself.last_leak_time = current_timereturn True  # 流量处理成功else:return False  # 漏桶已满,丢弃流量

令牌桶算法更适合平滑限制流量,可以灵活地处理不同请求的流量需求;而漏桶算法更适合于固定速率的流量处理,可以有效地限制请求的处理速度 .对应到实际项目过程中,
漏桶的特点的就是恒定流速,令牌的特点就是可以应对突击的流量,应对秒杀大促等的场景.

2.2 常见的限流方式

2.2.1 单机限流&集群限流

单机限流和集群限流是常见的流量控制方式,它们在实现和应用上有一些区别,并且各自具有不同的优缺点.下面是单机限流和集群限流的区别以及它们的优缺点:

  • 区别:

单机限流:在单个服务器或节点上进行限流,仅对该节点的流量进行控制.
集群限流:在整个集群或多个服务器上进行限流,可以对整个系统的流量进行控制.

  • 单机限流的优缺点:

    • 优点:

实现简单:单机限流通常只需要在单个节点上实现限流逻辑,不需要进行节点间的数据共享和协调.
高效低延迟:限流操作只涉及当前节点,因此具有较高的效率和低延迟.

  • 缺点:

有限的扩展性:单机限流的处理能力受限于单个节点的性能,当流量过大时,单个节点可能无法承受.

  • 集群限流的优缺点:

    • 优点:

全局控制能力:集群限流可以在整个集群或多个节点上进行流量控制,实现全局的流量控制策略.
高可伸缩性:通过增加节点来扩展处理能力,可以更好地应对高流量的情况.

  • 缺点:

复杂性增加:集群限流需要在多个节点之间进行数据共享和协调,增加了系统的复杂性.
网络开销:集群限流需要节点间的通信和协调,可能会带来一定的网络延迟和额外的开销.

总的来说单机限流适用于对单个节点或服务器进行流量控制的场景,简单、高效,但扩展性有限;
集群限流适用于对整个系统或多个节点进行流量控制的场景,具有全局控制能力和高可伸缩性,但复杂度和网络开销较高.
选择合适的限流方式应根据具体的应用需求和系统架构来决定.

2.2.2 前置限流&后置限流

前置限流和后置限流是两种常见的流量控制方式,它们在应用时机和实现方式上有一些区别,并且各自具有不同的优缺点.

区别:
前置限流:在请求到达服务之前进行流量控制,即在请求进入系统之前进行限流处理.
后置限流:在请求离开服务之后进行流量控制,即在请求处理完成后进行限流处理.

前置限流的优缺点:

  • 优点:

提前过滤请求:前置限流可以在请求进入系统之前进行过滤和拒绝,减轻服务的负担.
快速响应:由于限流操作在请求进入系统之前进行,可以快速地进行限流判断,避免不必要的请求处理.

  • 缺点:

精确度有限:前置限流通常只能基于部分请求信息进行限流判断,无法对具体请求的处理结果进行评估.
需要额外资源:前置限流需要在请求进入系统之前进行处理,可能需要额外的流量控制组件或网络设备.

后置限流的优缺点:

  • 优点:

基于实际处理结果:后置限流可以根据请求的实际处理结果进行限流判断,更加准确地控制流量.
动态调整:后置限流可以根据实时的系统负载和性能情况,动态调整限流策略.

  • 缺点:

延迟较高:后置限流需要等待请求处理完成后才能进行判断和限流操作,可能会引入较高的延迟.
需要额外资源:后置限流需要在请求处理完成后进行处理,可能需要额外的流量控制组件或网络设备.

从上面的描述知道前置限流适用于在请求进入系统之前进行快速的流量控制,能够提前过滤请求和快速响应,但精确度有限;
后置限流适用于根据请求的实际处理结果进行流量控制,能够基于实际情况进行动态调整,但可能引入较高的延迟.

2.3 实际落地是怎么做的

2.3.1 流量链路

在介绍实际的限流方案需要简单介绍下整体流量链路.

在这里插入图片描述

以上是大致的一个流量链路.

step1:从整个入口到网关是整体流量的入口.
step2:从入口到各个 servicenginx
step3:从 nginx 再到本地的 service 接口

目前系统提供的服务分为两个部分.http 接口以及 rpc 接口.先说 http 接口这一块.这块主要支撑的是整个
主站的服务.具体的协议也是 http 的形式.通过反向代理挂载每一个逻辑分组(一个分组多个机器).

2.3.2 各链路限流

2.3.2.1 网关层

首先是整个网关这一层
这一层主要是用来代理整个公司级别的服务.这一层目前是用后置限流来处理进行处理的.

后置限流:后置限流是指在请求处理完之后,再根据请求的处理结果来判断是否需要限制请求的处理速率.即先处理请求,然后根据处理结果来决定是否限流.
这种方式可以确保请求的处理逻辑不受限流策略的影响,但可能会导致一些请求在处理完后才被限制,从而可能导致系统的负载过大.

前置限流:前置限流是指在请求处理之前,根据系统的负载情况或者其他指标来判断是否需要限制请求的处理速率.即在处理请求之前就根据限流策略来决定是否拒绝该请求.
这种方式可以避免系统负载过大,但可能会导致一些请求被提前拒绝,从而可能影响系统的正常运行.

通过上面的描述能知道后置限流的逻辑是其实目的是不干扰整个业务逻辑的执行,但是在整体流量的防控上做一次兜底.其实本质是没有做到下游的系统保护,这种方式的限流对象
仅仅是流量,就没有系统保护这一层的能力.

2.3.2.2 nginx 层

第二层是nginx 到服务这一层.

这一层目前是有两个维度.
根据 request 请求的方法指定方法请求级别的限流.
这个基本是对于单机限流的一个兜底,在服务的集群限流可能出现的一些漂移现象后的系统保护.
还有一个维度是每次请求都通过 lua 获取本地的物理机 cpu 指标. 具体的限制指标度量,可以依照压测对于 cpu 的观测.

-- 执行系统命令并获取输出结果
function execute_command(command)local handle = io.popen(command)local result = handle:read("*a")handle:close()return result
end-- 获取系统的CPU信息
function get_cpu_info()local cpu_info = execute_command("cat /proc/cpuinfo")return cpu_info
end-- 示例代码
local cpu_info = get_cpu_info()
print(cpu_info)
2.3.3.3 服务本身的限流

上面的限流基本是在服务本身之外的.或网关或流量代理实现的.
对于大型的分布式系统一般是选用集群限流.能很好的因为一些节点的故障带来的整体流量的承载能力的下载如果是单机限流,在节点故障后相当于整体的系统负载能力就削弱了.

具体的限流阈值有两个点.

  • 或者根据相应的往年的监控流量值来进行推算.
  • 具体根据压测时的阈值来进行调整.

第一点需要系统具备完整的监控体系.以获取足够的历史数据来进行推演.有的同学说了,我的系统或者我的接口是第一次上线无法获取足够的历史监控来推测.
系统第一次上线的场景:只能与 qa 测试这边打一个配合,完整的链路压测来彻底了解你的系统.获取到系统在可接受的接口性能下如:200ms.下的最大 单机qps或整体的集群最大 qps.
如果是单机压测,那么集群的限流就是线上机器数*单机承压的 qps 了.

还有一个点对于集群限流的场景,还是觉得有必要 mark 下.对于 rpc 服务来说,特别是上下游关系复杂调用方较多.这时候有单纯的一个集群限流
往往解决不了问题.很可能需要根据不同的调用方来实现不同的集群限流.例如:对于核心的,量大的 调用方单独的集群限流.如 2 个这种调用方就需要两个
集群限流 key.其他的一些小流量这样可以归并到 other 这样的集群限流渠道就好了.

集群限流的实现方式 sentinel

预取率:指的是在集群限流场景下.本地的调用端对于集群 token 的预取占比.举个例子:集群限流是 10000.预取:7000.那么预取率则是 70%.
假如有 70 台机器.则每个机器的 token 预取个数则是 10.

目前集群限流的过程

在这里插入图片描述

通过图示可以看出图上为令牌桶限流算法.
通过平台设置指定 key 的限流阈值.
consumer 启动完成 token 预取.预取的逻辑很常见.(如:美团的 leaf 的框架也有设计.好的框架总是借鉴来借钱去,这里也是套用电影里的说法
致敬)
实际请求过程中通过token 验证通过,完成对 provider 的调用.验证不通过则触发限流.

赠人玫瑰 手有余香 我是柏修 一名持续更新的晚熟程序员
期待您的点赞,关注加收藏,加个关注不迷路,感谢
您的鼓励是我更新的最大动力
↓↓↓↓↓↓

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

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

相关文章

重学java 56. Map集合

我们要拥有一定成功的信念 —— 24.6.3 一、双列集合的集合框架 HashMap 1.特点: a.key唯一,value可重复 b.无序 c.无索引 d.线程不安全 e.可以存null键,null值 2.数据结构:哈希表 LinkedHashMap&#xff08;继承HashMap&#xff09; 1.特点: a.key唯一,value可重复 b.有序 c.无…

矩阵连乘问题

#include<iostream> using namespace std; #define N 7 void MatrixChain(int p[N],int n,int m[N][N],int s[N][N]) {for(int i1;i<n;i)m[i][i]0;for(int r2;r<n;r)//有多少个相乘(规模){for(int i1;i<n-r1;i){int jir-1;m[i][j]m[i][i]m[i1][j]p[i]*p[i1]*p[j…

小熊家务帮day10- 门户管理

门户管理 1 门户介绍1.1 介绍1.2 常用技术方案 2 缓存技术方案2.1 需求分析2.1.1 C端用户界面原型2.1.2 缓存需求2.1.3 使用的工具 2.2 项目基础使用2.2.1 项目集成SpringCache2.2.2 测试Cacheable需求Service测试 2.1.3 缓存管理器&#xff08;设置过期时间&#xff09;2.1.4 …

深入理解序列化:概念、应用与技术

在计算机科学中&#xff0c;序列化&#xff08;Serialization&#xff09;是指将数据结构或对象状态转换为可存储或传输的格式的过程。这个过程允许将数据保存到文件、内存缓冲区&#xff0c;或通过网络传输至其他计算机环境&#xff0c;不受原始程序语言的限制。相对地&#x…

URL编码:讲解,抓包

URL 编码&#xff08;也称为百分号编码&#xff09;是一种在 URLs 中编码数据的方法。它将特殊字符转换为由百分号&#xff08;%&#xff09;后跟两个十六进制数字组成的格式。URL 编码通常用于将数据传递到网页或 Web 服务器时&#xff0c;以确保 URL 在传输过程中保持一致和安…

167.二叉树:另一棵树的字树(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* Tre…

2.3 OpenCV随手简记(四)

阈值处理是很多高级算法底层处理的预方法之一。 自己求图像平均阈值&#xff1a; # -*- codingGBK -*- import cv2 as cv import numpy as np #求出图像均值作为阈值来二值化 def custom_image(image): gray cv.cvtColor(image, cv.COLOR_BGR2GRAY) cv.imshow("原来&qu…

【JavaScript】---DOM操作1:获取元素

【JavaScript】—DOM操作1&#xff1a;获取元素 文章目录 【JavaScript】---DOM操作1&#xff1a;获取元素一、什么是DOM&#xff1f;1.1 概念1.2 图例演示 二、查找HTML元素2.1 getElementById()2.2 getElementsByTagName()2.3 getElementsByClassName()2.4 querySelector()2.…

Go语言 几种常见的IO模型用法 和 netpoll与原生GoNet对比

【go基础】16.I/O模型与网络轮询器netpoller_go中的多路io复用模型-CSDN博客 字节开源的netPoll多路复用器源码解析-CSDN博客 一、几种常见的IO模型 1. 阻塞I/O (1) 解释&#xff1a; 用户调用如accept、read等系统调用&#xff0c;向内核发起I/O请求后&#xff0c;应用程序…

【Spring Cloud Alibaba】服务注册与发现+远程调用

目录 注册微服务到Nacos&#xff08;服务提供者&#xff09;创建项目修改依赖信息添加启动注解添加配置信息启动服务&#xff0c;Nacos控制台查看服务列表 注册微服务到Nacos&#xff08;服务消费者&#xff09;创建项目添加依赖信息添加启动注解添加配置信息启动服务&#xff…

基于卷积神经网络(CNN)的深度迁移学习在声发射(AE)监测螺栓连接状况的应用

螺栓结构在工业中用于组装部件&#xff0c;它们在多种机械系统中扮演着关键角色。确保这些连接结构的健康状态对于航空航天、汽车和建筑等各个行业至关重要&#xff0c;因为螺栓连接的故障可能导致重大的安全风险、经济损失、性能下降和监管合规问题。 在早期阶段检测到螺栓松动…

vue3路由详解,从0开始手动配置路由(vite,vue-router)

创建一个不含路由的vue项目 &#xff08;查看路由配置可以直接跳过这一段&#xff09; 输入npm指令&#xff0c;然后写一个项目名称&#xff0c;之后一路回车即可 npm create vuelatest 注意这里我们不选引入vue router&#xff0c;成功后可以 查看目录 然后按提示信息输入指…

新闻出版署发布新规定,腾讯游戏限制未成年人端午期间每天一小时

原标题&#xff1a;腾讯游戏端午节期间针对未成年人的游戏时间限制措施 易采游戏网6月3日消息&#xff1a;近日国家新闻出版署针对未成年人沉迷网络游戏问题发布了《关于进一步严格管理 切实防止未成年人沉迷网络游戏的通知》&#xff0c;旨在加强对未成年人保护的力度&#xf…

GIS之arcgis系列06:线划图缓冲区分析

缓冲区工具将在输入要素周围指定距离内创建缓冲区面。 缓冲区例程将遍历输入要素的每个折点并创建缓冲区偏移。 通过这些偏移创建输出缓冲区要素 原理&#xff1a; 01.打开文件 02.确定单位&#xff0c;在文件属性里。 03.工具箱-->分析工具-->邻域分析-->缓冲区。 …

派派派森02

目录 1.容器 1.列表 2.元组 3.字符串 3.序列 4.集合 5.字典 2.数据容器通用操作 • max最大元素 • min最小元素 • 容器的通用转换功能 • 通用排序功能 3.字符串大小比较 4.函数中多个返回值 5.函数参数多种传递方式 1.位置参数 2.关键字参数 3.缺省参数 …

【C++/STL】list(常见接口、模拟实现、反向迭代器)

&#x1f308;个人主页&#xff1a;秦jh_-CSDN博客&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 目录 前言 list的常见接口 对迭代器的封装 节点 重载-> const迭代器 list与vector的对比 反向迭代…

2020长安杯

链接成功 检材一 1检材 1 的操作系统版本是 ()A. CentOS release 6.5 (Final)B. Ubuntu 16.04.3 LTSC. Debian GNU/ Linux 7.8 (wheezy)D. CentOS Linux release 7.6.1810 (Core)D 2检材 1 中&#xff0c;操作系统的内核版本是 ()(答案格式&#xff1a; “1.2.34” 数字和半角…

JVMの堆、栈内存存储

1、JVM栈的数据存储 通过前面的学习&#xff0c;我们知道&#xff0c;将源代码编译成字节码文件后&#xff0c;JVM会对其中的字节码指令解释执行&#xff0c;在解释执行的过程中&#xff0c;又利用到了栈区的操作数栈和局部变量表两部分。 而局部变量表又分为一个个的槽位&…

前端将DOM元素导出为图片

前端工作中经常会用到把一些元素导出&#xff0c;比如表格&#xff0c;正好项目有遇到导出为excel和导出为图片&#xff0c;就都封装实现了一下&#xff0c;以供其他需求的开发者使用&#xff1a; 1.导出为文档 这个说白了就是下载的功能&#xff0c;传过去检索参数&#xff…

超分辨重建——SRGAN网络训练自己数据集与推理测试(详细图文教程)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…