首页 > 数据库 >Redis Functions 介绍之二

Redis Functions 介绍之二

时间:2023-11-10 17:31:36浏览次数:44  
标签:function Functions keys Redis local redis 之二 key my

首先,让我们先回顾一下上一篇讲的在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感兴趣的开发者的支持。

标签:function,Functions,keys,Redis,local,redis,之二,key,my
From: https://blog.51cto.com/u_13739602/8305594

相关文章

  • docker redis
    dockerrun--restart=always-p6379:6379--nameredis-dredis:latest--requirepass123456dockerrun--restart=always\-p6379:6379\--nameredis\-v/opt/redis/conf/redis.conf:/etc/redis/redis.conf\-v/opt/redis/data:/data\-dredisredis-s......
  • redis 6个节点(3主3从),始终一个节点不能启动
    redis节点,始终有一个节点不能启动起来1.修改了配置文件protected-modeno,重启修改了配置文件protected-modeno,重启redis问题依然存在2、查看/var/log/message的redis日志Aug2107:40:33redisMasterkernel:Outofmemory:Killprocess31814(redis-server)score193ors......
  • redis数据类型
    ·Redis常见数据类型string可存储三种类型值:字符串整数浮点数string是最基本的类型,value可以是数字、字符串或者二进制数据。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象。常用于缓存、计数、共享session,分布式锁进......
  • redis 类型Hash 中value存储空间大小
    在Redis中,Hash数据类型的存储空间大小取决于存储在Hash中的键值对的数量以及每个键值对的键和值的大小。Redis内部会根据实际存储的数据进行动态分配内存,因此存储空间大小是可变的。下面是关于Hash数据类型中value存储空间大小的一些考虑因素:键值对数量:Hash中的键值对数量是主要影......
  • Windows下绿色版Redis安装与配置
    介绍官网:https://redis.ioRedis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。NoSql(NotOnlySQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不......
  • 【主流技术】聊一聊 Redis 的基本结构和简单应用(一)
    目录前言一、String类型二、List类型三、Hash类型四、Set结构五、SortSet(Zset)结构六、文章小结前言Redis是目前互联网后端的热门中间件之一,在许多方面都有深度的应用,作为后端开发熟练掌握该技术是十分有必要的。Redis的五种数据类型是:1、String(字符串);2、Hash(哈希);3、L......
  • Redis分片集群
    搭建分片集群主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:●海量数据存储问题●高并发写的问题使用分片集群可以解决.上述问题,分片集群特征:●集群中有多个master,每个master保存不同数据●每个master都可以有多个slave节点●master之间通过ping监测彼......
  • 无涯教程-批处理 - Local Variables in Functions函数
    函数中的局部变量可用于避免名称冲突,并将变量更改保持在函数本地,首先使用SETLOCAL命令来确保命令处理器备份所有环境变量,可以通过调用ENDLOCAL命令来恢复变量,当到达批处理文件的末尾时,即通过调用GOTO:EOF,将自动调用ENDLOCAL。使用SETLOCAL对变量进行本地化允许在函数内自由使用......
  • 无涯教程-批处理 - Functions with Return Values函数
    函数可以通过简单地传递变量名称来使用返回值,这些变量名称将在调用函数时保存返回值,如下所示Call:function_namevalue1,value2…valuen使用set命令和tilde(〜)字符以及参数的位置编号在函数中设置返回值。下面的示例演示如何使用返回值调用函数。@echooffSETLOCALCALL......
  • Redis队列和阻塞队列
    redis队列的优点是轻量级,业务足够简单时不需要使用rabbitMq这样专业的消息中间件;缺点是弹出队列中的元素时,即使该消息处理失败也无法再次进行消费Redis队列List简单演示如下普通的redis队列,为了实现业务,通常会使用while进行循环,这样的话没有消息时依旧会频繁的执行循环,造成cpu的......