常见的限流算法- python版本

news2024/12/23 2:58:57

shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。
个人IP:shigen

在系统的稳定性设计中,需要考虑到的就是限流,避免高并发环境下一下子把服务整垮了。shigen在翻看以前的笔记的时候,看到了python版本的限流算法,在此做一个分享。

前提

本地的redis服务已经启动,mac用户两行命令即可:

brew install redis && brew services start redis

完了之后,在代码里写上获得redis连接的代码:

def get_redis_con():
    pool = redis.ConnectionPool(max_connections=4, decode_responses=True)
    return redis.Redis(connection_pool=pool)

其他配置参照官方文档。

固定窗口

类似于把时间切分了,每个时间段只允许固定次的请求。

固定窗口

最直白的话语就是:我的接口1s只允许100次请求,多了我就抛异常。

def fixed_window(user, action, time_zone=60, max_times=30):
    key = f'{action}'
    count = get_redis_con().get(key)
    if not count:
        count = 1
        get_redis_con().setex(key, time_zone, count)
    if int(count) < max_times:
        get_redis_con().incr(key)
        return True
    return False

代码中加上了user,其实就是避免单个用户的接口防刷。在之前的文章<如何优雅的实现接口防刷>中,其实就是用的这种方法。

对应的话,其实也是有一些问题的。

最主要的一个缺点就是:流量不是平滑的,可能存在多个流量峰值导致服务间歇性的不可用。最直观的感受是在窗口切换的时候,流量堆积导致的问题。

滑动窗口

描述的原理是:

  1. 将时间划分为细粒度的区间,每个区间维持一个计数器,每进入一个请求则将计数器加一;
  2. 多个区间组成一个时间窗口,每流逝一个区间时间后,则抛弃最老的一个区间,纳入新区间;
  3. 若当前窗口的区间计数器总和超过设定的限制数量,则本窗口内的后续请求都被丢弃。

可能还是有一些抽象,我们借用代码来讲解:

def silde_window(user, action, time_zone=60, max_times=30):
    key = f'{action}'
    now_ts = time.time() * 1000
    # ms级时间戳,保证唯一
    value = now_ts
    # 时间窗口的左边界
    old_ts = now_ts - time_zone * 1000
    # 记录 {成员元素:分数值}
    mapping = {
        value: now_ts,
    }
    get_redis_con().zadd(key, mapping)
    # 删除时间窗口之前的数据
    get_redis_con().zremrangebyscore(key, -1, old_ts)
    # 获得窗口内的行为数量
    count = get_redis_con().zcard(key)
    get_redis_con().expire(key, time_zone + 1)
    if not count or int(count) < max_times:
        return True
    return False

用到的数据结构是zset。这里的时间戳就是对应值的score

这种方式可以应对流量的激增,但是流量的曲线还是不够平滑。

漏桶算法

就类似于一个桶,请求先去填满桶,填满之后,其它的请求直接拒绝;同时,桶以一定的速率漏出,放行请求。

这种算法的速率是不支持动态调整的,对于系统资源的充分利用上还是存在问题的。

令牌桶算法

漏桶算法的主角是桶,令牌桶的主角是令牌。

def pass_token_bucket(user, action, time_zone=60, max_times=30):
    key = f'{user}:{action}'
    # 令牌生成速度
    rate = max_times / time_zone
    capacity = max_times
    token_count = get_redis_con().hget(key, 'tokens')
    last_time = get_redis_con().hget(key, 'last_time')
    now = time.time()
    token_count = int(token_count) if token_count else capacity
    last_time = last_time if last_time else now
    # 经过一段时间之后生成的令牌数量
    new_token_count = int((now - last_time) * rate)
    if new_token_count > 1:
        token_count += new_token_count
        if token_count > capacity:
            token_count = capacity
        last_time = time.time()
        get_redis_con().hset(key, 'last_time', last_time)

    if token_count >= 1:
        token_count -= 1
        get_redis_con().hset(key, 'tokens', token_count)
        return True
    return False

