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

Redis Functions 介绍(二)

首先,让我们先回顾一下上一篇讲的在Redis Functions中关于将key的名字作为参数和非key名字作为参数的区别,先看下面的例子

首先,我们先在一个Lua脚本文件mylib.lua中定义如下的库和函数

//--------------------mylib.lua 文件开始 ----------- //

#!lua name= mylib

local function my_hset(keys, args)

    local hash = keys[1]

    local time = redis.call('TIME')[1]     //这一行的目的是执行TIME命令得到当前的服务器时间

    return redis.call('HSET', hash, '_last_modified_', time, unpack(args))

end

redis.register_function('my_hset', my_hset)

//--------------------mylib.lua 文件结束 ----------- //

然后我们在命令行中运行如下命令:

$ cat mylib.lua | redis-cli -x FUNCTION LOAD

"mylib"

当我们再运行如下FCALL命令时候,我们会得到如下的结果:

redis> FCALL my_hset 1 myhash_key first_field "first value" second_field "second value"

(integer) 3

上面命令的my_hset是函数名,1代表第一个参数myhash_key是key名,后面的first_field "first value" second_field "second value" 都是这个key: myhash_key的field:value对

我们通过在Redis客户端运行 HGETALL myhash_key可以查看到相对应的结果:

redis> HGETALL myhash_key

1) "_last_modified_"

2) "1659536487"

3) "first_field"

4) "first value"

5) "second_field"

6) "second value"

好了,在复习完了上一篇Redis Functions的内容之后,我们可以看到上面的例子中mylib库中只包含了一个函数my_hset, 事实上在一个库中可以包括多个函数,在下面的例子中我们要添加另外2个function: my_hgetall  与 my_hlastmodified.

其中,函数my_hgetall相当于在redis 客户端执行hgetall命令,而my_hlastmodified函数返回的是传入的key中_last_modified这一个field的值

首先,让我们在mylib.lua中添加这两个function

local function my_hgetall(keys, args)

    local hash = keys[1]

    local res = redis.call('HGETALL', hash)

    return res

end

local function my_hlastmodified(keys, args)

    local hash = keys[1]

    return redis.call('HGET', keys[1], '_last_modified_')

end

然后,在mylib中注册这两个函数

redis.register_function('my_hgetall', my_hgetall)

redis.register_function('my_hlastmodified', my_hlastmodified)

因为我们要在mylib库中新增两个函数,所以我们需要运行如下的命令

$ cat mylib.lua | redis-cli -x FUNCTION LOAD REPLACE

"mylib"

接下来我们运行my_hgetall函数与my_hlastmodified

redis> FCALL my_hgetall 1 myhash_key

1) "_last_modified_"

2) "1659536487"

3) "first_field"

4) "first value"

5) "second_field"

6) "second value"

redis> FCALL my_hlastmodified 1 myhash_key

"1659536487"

最后我们可以通过FUNCTION LIST命令来查看当前所有的Redis Function的库及其包含的函数信息。下面我们来查看一下当前库mylib中包括的3个function的信息

127.0.0.1:6381> FUNCTION list

1) 1) "library_name"

   2) "mylib"

   3) "engine"

   4) "LUA"

   5) "functions"

   6) 1) 1) "name"

         2) "my_hset"

         3) "description"

         4) (nil)

         5) "flags"

         6) (empty array)

      2) 1) "name"

         2) "my_hlastmodified"

         3) "description"

         4) (nil)

         5) "flags"

         6) (empty array)

      3) 1) "name"

         2) "my_hgetall"

         3) "description"

         4) (nil)

         5) "flags"

         6) (empty array)

在Redis的官方文档中,我们发现我们可以在库中定义一个function供库中的其他函数使用,在官方的使用说明,它给出了一个例子用于错误检测。我们下面来看看这个例子

定义一个check_keys的函数,用来检测客户端调用的redis function的函数输入的key是否存在并且只有一个

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

相应的,我们也需要修改已经有的3个函数,让他们去调用新增的check_keys函数

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

    local hash = keys[1]

    local res = redis.call('HGETALL', hash)

    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

这里要注意一点,在上面地例子中,如果我们运行FCALL:

redis> FCALL my_hgetall 1 myhash_key

1) "_last_modified_"

2) "1659536487"

3) "first_field"

4) "first value"

5) "second_field"

6) "second value"

我们可以看到运行是正常地,但是如果我们运行FCALL_RO:

redis> FCALL_RO my_hgetall 1 myhash_key

(error) ERR Can not execute a script with write flag using *_ro command.

我们会收到一个错误。这是为什么呢?

事实上,函数my_hgetall的目的只是从数据中读取数据,并没有写操作。但是当我们定义它的时候,并没有标注它是只读属性

