第十节 SpringBoot Starter 实战之 redis 滑动窗口

使用 redis 实现滑动窗口,我们会基于这个场景,建立一个 Starter,在这之前,我们需要先。理解这个场景。

关键字:滑动窗口、流式计算、lua脚本、redis、zset、starter

概要:本文封装 redis 的API,实现简易滑动窗口,分别从业务背景、窗口理解、redis 的 zset 结构,lua 脚本,注意事项,不足等进行讲解

一、业务背景

规则预警,在特定时间触发规则达到 n 次后发出告警信息,例如:5 分钟之内失败 2 次,当满足条件后会发一条通知告警;数值可以根据实际情况动态配置。

下图是动态展示滑动窗口的示意图,按照黄色线固定窗口进行移动,窗口内会出现各种数值点,对窗口数字进行统计:

借助 redis 的 zset 有序集合能力,其中 score 字段要求有序,因此使用时间戳做 score,这样既保证顺序也能根据时间窗口计算窗口内的个数,通过计算时间窗口内的个数再与业务做判断;另外为了保障原子能力,使用lua脚本

二、redis版功能实现

通过 Lua 脚本实现 CAS(check-and-set)命令。

关于窗口在业务上的诉求,我分了三种场景,分别如下所示:

2.1 场景一、统计时间窗口内是否达到预定阈值,返回true和false, 并且达到阈值后清除

描述:1. 添加计数,2.将时间窗口外的数据移除;3.统计当前窗口的个数;4.判断是否超过阈值,5.超过清理并返回,否则返回false

redis.pcall('zadd', KEYS[1], ARGV[1], ARGV[1]);
redis.pcall('zremrangebyscore', KEYS[1], 0, ARGV[2]);
redis.pcall("expire", KEYS[1], ARGV[3]);
if tonumber(redis.pcall('zcard',KEYS[1])) >= tonumber(ARGV[4]) 
    redis.pcall('zremrangebyscore', KEYS[1], 0, ARGV[1]);
    then return true end;
return false;

注意:不要使用下面这种方式。 集群方式下,不支持local变量,另外尽量少用变量,减少lua脚本占用过多内存

local key           = KEYS[1]; 
local current_time  = ARGV[1]; 
local pre_time      = ARGV[2]; 
local expire_second = ARGV[3]; 
local threshold     = ARGV[4]; 
redis.pcall("zadd", key, current_time, current_time);
redis.pcall("zremrangebyscore", key, 0, pre_time);;
local count = redis.pcall("zcard",key);
redis.pcall("expire", key, expire_second);
if tonumber(count) >= tonumber(threshold) then 
    redis.pcall("zremrangebyscore", key, 0, current_time);
    return true end;
return false;

2.2 场景二、统计时间窗口内是否达到预定阈值,返回true和false, 满足true的时候不做清理

redis.pcall('zadd', KEYS[1], ARGV[1], ARGV[1]);
redis.pcall('zremrangebyscore', KEYS[1], 0, ARGV[2]);
redis.pcall("expire", KEYS[1], ARGV[3]);
if tonumber(redis.pcall('zcard',KEYS[1])) >= tonumber(ARGV[4]) 
    then return true end;
return false;

2.3 场景三、统计时间窗口内的个数

只统计个数,不做其他的

redis.pcall('zadd', KEYS[1], ARGV[1], ARGV[1]);
redis.pcall('zremrangebyscore', KEYS[1], 0, ARGV[2]);
redis.pcall("expire", KEYS[1], ARGV[3]);
return redis.pcall("zcard",KEYS[1]);

当然在实际落地的过程,会遇到一些其他问题,比如使用lua限制,分布式限制等

有了上面的三个场景后,接下来我们开始实战一个 Starter

三、Starter 实现

3.1 自定义一个 Starter 需要的流程(关键步骤)

  1. 选择一个合理的业务场景。比如我选择了 滑动窗口这个场景。
  2. 创建新的Maven项目,并引入依赖,通常命名需要遵循Spring Boot的命名规范,通常是<your-module-name>-spring-boot-starter
  3. 代码实现,以及其他类的引入
  4. 编写自动配置类。 xxxAutoConfiguration
  5. 编写spring.factories文件, 在src/main/resources/META-INF/spring.factories中注册自定义的自动配置类
  6. 打包并发布到仓库,并在其他项目测试

3.2 本 Starter 的项目工程结构

本文的源码地址:uzong-starter-learning: 学习 SpringBoot Starter 的工程案例

四、代码实现

4.1 lua 脚本

本文给出三个 lua 脚本,分别应对三个场景。

lua 是一种非常简单的脚本语言,如果想了解更多,可以在菜鸟教程中学习,非常轻量:Lua 教程 | 菜鸟教程