对于漏桶和令牌桶,算法的实现其实都大差不差。shigen在学习这个的时候,还有一点整混淆了。

最后,说一下如何验证,使用到了python的多线程。

executor = ThreadPoolExecutor(max_workers=4)
APIS = ['/api/a', '/get/user/1', '/get/user/2', '/get/user/3']


def task() -> bool:
    user = random.randint(1000, 1010)
    status = pass_token_bucket(user, random.choice(APIS))
    if not status:
        raise SystemError('{}被限制'.format(user))
    return status
  
  if __name__ == '__main__':
    jobs = [executor.submit(task) for _ in range(1000)]
    for job in jobs:
        print(job.result())

与shigen一起,每天不一样!

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

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

相关文章

DC/DC高压模块直流升压可调稳压输出升压变换器5V12V24V48V转50V110V150V130V200V250V300V450V500V600V800V

特点 效率高达 80%以上1*2英寸标准封装单电压输出价格低稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上 应用 HRB W2~40W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、9~18V、及18~36V、…

容量治理三板斧:扩容、限流与降级

前言 随着现代软件系统日益复杂和用户规模的不断增长&#xff0c;分布式架构成为了保持系统高可用性与高性能的标准解决方案。然而&#xff0c;随之而来的是对系统容量治理的新挑战。在这样的背景下&#xff0c;容量治理成为了分布式系统设计和运维中不可或缺的一环。要确保系…

【PyTorch][chapter 22][李宏毅深度学习]【无监督学习][ WGAN]【理论一】

简介&#xff1a; 2014年Ian Goodfellow提出以来&#xff0c;GAN就存在着训练困难、生成器和判别器的loss无法指示训练进程、生成样本缺乏多样性等问题。从那时起&#xff0c;很多论文都在尝试解决&#xff0c;但是效果不尽人意&#xff0c;比如最有名的一个改进DCGAN依靠的是对…

AI毕业设计生成器(基于AI大模型技术开发)支持Java和Python

这是一个辅助生成计算机毕业设计的工具&#xff0c;可以自动完成毕业设计的源码。它基于几百个github上面开源的java和python项目&#xff0c;运用tengsorflow技术&#xff0c;训练出了AI大模型。基本实现了计算机毕业设计生成器&#xff0c;能够初步生成Java或python基本源码。…

嵌入式驱动学习第三周——container_of()宏

前言 Linux内核编程中&#xff0c;会经常看见一个宏函数container_of&#xff0c;那么这究竟是什么呢&#xff0c;本篇博客记录学习container_of的过程。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可…

1688平台最关键的接口接入实例|获得1688商品详情| 按关键字搜索商品| 按图搜索1688商品(拍立淘)| 获得淘口令真实url

参数说明 通用参数说明 version:API版本key:调用key,测试key:test_api_keyapi_name:API类型[item_get,item_search]cache:[yes,no]默认yes&#xff0c;将调用缓存的数据&#xff0c;速度比较快result_type:[json,xml,serialize,var_export]返回数据格式&#xff0c;默认为jsonl…

【JavaScript 漫游】【034】AJAX

文章简介 本篇文章为【JavaScript 漫游】专栏的第 034 篇文章&#xff0c;对浏览器模型的 XMLHttpRequest 对象&#xff08;AJAX&#xff09;的知识点进行了总结。 XMLHttpRequest 对象概述 浏览器与服务器之间&#xff0c;采用 HTTP 协议通信。用户在浏览器地址栏键入一个网…

Cisco Packet Tracer模拟器实现交换机的vlan配置、生成树技术及模拟器路由设置

1. 内容 1.对交换机进行Vlan配置&#xff0c;完成交换机Vlan的划分、交换机间相同Vlan的通信以及三层交换机的配置。 2.实现交换机的生成树技术&#xff0c;在两个交换机上配置生成树协议&#xff0c;实现Vlan的负载均衡 3.对路由器进行设置&#xff0c;包括模拟器中路由器的…