local function my_hgetall(keys, args)

    local hash = keys[1]

    local res = redis.call('HGETALL', hash)

    return res

end

所以这个时候,当我们用命令FCALL_RO就会返回一个错误:Can not execute a script with write flag using *_ro command

所以为了可以让FCALL_RO执行一个只读属性的函数,我们需要对my_hgetall的注册方式进行一下修改:

redis.register_function{

    function_name='my_hgetall',

    callback=my_hgetall,

    flags={ 'no-writes' }

}

这个时候,我们再运行FCALL_RO命令时候,我们就会得到正确的结果了

redis> FCALL_RO my_hgetall 1 myhash_key

1) "_last_modified_"

2) "1659536487"

3) "first_field"

4) "first value"

5) "second_field"

6) "second value"

下面我们来看看Redis functions是如何在集群中运行的

在非集群状态时候,如果有主从节点,那么主节点上的function会自动地被复制到从节点,这与function创建地初衷也是一致地:Redis认为Functions是数据库的一部分,是可以持久化的,并且也是可以复制的。

但是,如果function是存在于集群的几点中,那么就有一些不一样的特性了。Redis function无法被自动地加载到集群中地所有节点,而需要被管理员手动地将function加载到集群中地每个节点中。要加载Redis function在集群中地节点,可以运行如下地命令:

redis-cli --cluster-only-masters --cluster call host:port FUNCTION LOAD [REPLACE] function-code

如果运行命令:

redis-cli --cluster add-node

那么这个时候集群中已经存在的节点会将已经加载地function自动地传播到新加入集训地节点

使用Redis Function的其他的注意事项

如果一个已经加载Redis Function的节点需要重启,那么在重启之前建议先运行命令:

redis-cli --functions-rdb

这样会将已经存在于节点上的Redis function存到一个RDB文件中,当这个节点重启之后可以直接加载这个rdb文件,就不需要再手工加载每一个function了,大大地节省了时间和减少错误机率

本篇文章引用了部分Redis官方文档的例子, 大家可以从链接去查看和运行一下。

https://redis.io/docs/interact/programmability/functions-intro/

下一篇博客我们开始分析Redis function的源码,让我们深入探讨一下这个Redis新特性内部是如何执行,欢迎继续关注Redis Functions系列博客

最后,感谢Redis社区的所有贡献者的努力工作,及所有对Redis感兴趣的开发者的支持

相关文章:

Redis Functions 介绍(二)

首先,让我们先回顾一下上一篇讲的在Redis Functions中关于将key的名字作为参数和非key名字作为参数的区别,先看下面的例子 首先,我们先在一个Lua脚本文件mylib.lua中定义如下的库和函数 //--------------------mylib.lua 文件开始 --------…...

R语言环境下使用curl库做的爬虫代码示例

curl库是一个用于传输数据的工具和库,它支持多种协议,包括HTTP、FTP、SMTP等。在爬虫中,curl库可以用来获取网页内容,从而实现爬取网页的功能。通过设置curl的选项,可以实现对网页的请求、响应、重定向等操作。在使用c…...

【论文阅读】Equivariant Contrastive Learning for Sequential Recommendation

【论文阅读】Equivariant Contrastive Learning for Sequential Recommendation 文章目录 【论文阅读】Equivariant Contrastive Learning for Sequential Recommendation1. 来源2. 介绍3. 前置工作3.1 序列推荐的目标3.2 数据增强策略3.3 序列推荐的不变对比学习 4. 方法介绍4…...

智行破晓,驭未来航程!——经纬恒润智能驾驶数据闭环云平台OrienLink重磅来袭

2023是被AI技术标记的⼀年。年初,OpenAI的GPT崭露头角;6月,Tesla在CVPR2023上对World Model进行深度解读;8月,SIGGRAPH见证GH200、L40S显卡和ChatUSD的登场,FSD V12彰显端到端智能驾驶的实力;9月…...

深入理解WPF中的依赖注入和控制反转

在WPF开发中,依赖注入(Dependency Injection)和控制反转(Inversion of Control)是程序解耦的关键,在当今软件工程中占有举足轻重的地位,两者之间有着密不可分的联系。今天就以一个简单的小例子&…...

【CIO人物展】国家能源集团信息技术主管王爱军:中国企业数智化转型升级的内在驱动力...

王爱军 本文由国家能源集团信息技术主管王爱军投递并参与《2023中国数智化转型升级优秀CIO》榜单/奖项评选。丨推荐企业—锐捷网络 大数据产业创新服务媒体 ——聚焦数据 改变商业 随着全球信息化和网络化的进程日益加速,数字化转型已经成为当下各大企业追求的核心…...

