Redis 7 新特性之 自定义Functions

news2024/12/23 8:14:10

Redis 7 新特性之 自定义Functions

Redis Functions(函数)是用于管理服务端执行代码的API。在Redis 7中出现,旨在取代之前版本的EVAL函数,是Redis 7新特性之一。

Eval 脚本的缺点

Redis 7之前的版本通过Eval执行脚本,该命令允许发送Lua脚本供服务器执行。Eval脚本的核心作用是在Redis中高效、原子地执行应用程序逻辑。通过Lua脚本可以组合不同数据类型、不同键值原子执行。

使用EVAL需要应用程序每次都发送整个脚本以供执行。由于这会导致网络和脚本编译开销,Redis以EVALSHA命令的形式提供了优化。通过首先调用SCRIPT LOAD以获取脚本的SHA1,应用程序可以在之后单独使用SHA1重复调用脚本。

按照架构设计,Redis只缓存加载的脚本。这意味着脚本缓存随时可能丢失,例如在调用script FLUSH之后、重新启动服务器之后或故障切换到副本时。如果缺少脚本,应用程序负责在运行时重新加载脚本。基本假设是脚本是应用程序的一部分,不由Redis服务器维护。

这种方法适用于许多轻量级脚本用例,但一旦应用程序变得复杂并更加依赖脚本,就会带来一些困难:

  • 所有客户端应用程序实例都必须维护所有脚本的副本
  • 在事务上下文中调用缓存脚本会增加由于缺少脚本而导致事务失败的可能性
  • SHA1 设计作用不大 原因是调试非常困难
  • EVAL促进了一种反模式,即客户端应用程序逐字渲染脚本,而不是调用KEYS和ARGV Lua API
  • 脚本之间不能相互调用 重复代码优化也成为无稽之谈

Redis Functions 介绍

Redis Functions是从Lua脚本进化而来。Functions提供与Lua脚本相同的核心功能。Redis将 Functions函数作为数据库的一个组成部分进行管理,并通过数据持久性和复制确保其可用性。因为函数是数据库的一部分,因此在使用前声明,所以应用程序不需要在运行时加载它们,也不需要冒中止事务的风险。使用函数的应用程序只依赖于它们的API,而不依赖于数据库中嵌入的脚本逻辑。

Redis Functions的设计还试图模糊编程语言的界限。Lua是Redis目前唯一支持作为嵌入式执行引擎的语言解释器,其目的是简单易学。然而,选择Lua作为一种语言仍然给许多Redis用户带来了挑战。Redis Functions特性对实现的语言没有任何限定。作为函数定义的一部分的执行引擎负责运行它。理论上,引擎可以用任何语言执行函数,只要它遵守若干规则(例如终止执行函数的能力)。

与Lua脚本操作一样,函数的执行是原子的。函数的执行在其整个时间内阻止所有服务器活动,这与事务的语义类似。这些语义意味着脚本的所有效果要么尚未发生,要么已经发生。执行函数的阻塞语义始终适用于所有连接的客户端。因为运行一个函数会阻塞Redis服务器,所以函数应该快速完成执行,所以应该避免使用长时间运行的函数。

总结:Redis Functions 类似MYSQL中的存储过程、自定义函数;事先定义Functions的逻辑,存储在服务端,客户端要做的仅仅是调用函数即可

Redis Functions 学习

接下来通过一些具体的例子和Lua片段来探索Redis函数。

每一个Redis 函数都需要被加载到Redis服务。使用FUNCTION LOAD命令将库加载到Redis数据库。该命令获取library 内容作为输入,格式为:

#!<engine name> name=<library name>
  • 为执行引擎名称,目前固定为 lua
  • 库名称 可自定义

尝试加载空的库内容,会导致报错

redis> FUNCTION LOAD "#!lua name=mylib\n"
(error) ERR No functions registered

错误的原因是,因为加载的库中没有函数。每个库都需要包含至少一个注册函数才能成功加载。已注册的函数被命名,并充当库的入口点。当目标执行引擎处理FUNCTION LOAD命令时,它会注册库的函数。

Lua引擎在加载时编译和评估库源代码,并期望通过调用register_function()API来注册函数。

#!lua name=mylib
redis.register_function(
  'knockknock',
  function() return 'Who\'s there?' end
)