案例分析篇07:数据库设计相关28个考点(23~28)(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

基于yolov5的草莓成熟度检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的草莓成熟度检测系统&#xff0c;系统既能够实现图像检测&#xff0c;也可以进行视屏和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的草莓成熟度系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目…

力扣226.翻转二叉树(二叉树的先序遍历)

文章目录 题目描述思路复杂度Code 题目描述 思路 利用二叉树的先序遍历&#xff0c;每次递归遍历时将当前节点的左右子节点交换即可 复杂度 时间复杂度: O ( n ) O(n) O(n)&#xff1b;其中 n n n为树节点的个数 空间复杂度: O ( h e i g h ) O(heigh) O(heigh)&#xff1b;其…

虚位以待!OpenHarmony开发者激励计划持续招募中

虚位以待&#xff01;OpenHarmony开发者激励计划持续招募中 自2022年5月7日&#xff0c;OpenHarmony开发者激励计划启动招募以来&#xff0c;就正式公开邀请广大开发者们参与 OpenHarmony 生态共建。随着社区的快速成长&#xff0c;目前已有累计超过7000名贡献者&#xff0c;产…

7个帮您恢复文件的Android 数据恢复推荐

您的 Android 设备上保存哪些类型的数据&#xff1f;如果您像大多数人一样&#xff0c;那么您可能已经列出了文档、照片、视频和音频文件。如果您使用智能手机或平板电脑的时间足够长&#xff0c;我们愿意打赌您对 Android 数据丢失有第一手经验。 对您来说幸运的是&#xff0…

目标检测数据集:手机顶盖焊缺陷检测数据集

✨✨✨✨✨✨目标检测数据集✨✨✨✨✨✨ 本专栏提供各种场景的数据集,主要聚焦:工业缺陷检测数据集、小目标数据集、遥感数据集、红外小目标数据集,该专栏的数据集会在多个专栏进行验证,在多个数据集进行验证mAP涨点明显,尤其是小目标、遮挡物精度提升明显的数据集会在该…

ubuntu 18.04安装教程(详细有效)

文章目录 一、下载ubuntu 18.04镜像二、安装ubuntu1. 点击下载好的Vmware Workstation&#xff0c;点击新建虚拟机&#xff0c;选择 “自定义(高级)”&#xff0c;之后下一步。2. 默认配置&#xff0c;不需要更改&#xff0c;点击下一步。3. 选择 “安装程序光盘映像文件(iso)(…

用信号的方式回收僵尸进程

当子进程退出后&#xff0c;会给父进程发送一个17号SIGCHLD信号&#xff0c;父进程接收到17号信号后&#xff0c;进入信号处理函数调用waitpid函数回收僵尸进程若多个子进程同时退出后&#xff0c;这是切回到父进程&#xff0c;此时父进程只会处理一个17号信号&#xff0c;其他…

vulhub中Weblogic SSRF漏洞复现

Weblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi等脆弱组件。 访问http://your-ip:7001/uddiexplorer/&#xff0c;无需登录即可查看uddiexplorer应用。 SSRF漏洞测试 SSRF漏洞存在于http://your-ip:7001/ud…

魅族录屏功能在哪里?这篇文章告诉你答案

“魅族录屏功能在哪里&#xff1f;作为一名魅族手机的新用户&#xff0c;我对这款手机非常满意。然而&#xff0c;最近我在工作中需要用到录屏功能&#xff0c;却找不到如何开启的方法。想请教各位魅族手机的达人们&#xff0c;能否分享一下录屏功能的开启方法&#xff1f;非常…

Android studio Gradle下载失败,如何手动配置解决该问题详解

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 前言&#xff1a; 今天在打开公司一个项目时&#xff0c;突然要重新下载相关的gradle&am…

JWT实战之升级Java JWT

概述 关于JWT的基础概念&#xff0c;如JWT组成部分&#xff0c;以及入门实战&#xff0c;如&#xff1a;如何生成Token、如何解析Token、怎么加入自定义字段等&#xff0c;可参考JWT入门教程。 如前文提到的blog所述&#xff0c;大多数公司都会使用如下&#xff08;版本&…