(后续补充)vue+express、gitee pm2部署轻量服务器

首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 关闭防火墙 systemctl stop firewalld 重新载入防火墙使设置生效 firewall-cmd --reload 后端的 pm2.config.cjs …...

第G7周:Semi-Supervised GAN 理论与实战

🍨 本文为🔗365天深度学习训练营 中的学习记录博客 🍦 参考文章:365天深度学习训练营-第G7周:Semi-Supervised GAN 理论与实战(训练营内部成员可读) 🍖 原作者:K同学啊|接…...

美国Embarcadero产品经理Marco Cantù谈Delphi/C++ Builder目前开发应用领域

美国Embarcadero产品经理Marco Cant 日前在欧洲的一次信息技术会议上谈到了Delphi/C Builder目前开发应用领域:RAD Studio Delphi/C Builder目前应用于哪些开发领域?使用 Delphi 和 CBuilder 进行开发为当今众多企业提供了动力。 航空航天 大型数据采集 …...

【iOS】——知乎日报第三周总结

文章目录 一、获取新闻额外信息二、工具栏按钮的布局三、评论区文字高度四、评论区长评论和短评论的数目显示五、评论区的cell布局问题和评论消息的判断 一、获取新闻额外信息 新闻额外信息的URL需要通过当前新闻的id来获取,所以我将所有的新闻放到一个数组中&…...

leetcode每日一题-周复盘

前言 该系列文章用于我对一周中leetcode每日一题or其他不会的题的复盘总结。 一方面用于自己加深印象,另一方面也希望能对读者的算法能力有所帮助。 该复盘对我来说比较容易的题我会复盘的比较粗糙,反之较为细致 解答语言:Golang 周一&a…...

[NLP] LlaMa2模型运行在Mac机器

本文将介绍如何使用llama.cpp在MacBook Pro本地部署运行量化版本的Llama2模型推理,并基于LangChain在本地构建一个简单的文档Q&A应用。本文实验环境为Apple M1 芯片 8GB内存。 Llama2和llama.cpp Llama2是Meta AI开发的Llama大语言模型的迭代版本,…...

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(六)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 这节主要讲条件节点与并发节点的有效性检查,主要是增加这两个节点的子节点检查,因为…...

听GPT 讲Rust源代码--library/std(15)

题图来自 An In-Depth Comparison of Rust and C[1] File: rust/library/std/src/os/wasi/io/fd.rs 文件路径:rust/library/std/src/os/wasi/io/fd.rs 该文件的作用是实现与文件描述符(File Descriptor)相关的操作,具体包括打开文…...

腾讯云CVM服务器操作系统镜像大全

腾讯云CVM服务器的公共镜像是由腾讯云官方提供的镜像,公共镜像包含基础操作系统和腾讯云提供的初始化组件,公共镜像分为Windows和Linux两大类操作系统,如TencentOS Server、Windows Server、OpenCloudOS、CentOS Stream、CentOS、Ubuntu、Deb…...

Mxnet框架使用

目录 1.mxnet推理API 2.MXNET模型转ONNX 3.运行示例 1.mxnet推理API # 导入 MXNet 深度学习框架 import mxnet as mx if __name__ __main__:# 指定预训练模型的 JSON 文件json_file resnext50_32x4d # 指定模型的参数文件params_file resnext50_32x4d-0000.params # 使…...

每个程序员都应该自己写一个的:socket包装类

每个程序员都应该有自己的网络类。 下面是我自己用的socket类,支持所有我自己常用的功能,支持windows和unix/linux。 目录 客户端 服务端 非阻塞 获取socket信息 完整代码 客户端 作为socket客户端,只需要如下几个功能: //…...

JMeter:断言之响应断言

一、断言的定义 断言用于验证取样器请求或对应的响应数据是否返回了期望的结果。可以是看成验证测试是否预期的方法。 对于接口测试来说,就是测试Request/Response,断言即可以针对Request进行,也可以针对Response进行。但大部分是对Respons…...

RLHF的替代算法之DPO原理解析:从Zephyr的DPO到Claude的RAILF

前言 本文的成就是一个点顺着一个点而来的,成文过程颇有意思 首先,如上文所说,我司正在做三大LLM项目,其中一个是论文审稿GPT第二版,在模型选型的时候,关注到了Mistral 7B(其背后的公司Mistral AI号称欧洲…...

U盘显示无媒体怎么办?方法很简单

当出现U盘无媒体情况时,您可以在磁盘管理工具中看到一个空白的磁盘框,并且在文件资源管理器中不会显示出来。那么,导致这种问题的原因是什么呢?我们又该怎么解决呢? 导致U盘无媒体的原因是什么? 当您遇到上…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...