代码片段演示一个简单的库,它注册了一个名为knockknock的函数,并返回一个字符串回复。redis.register_function方法接收两个参数

  • 函数名称
  • 执行方法

简单演示

接下来加载库内容并使用 FCALL函数执行自定义函数

redis> FUNCTION LOAD "#!lua name=mylib\nredis.register_function('knockknock', function() return 'Who\\'s there?' end)"
mylib
redis> FCALL knockknock 0
"Who's there?"

FCALL 函数提供了两个参数

  • 函数注册名称
  • 参数个数0,表示后面键的数量 跟EVAL用法一致

删除库函数

# 删除mylib的库函数
function delete mylib

输入参数

  1. 定义函数
-- 定义 mylib.lua 文件 内容如下
#!lua name=mylib
local function my_hset(keys, args)
  local hash = keys[1]
  local time = redis.call('TIME')[1]
  return redis.call('HSET', hash, '_last_modified_', time, unpack(args))
end
redis.register_function('my_hset', my_hset)
  1. 注册函数
# 根据lua文件内容 并注册库函数
cat mylib.lua | redis-cli -x FUNCTION LOAD REPLACE

参数说明:

  • redis-cli -x -x选项代表从标准输入(stdin)读取数据作为redis-cli的***一个参数。在这里表示mylib.lua 的内容作为参数
  • REPLACE REPLACE修饰符 告知Redis要覆盖现有的库定义。否则,会收到一个错误,显示库已经存在
  1. 指定函数
redis> FCALL my_hset 1 myhash myfield "some value" another_field "another value"
(integer) 3
redis> HGETALL myhash
1) "_last_modified_"
2) "1640772721"
3) "myfield"
4) "some value"
5) "another_field"
6) "another value"

扩展函数

开发者可以向库中添加更多的函数,以满足不同的需求。如下,添加两个访问hash的方法

-- mylib.lua 文件
#!lua name=mylib

local function my_hset(keys, args)
  local hash = keys[1]
  local time = redis.call('TIME')[1]
  return redis.call('HSET', hash, '_last_modified_', time, unpack(args))
end

local function my_hgetall(keys, args)
  -- 使用RESP3 协议返回数据
  redis.setresp(3)
  local hash = keys[1]
  local res = redis.call('HGETALL', hash)
  res['map']['_last_modified_'] = nil
  return res
end

local function my_hlastmodified(keys, args)
  local hash = keys[1]
  -- 获取hash的最后修改时间
  return redis.call('HGET', hash, '_last_modified_')
end

redis.register_function('my_hset', my_hset)
redis.register_function('my_hgetall', my_hgetall)
redis.register_function('my_hlastmodified', my_hlastmodified)
# 根据lua文件内容 并注册库函数
cat mylib.lua | redis-cli -x FUNCTION LOAD REPLACE
# 调用函数
redis> FCALL my_hgetall 1 myhash
1) "myfield"
2) "some value"
3) "another_field"
4) "another value"
redis> FCALL my_hlastmodified 1 myhash
"1640772721"

代码复用

Redis 函数库另一个优势是,减少重复代码,精简代码,提高复用性。现在在之前的基础上添加参数检查校验的函数

-- mylib.lua 文件
#!lua name=mylib

local function check_keys(keys)
  local error = nil
  local nkeys = table.getn(keys)
  if nkeys == 0 then
    error = 'Hash key name not provided'
  elseif nkeys > 1 then
    error = 'Only one key name is allowed'
  end

  if error ~= nil then
    redis.log(redis.LOG_WARNING, error);
    return redis.error_reply(error)
  end
  return nil
end

local function my_hset(keys, args)
  local error = check_keys(keys)
  if error ~= nil then
    return error
  end

  local hash = keys[1]
  local time = redis.call('TIME')[1]
  return redis.call('HSET', hash, '_last_modified_', time, unpack(args))
end

local function my_hgetall(keys, args)
  local error = check_keys(keys)
  if error ~= nil then
    return error
  end

  redis.setresp(3)
  local hash = keys[1]
  local res = redis.call('HGETALL', hash)
  res['map']['_last_modified_'] = nil
  return res
end

local function my_hlastmodified(keys, args)
  local error = check_keys(keys)
  if error ~= nil then
    return error
  end

  local hash = keys[1]
  return redis.call('HGET', keys[1], '_last_modified_')
end

