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感兴趣的开发者的支持

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

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

相关文章

SpringBoot项目从resources目录读取文件

SpringBoot 从 resources 读取文件 使用 Spring 给我们提供的工具类来进行读取 File file org.springframework.util.ResourceUtils.getFile("classpath:人物模板.docx");可能读取失败,出现如下错误: java.io.FileNotFoundException: clas…

C语言实现九九乘法表

学习C语言后&#xff0c;我们会发现打印九九乘法表是很简单的&#xff0c;话不多说&#xff0c;我们上代码&#xff01; 目录 1.函数代码 2.运行结果 1.函数代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int i 1;int j 1;int n 0;//行数in…

Instant-NGP论文笔记

文章目录 论文笔记 论文笔记 instant-ngp的nerf模型与vanilla nerf的模型架构相同。 instant-ngp的nerf模型包含两个MLP&#xff0c;第一个MLP就两个全连接&#xff0c;输入维度是32&#xff08;16层分辨率x2&#xff09;&#xff0c;输出是16&#xff08;用于预测密度&#x…

【LeetCode每日一题合集】2023.9.18-2023.9.24(⭐拓扑排序⭐设计数据结构:LRU缓存实现 LinkedHashMap⭐)

文章目录 337. 打家劫舍 III&#xff08;树形DP&#xff09;2560. 打家劫舍 IV&#xff08;二分查找动态规划&#xff09;LCP 06. 拿硬币&#xff08;简单贪心模拟&#xff09;2603. 收集树中金币⭐思路——拓扑排序删边 2591. 将钱分给最多的儿童&#xff08;分类讨论&#xf…

记一次pdjs时安装glob出现,npm ERR! code ETARGET和npm ERR! code ELIFECYCLE

如往常一样&#xff0c;我使用pdjs来编译proto文件&#xff0c;但出现了以下报错&#xff1a; 大致就是pdjs的util在尝试执行npm install glob^7.2.1 escodegen^1.13.0时出错了 尝试手动执行安装&#xff0c;escodegen被正确安装&#xff0c;但glob^7.2.1出错 npm ERR! code E…

Redis那些事儿(三)

文章目录 1. 前言2. 常用api介绍3. 需求假设&#xff08;获取离我最近的停车场&#xff09;4. 代码示例 1. 前言 接着上一篇Redis那些事儿&#xff08;二&#xff09; &#xff0c;这一篇主要介绍Redis基于Geo数据结构实现的地理服务&#xff0c;它提供了一种方便的方式来存储和…

库房管理软件采购申请流程代码实现解析

300rmb掏了个javavue2的小系统&#xff0c;学习代码&#xff0c;调整下申请流程。 原有的入库流程是&#xff0c;库管&#xff08;admin&#xff09;提出采购申请给采购员&#xff08;caigou&#xff09;&#xff0c;采购员采购入库时点击入库完成采购入库流程。 想弄清后端代…

非关系型数据库Redis的安装【Linux】及常用命令

前言 Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的内存数据库管理系统&#xff0c;它以键值存储方式来存储数据&#xff0c;并且支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等。Redis最初由Salvatore Sanfilippo开发&#xff0c…

数据分析实战 | 关联规则分析——购物车分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据预处理 七、生成频繁项集 八、计算关联度 九、可视化 一、数据及分析对象 数据集链接&#xff1a;Online Retail.xlsx 该数据集记录了2010年12月01日至2011年12月09日…

Docker 修改镜像的Digests值

最近工作中遇到个事情&#xff0c;我在本地虚拟机导出的镜像&#xff0c;导入到服务器发现镜像的digests是<none>&#xff0c;网上找了半天发现没有相关的解决方案&#xff0c;服务器上的源码是通过镜像的hash值拉取镜像没有Tag&#xff0c;镜像digests为<none>很痛…

21. 合并两个有序链表

Problem: 21. 合并两个有序链表 文章目录 思路1 递归实现2 迭代实现 Code 思路 方法1 递归实现 方法2 迭代实现 1 递归实现 分析问题 对于本题&#xff0c;合并两个有序链表A和B&#xff0c;mergeTwoLists&#xff08;A,B&#xff09;&#xff0c;递归只需要关注本层我要干什么…

性能优于BERT的FLAIR:一篇文章入门Flair模型

文章目录 What is FLAIR&#xff1f;FLAIR ModelContextual String Embedding for Sequence Labelingexample FLAIR Application AreaSentiment AnalysisNamed Entity RecognitionText Classification FLAIR一、什么是FLAIR&#xff1f;二、FLAIR Library的优势是什么&#xff…

23年面试总结

网易一面 231026 0、介绍下你自己 1、具体负责的工作内容 系统的建设与维护工作。环境搭建与维护、巡检、容量规划、CICD流水线管理、可观测指标建立、监控告警处理&#xff0c;用户的请求事件问题处 2、介绍一下http协议 http协议&#xff08;hyper text transfer protoco…

突破性技术!开源多模态模型—MiniGPT-5

多模态生成一直是OpenAI、微软、百度等科技巨头的重要研究领域&#xff0c;但如何实现连贯的文本和相关图像是一个棘手的难题。 为了突破技术瓶颈&#xff0c;加州大学圣克鲁斯分校研发了MiniGPT-5模型&#xff0c;并提出了全新技术概念“Generative Vokens "&#xff0c…

❤️ React的安装和使用(实战篇)

React的安装和使用 一、React的安装和使用 reactJs警告提示&#xff1a; This version of tar is no longer supported, and will not receive security updates. Please upgrade asap 翻译&#xff1a;tar2.2.2&#xff1a;此版本的tar不再受支持&#xff0c;将不会收到安全…

golang实现极简todolist

ToDoList 最近跟着qimi老师做了一个ToDoList&#xff0c;我做的GitHub地址贴在这里&#xff0c;但由于前端出了点问题&#xff0c;所以都是用postman进行测试 原项目地址 部分功能展示 删除代办 查找代办 下面给出思路 思路 其实这是一个很简单的增删改查的实现&#xff…

linux下使用vscode对C++项目进行编译

项目的目录结构 头文件swap.h 在自定义的头文件中写函数的声明。 // 函数的声明 void swap(int a,int b);swap.cpp 导入函数的声明&#xff0c;写函数的定义 #include "swap.h" // 双引号表示自定义的头文件 #include <iostream> using namespace std;// 函…

QR码应用实战:Spring Boot与ZXing完美结合

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 QR码应用实战&#xff1a;Spring Boot与ZXing完美结合 前言第一&#xff1a; 介绍QR码和ZXing第二&#xff1a;springboot整合zxing添加ZXing依赖生成二维码生成条形码 前言 …

LeetCode.6 N字形变换

一开始想的是真的创建一个数组 去按照题目所给的要求填入数据 最后输出不为空的数组项 但是不仅时间复杂度高 而且错误频繁出现 最终也没有提交成功 查阅题解后发现数组并不重要 假设我们忽略掉数组中的那些空白项 最终输出的结果就是numRows行的字符串的拼接 string conver…

HCIE-kubernetes(k8s)-Authentication身份验证

1、远程登录 1、kubeconfig方式 在master上都是以kubeconfig方式登录的&#xff0c;并不是说有一个文件叫kubeconfig。 默认使用的配置文件是~/.kube/config 这个配置文件&#xff0c;而这个配置文件是通过这个文件/etc/kubernetes/admin.conf 如果在node上执行命令&#xff…