首先,让我们先回顾一下上一篇讲的在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/manual/programmability/functions-intro/

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

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

Redis Functions 介绍之二的更多相关文章

  1. Redis(二):Redis入门介绍

    Redis入门介绍目录导航: 入门概述 VMWare + VMTools千里之行始于足下 Redis的安装 Redis启动后杂项基础知识讲解 入门概述 是什么 Redis:REmote DIction ...

  2. redis学习(二) redis数据结构介绍以及常用命令

    redis数据结构介绍 我们已经知道redis是一个基于key-value数据存储的数据结构数据库,这里的key指的是string类型,而对应的value则可以是多样的数据结构.其中包括下面五种类型: ...

  3. Redis安装介绍

    Redis安装介绍 一.Linux版本及配置 1.  Linux版本:Red Hat Enterprise Linux 6虚拟机 2.  配置: 内存:1G:CPU:1核:硬盘:20G 二.Redis ...

  4. Redis学习笔记(二)-key相关命令【转载】

    转自 Redis学习笔记(二)-key相关命令 - 点解 - 博客园http://www.cnblogs.com/leny/p/5638764.html Redis支持的各种数据类型包括string, ...

  5. Redis 小白指南(二)- 基础命令和五大类型:字符串、散列、列表、集合和有序集合

    Redis 小白指南(二)- 基础命令和五大类型:字符串.散列.列表.集合和有序集合 引言 目录 基础命令 字符串类型 散列类型 列表类型 集合类型 有序集合类型 基础命令 1.获得符合规则的键名列表 ...

  6. NoSQL数据库之Redis数据库:Redis的介绍与安装部署

     NoSQL(NoSQL = Not Only SQL),它指的是非关系型的数据库.随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的w ...

  7. Redis 小白指南(二)- 聊聊五大类型:字符串、散列、列表、集合和有序集合

    Redis 小白指南(二)- 聊聊五大类型:字符串.散列.列表.集合和有序集合 引言 开篇<Redis 小白指南(一)- 简介.安装.GUI 和 C# 驱动介绍>已经介绍了 Redis 的 ...

  8. 4 Redis 配置文件介绍

    2016-12-22 14:28:39 该系列文章链接NoSQL 数据库简介Redis的安装及及一些杂项基础知识Redis 的常用五大数据类型(key,string,hash,list,set,zse ...

  9. 第五章· Redis主从复制介绍

    一.Redis主从复制 二.Redis主从复制工作机制 一.Redis主从复制 Redis复制功能简单介绍 1)使用异步复制.2)一个主服务器可以有多个从服务器.3)从服务器也可以有自己的从服务器.4 ...

  10. redis cluster介绍

    讲解分布式数据存储的核心算法,数据分布的算法 hash算法 -> 一致性hash算法(memcached) -> redis cluster,hash slot算法 一.概述 1.我们的m ...

随机推荐

  1. go install 和 go get的区别

    go install 和 go get 都是 Go 语言中的命令行工具,用于处理依赖关系和安装包.它们的主要区别在于功能和使用场景. go install: 功能:go install 命令用于编译并 ...

  2. Llama 2 来袭 - 在 Hugging Face 上玩转它

    引言 今天,Meta 发布了 Llama 2,其包含了一系列最先进的开放大语言模型,我们很高兴能够将其全面集成入 Hugging Face,并全力支持其发布. Llama 2 的社区许可证相当宽松,且 ...

  3. centos7升级内核到最新稳定版

    前言 centos7默认的内核版本才3.10,诸如VXLAN.eBPF等特性无法体验,因此需要升级.目前(2022.02)Linux的内核版本已更新到5.16. 步骤 更新仓库 yum update ...

  4. jmeter对请求响应结果进行整段内容提取方法

    通过正则表达式提取器,将上一个请求(A请求)响应数据中的整段内容提取,传给下一个需要该提取数据的请求(B请求). 1. 请求接口响应结果 2. 添加正则表达式提取器 设置变量名为"tt&qu ...

  5. LabVIEW图形化TensoRT工具包的安装下载分享

    前言 Hello,大家好,我是virobotics(仪酷智能)今天我们一起来看一下如何安装[LabVIEWTensoRT工具包]. 一.LabVIEW图形化TensoRT工具包简介 工具包特点: 图形 ...

  6. 【JMeter】常用线程组设置策略

    常用线程组设置策略 目录 常用线程组设置策略 一.前言 二.单场景基准测试 1.介绍 2.线程组设计 3.测试结果 三.单场景并发测试 1.介绍 2.线程组设计 3.测试结果 四.单场景容量/爬坡测试 ...

  7. [Qt开发探幽(二)]浅谈关于元对象,宏和Q_ENUM

    目录 [Qt开发探幽(二)]浅谈关于元对象,宏和Q_ENUM 前言 一.元对象 但是 二.关于Q_OBJECT等宏属性 1.元对象系统 2.信号与槽 3.属性系统 三.关于Q_ENUMS 1.将其注册 ...

  8. iOS日志获取

    IOS日志获取 崩溃日志存放目录: /var/mobile/Library/Logs/CrashReporter

  9. 【项目源码】基于JavaEE的健康管理系统

    随着网络技术的不断发展,网站的开发与运用变得更加广泛.这次采用java语言SSH框架(Spring,Struts,Hibernate)设计并实现了面向特定群体的健康管理平台.该网站主要有教师饮食管理. ...

  10. SQL - 5

    Smiling & Weeping ----我本不想和风讨论你,可风说可以替我去见你 第五章:SQL高级处理 5.1 窗口函数 5.1.1 窗口函数概念及基本的使用方法 窗口函数也称为OLAP ...