redis.register_function('my_hset', my_hset)
redis.register_function('my_hgetall', my_hgetall)
redis.register_function('my_hlastmodified', my_hlastmodified)

重新注册加载库函数,并调用函数

127.0.0.1:6379> FCALL my_hset 0 myhash nope nope
(error) Hash key name not provided
127.0.0.1:6379> FCALL my_hgetall 2 myhash anotherone
(error) Only one key name is allowed

同时,Redis服务端也会输出对应的日志

13415:M 12 Dec 2022 21:53:15.581 # Hash key name not provided
13415:M 12 Dec 2022 21:53:21.197 # Only one key name is allowed

集群同步

在Redis 集群部署时 - 关于redis Cluster 集群搭建 请参考,需要考虑到Redis Functions各个节点之间的同步问题,默认情况下函数并不会加载集群中的各个节点,需要人工进行处理,

  • redis-cli --cluster add-node 新增节点会自动将节点函数同步到新节点中

  • edis-cli --cluster-only-masters --cluster call host:port FUNCTION LOAD 将函数同步到各个节点

     cat mylib.lua | redis-cli -x --cluster-only-masters --cluster call localhost:6001 FUNCTION LOAD
    

    在这里插入图片描述

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

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

相关文章

流媒体协议介绍(RTP/RTCP/RTSP/RTMP/MMS/HLS/HTTP/ HTTP-FLV(HDL) /SDP)

流媒体协议介绍&#xff08;RTP/RTCP/RTSP/RTMP/MMS/HLS/HTTP/ HTTP-FLV(HDL) /SDP&#xff09; 一、RTP&#xff1a;实时传输协议&#xff08;Real-time Transport Protocol&#xff09; RTP是一种基于包的传输协议&#xff0c;它用来传输实时数据。在网络上传输数据包的延迟…

艾美捷CD8α体内抗体参数说明化学性质

CD8a&#xff08;Ly 2.2&#xff09;存在于大多数胸腺细胞和包括大多数T抑制/细胞毒性细胞的成熟T淋巴细胞亚群的表面。CD8通过与T细胞受体复合物和蛋白酪氨酸激酶lck的结合参与T细胞活化。 艾美捷CD8α体内抗体基本参数&#xff1a; 中文名称&#xff1a;抗小鼠CD8a体内抗体-…

Kafka极客 - 15 重设消费者位移 Offset

文章目录1. 为什么要重设消费者组位移&#xff1f;2. 重设位移策略3. 消费者 API 方式设置4. 命令行方式设置1. 为什么要重设消费者组位移&#xff1f; 我们知道&#xff0c;Kafka 和传统的消息引擎在设计上是有很大区别的&#xff0c;其中一个比较显著的区别就是&#xff0c;…

怎么看xray发了那些数据包

怎么看xray发了那些数据包。版本说明&#xff1a;Xray 下载地址&#xff1a;https://github.com/chaitin/xray/releases 使用环境&#xff1a;windows、linux、macos皆可 工具说明&#xff1a;Xray扫描器是一款功能强大的安全评估工具。支持主动、被动多种扫描方式&#xff…

UNIAPP实战项目笔记51 登录用户名和密码输入框的数据验证功能

UNIAPP实战项目笔记51 登录账号用户名和密码输入框的数据验证功能 实际案例图片 账号验证 密码验证 登录成功跳转 显示登录和注册页面布局 账号密码的验证功能和登录验证提交 具体内容图片自己替换哈&#xff0c;随便找了个图片的做示例 具体位置见目录结构 完善布局页面和样式…

基于PHP和MySQL的新闻发布系统

关于世界杯⚽️ 国际足联世界杯&#xff08;FIFA World Cup&#xff09;&#xff0c;简称“世界杯”&#xff0c;是由全世界国家级别球队参与&#xff0c;象征足球界最高荣誉&#xff0c;并具有最大知名度和影响力的足球赛事。世界杯全球电视转播观众超过35亿 。世界杯每四年举…

【设计模式】简单工厂模式描述总结

简单工厂模式 定义&#xff1a;定义一个创建对象的接口&#xff0c;让子类决定实例化哪一个类。 类型&#xff1a;创建型模式 介绍&#xff1a; 在简单工厂模式中定义一个抽象产品类&#xff0c;抽象产品类声明公共的特性及属性&#xff0c;具体产品类继承抽象产品类后去实…