4.2 核心逻辑

com.uzong.sliding.window.calculate.CalculateCore

细节描述:

  1. CalculateCore 的创建,需要交给 xxxAutoConfiguration 类。不可在 CalculateCore 上添加 @Resource, @Service 等类。所有 Starter 类的创建都尽量交给 xxxAutoConfiguration,用来控制类的加载。 这是一种规范
  2. 此处依赖 RedisTemplate,DefaultRedisScript、RedisSerializer 等。用例处理接口调用、序列化等。
  3. 调用的是 redisTemplate.execute方法,参数中包含了执行脚本、序列化、业务参数、过期时间等等。最核心也是最基础的接口。用于执行Redis脚本

4.3 对外的 service api

用于上层可以直接使用的 api,目前只提供了3个。对于 api 尽量包含详细的说明。以及注意实现

其实现类,则主要依赖 CalculateCore 类,就不过多介绍

4.4 配置类 SlidingWindowAutoConfiguration

注意细节:

  1. 通过 ConditionalOnClass,否则无法被创建
  2. 通过构造方式在此自动装配类中创建 SlidingWindowServiceImpl 等对象。方便管理所有相关的 bean 对象

4.5 spring.factories

前缀都是 org.springframework.boot.autoconfigure.EnableAutoConfiguration

4.6 打包并发布到仓库,并在其他项目测试

先发布到本地 Maven 仓库,测试没问题,再发布到公司的私服。需要注意版本管理。

到这里,Starter 实战结束了。更多细节可以参考本项目。

执行测试

http://localhost:8080/api/sl/calculateCount?bizCodeKey=001&windowSeconds=10
http://localhost:8080/api/sl/clearOnCondition?bizCodeKey=001&windowSeconds=3&threshold=5
http://localhost:8080/api/sl/keepCalculate?bizCodeKey=001&windowSeconds=3&threshold=5

已同步发布到公众号:面汤放盐 第十节 Starter 实战之 redis 滑动窗口 (qq.com)

掘金账号:第十节 SpringBoot Starter 实战之 redis 滑动窗口 - 掘金 (juejin.cn)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

百亿数据存储-高并发搜索如何设计?

最近好多小伙伴都跑来问小北&#xff0c;百亿级别的数据存储要怎么设计架构啊&#xff1f; 听说面试里经常问到这个问题。 就像前几天&#xff0c;有位同学去字节面试&#xff0c;就碰到了这个问题&#xff1a; “百亿级数据存储&#xff0c;你怎么设计&#xff1f;” 他们回答…

Scikit-Learn随机森林回归

Scikit-Learn随机森林回归 1、随机森林1.1、集成学习1.2、Bagging方法1.3、随机森林算法1.4、随机森林的优缺点2、Scikit-Learn随机森林回归2.1、Scikit-Learn随机森林回归API2.2、随机森林回归实践(加州房价预测)1、随机森林 随机森林是一种由决策树构成的集成算法,它在大多…

QT::QNetworkReply类readAll()读取不到数据的可能原因

程序中&#xff0c;当发送请求时&#xff0c;并没有加锁&#xff0c;而是在响应函数中加了锁&#xff0c;导致可能某个请求的finished信号影响到其他请求响应数据的读取 connect(reply,&QNetworkReply::finished,this,&Display::replyFinished);参考这篇文章&#xff…

闪电加载:Hexo博客性能优化全攻略

巴索罗缪大熊 前言 这些年积累了很多前端性能优化的知识点和思路&#xff0c;日常工作很少涉及技术层极限优化&#xff0c;近期终于一点点把博客独立搭建并部署了&#xff0c;对之前的一些技术点进行了深度探索&#xff0c;最终结果也达到了预期效果&#xff0c;由于水平有限&…

怎么从视频中提取音频?这里有三种提取妙招

怎么从视频中提取音频&#xff1f;在数字媒体日益丰富的今天&#xff0c;视频内容成为了信息传播的重要形式。但有时我们可能只需要视频中的音频部分&#xff0c;用于制作播客、音乐剪辑或语音分析等。幸运的是&#xff0c;技术的发展为我们提供了多种从视频中高效提取音频的方…

如何降本增效获得目标客户?AI企业使用联盟营销这个方法就对了!

AI工具市场正在迅速发展&#xff0c;现仍有不少企业陆续涌出&#xff0c;那么如何让你的工具受到目标群体的关注呢&#xff1f;这相比是AI工具营销人员一直在思考的问题。 为什么AI企业难以获客呢&#xff1f; 即使这个市场正蓬勃发展&#xff0c;也无法保证营销就能轻易成功…

【问题解决】pycharm中添加python interpreter报错 conda excutable is no found

