精确掌控并发:滑动时间窗口算法在分布式环境下并发流量控制的设计与实现

这是《百图解码支付系统设计与实现》专栏系列文章中的第(15)篇,也是流量控制系列的第(2)篇。点击上方关注,深入了解支付系统的方方面面。

上一篇介绍了固定时间窗口算法在支付渠道限流的应用以及使用redis实现的核心代码。

本篇重点讲清楚滑动时间窗口算法原理和应用场景,以及使用reids实现的核心代码。

1. 滑动时间窗口原理

滑动窗口算法是一种更为灵活的流量控制方案,它比固定窗口算法能更平滑地处理突发流量。在滑动窗口中,时间窗口是重叠的,这意味着流量的计算是基于过去的一段连续时间内发生的事件。

工作流程:

  1. 窗口定义:确定窗口的大小,例如1秒钟,并设置窗口的滑动间隔,比如100毫秒。
  2. 计数与滑动:每个窗口都有自己的计数器。当一个新请求到达时,增加当前时间窗口及其前面相邻的窗口的计数。
  3. 限制检查:如果任何连续时间段内的请求总数超过阈值,则拒绝新的请求。
  4. 窗口更新:随着时间的推移,不断向前滑动窗口,并更新相应的计数器。

2. 滑动时间窗口在支付系统中的应用场景

滑动时间窗口在支付系统中的应用场景主要也是各种精确限流,比如把前一篇讲的固定时间窗口算法中,我们对外部渠道请求会做限流,那么就可以升级到滑动时间窗口,以提高精度。

只要是API限流,都可以使用。

3. 使用redis实现的核心代码

滑动窗口可以通过队列或循环数组来实现。每个窗口对应队列中的一个元素,记录该窗口期间的请求数。当时间滑动时,更新队列头部的元素,并可能将旧的元素出队

在Redis中,可以使用列表或有序集合来模拟这种滑动窗口。下面是一个Rdis实现的示例,使用有序集合(sorted set)来实现了滑动时间窗口算法:

/*** redis限流操作类*/
@Component
public class RedisLimitUtil {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 滑动时间窗口大小private static final long WINDOW_SIZE_IN_SECONDS = 1000;/*** 判断是否限流* 这里不考虑超过long最大值的情况,系统在达到long最大值前就奔溃了。*/public boolean isLimited(String key, String reuqestId, long countLimit) {// 使用Redis的多个命令来实现滑动窗口redisTemplate.zremrangeByScore(key, 0, currentTimeMillis - WINDOW_SIZE_IN_SECONDS);long count = redisTemplate.zcard(key);if (countLimit >= count) {redisTemplate.zadd(key, currentTimeMillis, reuqestId);return true;} else {return false;}}
}

每个请求都以其发生的时间戳作为分数(SCORE)存储在集合中。通过移除旧于当前时间窗口的请求来维护滑动窗口。通过检查集合中的元素数量,以确定是否超过了设定的最大请求数。

