当前位置: 首页 > news >正文

Redis学习笔记14:基于spring data redis及lua脚本ZSET有序集合实现环形结构案例及lua脚本如何发送到redis服务器

案例实现目标,一、实现一个环形结构,环形结构上节点有一个阀值threshold,超过阀值则移除分数score最低的成员,不足则将当前成员添加进环中,且确保成员不可重复;二、每次访问环中的数据都需要刷新key的过期时间;

一个对springboot redis框架进行重写,支持lettuce、jedis、连接池、同时连接多个集群、多个redis数据库、开发自定义属性配置的开源SDK

<dependency><groupId>io.github.mingyang66</groupId><artifactId>emily-spring-boot-redis</artifactId><version>4.4.0</version>
</dependency>

GitHub地址:https://github.com/mingyang66/spring-parent

一、环形结构lua脚本
-- 键名
local key = KEYS[1]
-- 分数
local score = tonumber(ARGV[1])
-- 值
local value = ARGV[2]
-- 阀值
local threshold = tonumber(ARGV[3])
-- 超时时间
local expire = tonumber(ARGV[4])local success, error = pcall(function(key, score, value, threshold, expire)-- 返回有序成员的分数local exists = redis.call('ZSCORE', key, value)if not exists then-- 获取有序集合的成员数local len = tonumber(redis.call('ZCARD', key))if (len >= threshold) then-- 移除有序集合中给定的排名区间的所有成员redis.call('ZREMRANGEBYRANK', key, 0, 0)end-- 向有序集合添加一个或多个成员,或者更新已存在成员的分数redis.call('ZADD', key, score, value)end-- 超时时间必须大于0,否则永久有效if expire > 0 then-- 设置超时时间redis.call('EXPIRE', key, expire)end
end, key, score, value, threshold, expire)-- 判定脚本是否执行成功
if success thenreturn 1
elsereturn error
end
二、spring data redis调用lua脚本工具方法
    /*** 基于ZSET有序集合构建环形结构* 1. 环上有一个阀值上线;* 2. 环可以设置有效期;* 3. 环上节点达到上限后移除分数最低的成员** @param redisTemplate redis模板工具类* @param key           键名* @param score         分数, 可以使用时间戳做为分值* @param value         成员值* @param threshold     阀值* @param expire        过期时间* @return true-执行成功 false-执行失败*/public static boolean zSetCircle(RedisTemplate redisTemplate, String key, long score, Object value, long threshold, Duration expire) {try {if (StringUtils.isEmpty(LUA_SCRIPT_ZSET_CIRCLE)) {LUA_SCRIPT_ZSET_CIRCLE = getLuaScript("META-INF/scripts/zset_circle.lua");}RedisScript<Long> script = RedisScript.of(LUA_SCRIPT_ZSET_CIRCLE, Long.class);if (expire == null) {expire = Duration.ZERO;}redisTemplate.execute(script, singletonList(key), score, value, threshold, expire.getSeconds());return true;} catch (Throwable ex) {BaseLogger baseLogger = BaseLoggerBuilder.create().withSystemNumber(SystemNumberHelper.getSystemNumber()).withTraceId(UUIDUtils.randomSimpleUUID()).withClientIp(RequestUtils.getClientIp()).withServerIp(RequestUtils.getServerIp()).withTriggerTime(DateConvertUtils.format(LocalDateTime.now(), DatePatternInfo.YYYY_MM_DD_HH_MM_SS_SSS)).withUrl("Redis").withRequestParams(key, value).withRequestParams("score", score).withRequestParams("threshold", threshold).withRequestParams("expire", expire.getSeconds()).withBody(PrintExceptionInfo.printErrorInfo(ex.getCause())).build();logger.info(JsonUtils.toJSONString(baseLogger));return false;}}/*** 获取lua脚本** @param filePath 脚本路径* @return lua字符串脚本*/public static String getLuaScript(String filePath) {try {return new ClassPathResource(filePath).getContentAsString(StandardCharsets.UTF_8);} catch (IOException e) {throw new RuntimeException(e);}}
三、控制器方法
    @GetMapping("zset")public boolean zset() {String value = RequestUtils.getHeader("value");return LuaScriptTools.zSetCircle(redisTemplate, "test-script-zset", System.currentTimeMillis(), value, 3, Duration.ofSeconds(60));}
四、什么是SHA1摘要

SHA1摘要是对lua脚本的内容进行哈希计算的结果。它是一个40个字符的十六进制字符串。

在Redis中,使用SCRIPT LOAD命令可以将lua脚本加载到服务器,并返回一个SHA1摘要,这个摘要可以被用于后续的EVALSHA名利来执行脚本。

SHA1摘要的作用是将脚本内容映射为一个唯一的标识符,以便在多次执行脚本时,可以通过传输摘要而不是完整的脚本内容来提高效率。

示例如下:

127.0.0.1:6379> SCRIPT LOAD "return redis.call('GET', 'mykey')"
"8f1c7a686c72f6ddc6e3b0b9a7e1f4d8d89563a8"
127.0.0.1:6379> EVALSHA "8f1c7a686c72f6ddc6e3b0b9a7e1f4d8d89563a8" 1 mykey
"myvalue"
五、spring data redis如何将lua脚本发送到服务器端?

如果将日志级别调整为debug级别,将会在日志中发现有这样一条信息:

io.lettuce.core.RedisNoScriptException: NOSCRIPT No matching script. Please use EVAL.

这条日志信息说明在redis服务器端通过客户端的SHA1字符串未找到对应的lua脚本,需要我们将lua脚本发送到服务器端并执行指令:

org.springframework.data.redis.core.script.DefaultScriptExecutor#eval方法是发送脚本及执行脚本的核心代码:

	protected <T> T eval(RedisConnection connection, RedisScript<T> script, ReturnType returnType, int numKeys,byte[][] keysAndArgs, RedisSerializer<T> resultSerializer) {Object result;try {// 通过SHA1编码发送到redis服务器,并查询对应的脚本,如果存在,则执行,如果不存在抛出异常result = connection.evalSha(script.getSha1(), returnType, numKeys, keysAndArgs);} catch (Exception e) {//异常信息会带有:io.lettuce.core.RedisNoScriptException: NOSCRIPT No matching script. Please use EVAL.if (!ScriptUtils.exceptionContainsNoScriptError(e)) {throw e instanceof RuntimeException ? (RuntimeException) e : new RedisSystemException(e.getMessage(), e);}//将lua脚本发送到redis服务器端,并根据参数执行脚本result = connection.eval(scriptBytes(script), returnType, numKeys, keysAndArgs);}if (script.getResultType() == null) {return null;}//解析执行脚本后返回的结果return deserializeResult(resultSerializer, result);}

根据上述分析,spring data redis执行lua脚本分为如下步骤:

  1. 从lua文件中读取lua脚本,转换为字符串;
  2. 对lua脚本字符串进行SHA1编码,得到一个40个字符串的十六进制字符;
  3. 通过connection对象的evalSha方法将SHA1编码字符串及要执行的参数发送到redis服务器,redis服务器通过SHA1字符串查找对应的lua脚本,如果查找到则根据参数执行对应的脚本,并返回执行结果;如果未查询到脚本,则会抛出异常,执行如下步骤。
  4. 通过connection对象的eval方法将lua脚本及执行脚本需要的参数信息发送到redis服务器,redis服务器会将lua脚本保存一份,并执行脚本,返回执行结果;

相关文章:

Redis学习笔记14:基于spring data redis及lua脚本ZSET有序集合实现环形结构案例及lua脚本如何发送到redis服务器

案例实现目标&#xff0c;一、实现一个环形结构&#xff0c;环形结构上节点有一个阀值threshold,超过阀值则移除分数score最低的成员&#xff0c;不足则将当前成员添加进环中&#xff0c;且确保成员不可重复&#xff1b;二、每次访问环中的数据都需要刷新key的过期时间&#xf…...

openssl C++研发之pem格式处理详解

一、PEM_writeXXX和EM_write_bio_XXX 在OpenSSL的crypto/pem.h头文件中&#xff0c;PEM_write_XXXX和PEM_write_bio_XXXX系列函数用于将特定类型的数据写入文件或BIO&#xff08;内存缓冲区&#xff09;中&#xff0c;其中XXXX代表不同的数据类型。 这些函数的使用方式相似&a…...

【教3妹学编辑-mysql】详解数据库三大范式

什么是范式 简单地理解就是&#xff1a;数据库设计时遵循的规范 三大范式 数据库三大范式包含&#xff1a;1、第一范式(1NF)&#xff1b;2、第二范式(2NF)&#xff1b;3、第三范式(3NF)。其中&#xff0c;第一范式(1NF)的要求是属性不可分割&#xff0c;第二范式(2NF)的要求是…...

【计算机网络笔记】路由算法之链路状态路由算法

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…...

读像火箭科学家一样思考笔记04_第一性原理(下)

1. 来自无形规则的阻力 1.1. 无形规则 1.1.1. 僵化成规则的不必要习惯和行为 1.1.2. 不像有形的书面规则 1.1.2.1. 书面规则出现在标准操作流程中&#xff0c;可以修改或删除 1.1.3. 成文的规则可能会抗拒变革&#xff0c;但无形规则却更加顽固 1.1.4. 我们为强加在自己身…...

开源集群管理系统对比分析:Kubernetes 与 Apache Mesos

集群管理系统是关键的软件解决方案&#xff0c;可以在互连机器网络中有效分配和利用计算资源。毫无疑问&#xff0c;它们通过确保可扩展性、高可用性和有效的资源管理在现代计算中发挥着至关重要的作用&#xff0c;这使得它们对于运行复杂的应用程序、管理数据中心以及进一步增…...

matlab 坡度滤波算法地面分割

目录 一、算法原理1、实现流程2、参考文献二、代码实现三、结果展示四、测试数据一、算法原理 1、实现流程 1、格网示意图 2、计算格网行列数 公式中的特殊符号为向上取整,...

【腾讯云 HAI域探秘】高性能服务器引领AI革新浪潮:从AI绘画、知识问答到PyTorch图像分类、视频检测的全方位探索

目录 1 HAI&#xff08;高性能应用服务&#xff09;简介2 HAI的应用场景2.1 HAI在AI作画中的灵活性与效率2.2 深入探索LLM语言模型的应用与性能2.3 HAI支持的AI模型开发环境与工具 3 基于stable difussio的AI 绘画应用实践3.1 使用AI模型中的stable diffusion模型服务3.2 设置和…...

【Java】ExcelWriter自适应宽度工具类(支持中文)

工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

C++二分查找算法:132模式枚举3简洁版

本文涉及的基础知识点 二分查找算法合集 本题不同解法 包括题目及代码C二分查找算法&#xff1a;132 模式解法一枚举3C二分查找算法&#xff1a;132 模式解法二枚举2代码简洁C二分查找算法&#xff1a;132 模式解法三枚举1性能最佳C单调向量算法&#xff1a;132 模式解法三枚…...

Map 和 WeakMap:JavaScript 中的键值对集合

JavaScript 是一种动态、弱类型的脚本语言&#xff0c;经常用于构建现代 Web 应用程序。在编写 JavaScript 代码时&#xff0c;我们经常需要使用各种数据结构来存储和管理数据。其中&#xff0c;Map 和 WeakMap 就是两个非常有用的数据结构&#xff0c;它们分别提供了用于存储键…...

linux rsyslog综合实战1

本次我们通过rsyslog服务将A节点服务器上的单个日志(Path:/var/log/245-1.log)实时同步到B节点服务器目录下(Path:/opt/rsyslog/245) 1.rsyslog架构 2.环境信息 环境信息 HostnameIpAddressOS versionModuleNotersyslog1192.168.10.245CentOS Linux release 7.9.2009 (Core)rs…...

redis+python 建立免费http-ip代理池;验证+留接口

前言: 效果图: 对于网络上的一些免费代理ip,http的有效性还是不错的;但是,https的可谓是凤毛菱角; 正巧,有一个web可以用http访问,于是我就想到不如直接拿着免费的HTTP代理去做这个! 思路: 1.单页获取ipporttime (获取time主要是为了后面使用的时候,依照时效可以做文章) 2.整…...

虚幻C++ day5

角色状态的常见机制 创建角色状态设置到UI上 在MainPlayer.h中新建血量&#xff0c;最大血量&#xff0c;耐力&#xff0c;最大耐力&#xff0c;金币变量&#xff0c;作为角色的状态 //主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category "Playe Stats&…...

C#中的DateTime类

C# 中的 DateTime 类是用于表示日期和时间的结构。它提供了一系列属性和方法&#xff0c;用于处理日期和时间的各种操作和计算。下面是一些常用的 DateTime 类的用法和方法解释&#xff0c;以及相应的示例说明&#xff1a; 创建 DateTime 对象&#xff1a; 使用当前日期和时间创…...

Flutter笔记:Matrix4矩阵变换与案例

Flutter笔记 Matrix4矩阵变换及其案例 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134474764 【简介…...

数字IC前端学习笔记:时钟切换电路

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 有些时候我们需要在系统运行时切换系统时钟&#xff0c;最简单的方法就是使用一个MUX&#xff08;数据选择器&#xff09;选择输出的时钟&#xff0c;如下代码片所…...

.NET6使用MiniExcel根据数据源横向导出头部标题及数据

.NET6MiniExcel根据数据源横向导出头部标题 MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。 特点: 低内存耗用&#xff0c;避免OOM、频繁 Full GC 情况 支持即时操作每行数据 兼具搭配 LINQ 延迟查询特性&#xff0c;能办到低消耗、快速分页等复杂查询 轻量…...

表内容的操作(增删查改)【MySQL】

文章目录 表的 CRUDCreate&#xff08;增加&#xff09;插入记录插入冲突则更新记录替换记录 Retrieve&#xff08;查找&#xff09;查找记录指定表达式的别名为结果去重WHERE 子句运算符条件查询区间查询模糊查询空值查询 对结果排序筛选分页结果 Update&#xff08;修改&…...

C++快速入门 - 2(几分钟让你快速入门C++)

C快速入门 - 2 1. 内联函数1.1 概念1.2 特性 2. auto关键字(C11)2.1 类型别名思考2.2 auto简介2.3 auto的使用细则2.4 auto不能推导的场景 3. 基于范围的for循环(C11)3.1 范围for的语法3.2 范围for的使用条件 1. 内联函数 1.1 概念 以inline修饰的函数叫做内联函数&#xff0c…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

深度解析云存储:概念、架构与应用实践

在数据爆炸式增长的时代&#xff0c;传统本地存储因容量限制、管理复杂等问题&#xff0c;已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性&#xff0c;成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理&#xff0c;云存储正重塑数据存储与…...