Educational Codeforces Round 121 (Rated for Div. 2) C. Monsters And Spells

翻译&#xff1a; Monocarp又在玩电脑游戏了。他是个巫师学徒&#xff0c;只会一个咒语。幸运的是&#xff0c;这个法术可以伤害怪物。 他目前所在的关卡包含&#x1d45b;个怪物。他们中的&#x1d456;-th在关卡开始后&#x1d458;&#x1d456;秒出现&#xff0c;并拥有ℎ…

Java石头剪刀布

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;JAVA开发者…

【iMessage苹果源码家庭推】tils扩大软件安装大概释放事变是由程序员筑造的,很轻易发生MemoryLeak控制

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

[附源码]计算机毕业设计的小区宠物管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

小侃设计模式(十七)-中介者模式

1.概述 中介者模式&#xff08;Mediator Pattern&#xff09;是用来降低多个对象和类之间的通信复杂性&#xff0c;这种模式提供了一个中介类&#xff0c;来封装一组对象之间的交互&#xff0c;它将对象之间的交互委派给中介对象交互&#xff0c;避免了对象之间的直接交互。中…

Vue2基础总结

知识点学了太多还是需要总结复习&#xff0c;否则后面会因为零碎的知识点而感到繁杂&#xff0c;那么今天我来总结一下vue相关的知识点&#xff0c;新学习vue的朋友也可以把这当做一个细致总结&#xff1a; 1.Vue是什么&#xff08;重点&#xff09;&#xff1a; 对于Vue的总…

创建 Vue3.0 工程

1.使用 vue-cli 创建 官方文档 : https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create // 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.以上 vue --version vue -V// 安装或者升级你的vue/cli、 覆盖安装最新版本; npm install -g vue/cli//1.创建…

C++初阶 stack和queue的模拟实现

作者&#xff1a;小萌新 专栏&#xff1a;C初阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;模拟实现STL库中的stack和queue 考试周结束咯 狠狠的学&#xff01; stack和queue的模拟实现容器适配器Stack模拟实现接口函数一览代码…

艾美捷西妥昔单抗Cetuximab化学性质和文献参考

西妥昔单抗&#xff08;抗EGFR&#xff09;是表皮生长因子受体&#xff08;EGFR&#xff09;的抑制剂。 艾美捷西妥昔单抗Cetuximab 品名&#xff1a;西妥昔单抗&#xff0c;抑制剂 完整名称&#xff1a;西妥昔单抗&#xff08;抗EGFR&#xff09; 同义词名称&#xff1a;C2…

2022年电动车与车辆工程国际会议(CEVVE 2022)

2022年电动车与车辆工程国际会议&#xff08;CEVVE 2022&#xff09; 重要信息 会议网址&#xff1a;www.cevve.org 会议时间&#xff1a;2022年12月19-21日 召开地点&#xff1a;中国北海 截稿时间&#xff1a;2022年12月15日 录用通知&#xff1a;投稿后2周内 收录检索…

CPU、内存占用率高排查

CPU高占用 排查思路 top 命令查看CPU占用率高的进程top -H -p ${pid} 命令查看具体是进程的哪个线程占用CPUprintf ‘%x\n’ ${pid} 将线程的pid转为16进制jstack ${十六进制pid} | grep -A 20 查看线程的基本信息与方法调用栈 模拟排查 [rootVM-24-5-centos www]# top top…

vue可视化管理工具创建项目报错解决errno: -4058;连接超时

vue可视化管理工具创建项目报错解决errno: -4058 简介&#xff1a;vue创建项目时&#xff0c;errno&#xff1a;-4058问题解决&#xff0c;使用vue ui指令时会报连接超时问题解决。 基础材料&#xff1a; 使用的node.js版本&#xff1a;18.12.1 vue版本&#xff1a;4.5.15…

【shell脚本】监控磁盘/内存使用率·检测域名是否正常·一键部署LMNP·拉黑攻击服务器的异常ip

文章目录1、监控2台服务器硬盘利用率脚本实战2、批量检查 5个网站域名是否正常3、统计磁盘使用率&#xff0c;磁盘大于%5 就打印mail 小于 硬盘正常 内存也是一样4、有人攻击我服务器 就拉黑异常ip5、使用for循环安装 批量安装3台服务器 php环境 使用&#xff08;LAMP&#xff…