  • zremrangeByScore 用于移除窗口之外的旧请求。
  • zcard 获取当前窗口内的请求数量。
  • zadd 将新请求添加到集合中。

使用:PayServiceImpl

/*** 支付服务示例*/
public class PayServiceImpl implements PayService {@Autowiredprivate RedisLimitUtil redisLimitUtil;@Overridepublic PayOrder pay(PayRequest request) {if (isLimited(request)) {throw new RequestLimitedException(buildExceptionMessage(request));}// 其它业务处理... ...}/** 限流判断*/private boolean isLimited(PayRequest request) {// 限流KEY,这里以[业务类型 + 渠道]举例String key = request.getBizType() + request.getChannel();// 限流值Long countLimit = countLimitMap.get(key);// 如果key对应的限流值没有配置,或配置为-1,说明不限流if (null == countLimit || -1 == countLimit) {return false;}return redisLimitUtil.isLimited(key, request.getRequestId(), countLimit);}
}

需要注意一点的是,这次需要传入requestId进去,用于保存这个requestId在redis有序队列里的分数,用于计数和清理。

其它的注释写得比较清楚,没什么补充的。

4. 注意事项

一些分布式服务框架,为了更高的可靠性,他们使用的是本地计算。比如接口限流1000TPS,一共有20台应用服务器,框架就会把计算出每台机器是50个TPS,下发给所有的应用服务器,在服务器上线、下线过程中,可能会有一段时间是不准确的。

但在渠道限流应该中,因为每个渠道的流量都不太高,所以可以使用这种redis方案。且精度更高,不受应用服务器的上、下线影响。

另外,在分布式系统中,需要确保不同节点之间的时间同步,以保证流量计算的准确性。如果应用服务器之间的时间不同步,那么流量就会计算错误。

5. 结束语

分布式流控有很多实现方案,通过把固定时间窗口算法升级为滑动时间窗口算法,我们对流量控制的精度会大幅提升。

下一篇会介绍漏桶原理及实现。漏桶和令牌桶的特点是请求进来先保存起来,然后按一定的速度发送出,而不是超过阀值就拒绝。

6. 传送门

支付系统设计与实现是一个专业性非常强的领域,里面涉及到的很多设计思路和理论也可以应用到其它行业的软件设计中,比如幂等性,加解密,领域设计思想,状态机设计等。

在《百图解码支付系统设计与实现》的知识宇宙,每一篇深入浅出的文章都是一颗既独立但又彼此强关联的星球,有必要提供一个传送门以便让大家即刻到达想要了解的文章。

专栏地址百图解码支付系统设计与实现
领域相关
支付行业黑话:支付系统必知术语一网打尽
跟着图走,学支付:在线支付系统设计的图解教程
支付交易的三重奏:收单、结算与拒付在支付系统中的协奏曲
在线支付系统的精英搭档:深入剖析收银核心与支付引擎的协同作战(一)
在线支付系统的精英搭档:深入剖析收银核心与支付引擎的协同作战(二)

技术专题
交易流水号的艺术:掌握支付系统的业务ID生成指南
揭密支付安全:为什么你的交易无法被篡改
金融密语:揭秘支付系统的加解密艺术
支付系统日志设计完全指南:构建高效监控和问题排查体系的关键基石
避免重复扣款:分布式支付系统的幂等性原理与实践
支付系统的心脏:简洁而精妙的状态机设计与核心代码实现
精确掌控并发:分布式环境下并发流量控制的设计与实现(一)
精确掌控并发:分布式环境下并发流量控制的设计与实现(二)
金融疆界:在线支付系统渠道网关的创新设计(一)

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

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

相关文章

消息的发送与接收

消息的发送与接收 消息的发送与接收不仅仅是在于聊天功能的实现。其实还有很多种情况也算"消息的发送与接收"。而且我们还可以通过多种方法去实现。我们可以基于实际情况来选择。 WebSocket实现 node做后端。找了好多&#xff0c;前端页面总是用到了jQuery&#x…

lvgl简介

LVGL&#xff08;Light and Versatile Graphics Library&#xff09;是一个开源的图形用户界面库&#xff0c;旨在提供轻量级、可移植、灵活和易于使用的图形用户界面解决方案。 它适用于嵌入式系统&#xff0c;可以在不同的操作系统、微控制器和图形加速器上运行。LVGL的核心…

1.go安装及相关配置

目录 概述下载基本命令Go build环境设置 结束 概述 下载 官网速递 选择 1.20.x 一个是因为是次新版本&#xff0c;另一个&#xff0c;mac 系统是 10.13.6 &#xff0c;1.20.x 是最后一个支持此版本的。 环境变量 GOROOT go的安装目录(将go安装到哪里 which go、cat /etc/p…

【嵌入式Android各种调试命令】

控制台下 写mac跟sn #写mac su echo 1 > /sys/class/unifykeys/attach echo mac > /sys/class/unifykeys/name echo 00:22:6D:C6:9A:57 > /sys/class/unifykeys/write cat /sys/class/unifykeys/read#写sn su echo 1 > /sys/class/unifykeys/attach echo usid &g…

高并发IO底层原理

1 概述 IO底层原理是隐藏在Java编程知识之下的基础知识&#xff0c;是开发人员必须掌握的基本原理。本文从操作系统的底层原理入手&#xff0c;通过图文的方式为大家深入剖析高并发IO的底层原理&#xff0c;并介绍如何通过设置来让操作系统支持高并发。 2 IO读写的基本原理 为…

MySQL 8.0中过时的功能(二)

max_length_for_sort_data系统变量由于优化器的变更而被弃用&#xff0c;因为这个变量已经过时并且没有任何效果。用于对连接进行压缩的以下传统参数已经被弃用&#xff1a; - --compress客户端命令行选项; - mysql_options() C API函数的MYSQL_OPT_COMPRESS选项; - slave_comp…

文件模块常用api

文件模块常用api 文件夹常用操作 文件夹操作 fs.mkdir fs.rmdir 需要是空目录 题目&#xff1a;递归删除目录* 串行/并行删除文件*

介绍异或(XOR)运算

异或&#xff08;XOR&#xff09;是一种逻辑运算符&#xff0c;用于比较两个二进制数的对应位。它的运算规则如下&#xff1a; 如果两个对应位的值相同&#xff0c;结果为0。如果两个对应位的值不同&#xff0c;结果为1。 异或运算的原理基于以下观察&#xff1a; 反转性质&a…

【电商API】DIY网络爬虫收集电商数据

DIY网络爬虫收集电商数据 网络爬虫是最常见和使用最广泛的数据收集方法。DIY网络爬虫确实需要一些编程知识&#xff0c;但整个过程比一开始看起来要简单得多。 当然&#xff0c;爬虫的有效性取决于许多因素&#xff0c;例如目标的难度、网站方的反爬虫措施等。如果将网络抓取用…

机器学习根据金标准标记数据-九五小庞

根据金标准标记数据是一种在机器学习和数据科学中常见的操作&#xff0c;主要用于评估分类模型的性能。其基本步骤如下&#xff1a; 收集数据&#xff1a;首先需要收集相关领域的原始数据&#xff0c;这些数据通常来自不同的来源和渠道。数据清洗和预处理&#xff1a;在这一步…

JavaScript高级特性详解

摘要&#xff1a;本文将深入探讨JavaScript中的一些高级特性&#xff0c;包括闭包、原型链、高阶函数和异步编程。我们将通过详细的注释和实例来帮助读者理解这些概念&#xff0c;并通过总结部分强调其在实际开发中的应用。 一、闭包 闭包是JavaScript中一个非常重要的概念&a…

soft212期末

文章目录 安卓填空题选择题 C# 安卓 Dalvik中得到Dx工具会把部分class文件转换成dex文件。 如果希望在XML布局文件中调用颜色资源&#xff0c;可以使用color调用 Android程序入口的Activity是在AndroidManifest.xml文件中注册的 Android中查看应用程序日志的工具是LogCat Dal…

JavaScript面向对象之实践项目

1、cat项目 &#xff08;1&#xff09;需要修改的原代码 &#xff08;2&#xff09;修改要求 使用括号表示法将name属性的值存储在变量catName中。使用点表示法运行greeting()方法。将color属性值更新为白。重写greeting() 方法&#xff0c;使它的问候语为"孟买猫碳头对…

go高频文件操作整理

如有帮助&#xff0c;欢迎留下足迹哦&#xff01; 目录 创建文件 带权限创建或打开 创建目录&#xff08;单级、多级&#xff09; 检查给定路径&#xff08;目录、文件&#xff09;是否存在 将目录和文件名拼接成为完整文件路径 给定文件路径获取文件后缀 给定文件路径获…

肯尼斯·里科《C和指针》第6章 指针(7)编程的练习:删除字符

肯尼斯里科《C和指针》第6章 指针&#xff08;6&#xff09;编程的练习&#xff1a;查找字符-CSDN博客 2.编写一个函数&#xff0c;删除一个字符串的一部分。函数的原型如下&#xff1a; int del_substr(char *str, char const *substr) 函数首先应该判断substr是否出现在str中…

良心推荐!几款收藏的神级IDEA插件分享

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 CodeGlanceGsonFormatPOJO to JsonRainbow BracketsTranslationLombokMaven HelperAlibaba Java Code GuidelinesGenerateAllSetterMybatisXChinese (Simplified…

GEE APP——基于PFI纯净森林指数的CCDC-SMA算法的长时序森林监测APP

简介 森林生态系统的碳排放受到破碎化加速和边缘效应的极大影响。要了解这些影响,就必须准确监测破碎化森林景观的变化。然而,这些变化通常强度低、尺度小,因此很难使用中等空间分辨率的卫星图像(如 Landsat)来检测。为了应对这一挑战,本研究开发了纯林指数(PFI),该指…

react js自定义实现状态管理

redux基础实现 myRedux export const createStore (reduce) > {if (typeof reduce ! function) throw new Error(Expected the reducer to be a function.)let state,listeners []state reduce()const getState () > stateconst dispatch (action) > {if(typeo…

Tomcat10.X部署老版本axis2 webservice项目不生效

目录 一、使用场景 二、问题描述 三、原因排查 四、解决方案 一、使用场景 原来项目是OpenJDK8tomcat9构建&#xff0c;现在需要升级到OpenJDK17tomcat10的组合。原来的webservice项目打包成aar格式&#xff0c;通过axis2部署在tomcat上。 二、问题描述 在配置好jdk和to…

c ffmpeg 学习

1. int8_t <> char u_int8_t unsigned char int16_t short int32_t int 2. #define X(x) x,x,x,x,x,x,x,x //表示8个x 主要用于数组赋值 #include <stdio.h> #include <stdlib.h> #include <string.h>#define X8(x)…