选择安装目录下的conda.bat文件&#xff0c;然后点击“Load Environments”按钮&#xff0c;然后在列表中选择conda环境即可。

开源表单流程设计器有哪几个突出的优势特点?

当前&#xff0c;传统的表单制作已经无法满足现在企业的发展需求了。想要实现高效率发展&#xff0c;需要引进先进的低代码技术平台、开源表单流程设计器等优秀软件平台助力发展。它们具有可视化操作界面、灵活好操作、易维护、效率高等诸多优势特点&#xff0c;在推动企业实现…

蓝桥杯嵌入式 第六届国赛 更新中……

题目 配置 注意事项 复制LCD的工程&#xff0c;先配置资源 --- 勾选完选项一定要再看一眼&#xff0c;可能选择错误 ADC&#xff1a;配置ADC2_IN15&#xff0c;对应PB15引脚 EEROM&#xff0c;配置PB6和PB7 按键 输入模式PB0、PB1、PB2、PA0 LED 一定要使能PD2 PWM互补输出&…

vue3 + ts 实现IP地址及Mac地址输入框功能

1、组件完成代码 <template><div class"ip-input"><div v-for"(item, index) in ipArr" :key"index" class"ip-input__item-wrap"><input ref"ipInput" v-model"ipArr[index]" type"t…

AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月29日预测第5弹

今天继续基于8883的大底&#xff0c;使用尽可能少的条件进行缩号&#xff0c;同时&#xff0c;同样准备两套方案&#xff0c;一套是我自己的条件进行缩号&#xff0c;另外一套是8883的大底结合2码不定位奖号预测二次缩水来杀号。好了&#xff0c;直接上结果吧~ 首先&…

【数据结构】

根据先序、中序、后序确定二叉树&#xff1a; #背景&#xff1a;树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序&#xff0c;根据先序和后序不一定可以确定一棵二叉树&#xff0c;给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。 抓住中序特点&#x…

开源工具专题-04 Atlassian Crowd部署备份及迁移

开源工具专题-04 Atlassian Crowd部署备份及迁移 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-05-29csdn 博客名称&#xff1a;五维空间-影子&…

SpringBoot与Spring Framework提供的缓存抽象

目录 缓存 项目总结 新建一个SpringBoot项目 pom.xml application.properties CacheConfig Book BookRepository接口 BookService服务类 BookController控制器 SpringbootCacheApplication启动类 启动项目&#xff0c;使用Postman测试 参考博文&#xff1a; 1、使用…

无人港口/码头兴起,可视化大屏功不可没。

码头/港口可视化大屏可以为管理上带来多方面的价值&#xff0c;包括但不限于&#xff1a; 1. 实时监控&#xff1a; 大屏可以将港口的各种数据、设备状态、船舶位置等信息实时展示&#xff0c;管理人员可以通过大屏随时监控港口的运营情况&#xff0c;及时发现并处理问题。 2…

第13章 常用类

一、包装类 二、String String的常用方法&#xff1a; equals&#xff1a;判断内容是否相等&#xff0c;区分大小写。 String str1 "hello";String str2 "Hello";System.out.println(str1.equals(str2));//false equalsIgnoreCase&#xff1a;判断内容…

清华大学提出IFT对齐算法,打破SFT与RLHF局限性

监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;和基于人类反馈的强化学习&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是预训练后提升语言模型能力的两大基础流程&#xff0c;其目标是使模型更贴近人类的偏好和需求。 考虑到监督…

一文看懂标准版和Pro版的区别

在CRMEB的众多产品中&#xff0c;有这样两款产品经常被拿来比较&#xff0c;它们就是CRMEB的标准版和Pro版商城系统&#xff0c;今天&#xff0c;我们就来盘一下这两款系统之间究竟有哪些不同。 1、Pro版系统性能更卓越 CRMEB Pro版采用Tp6 SwooleRedis高性能框架开发&#…

游戏联运平台如何助力游戏行业飞速发展?

随着科技的进步和互联网的普及&#xff0c;游戏行业正以前所未有的速度飞速发展。在这个过程中&#xff0c;游戏联运平台凭借其独特的优势和功能&#xff0c;成为了推动游戏行业腾飞的关键力量。本文将探讨游戏联运平台如何助力游戏行业实现飞速发展。 一、游戏联运平台的定义与…

四川易点慧电商抖音小店信誉之店

在当下这个电商飞速发展的时代&#xff0c;如何在众多网店中挑选出一家既可靠又值得信赖的店铺&#xff0c;成为了消费者们关注的焦点。四川易点慧电子商务有限公司抖音小店以其卓越的品质和诚信的经营&#xff0c;逐渐在抖音平台上崭露头角&#xff0c;成为了众多消费者心中的…