golang redis lua脚本 和 lua function

lua script

go 复制代码
package redisx

import (
	"github.com/redis/go-redis/v9"
)

var GetOrSet = redis.NewScript(`
	local res = redis.call('GET', KEYS[1])
	if res ~= nil then
		return res
	end
	redis.call('SET', KEYS[1], ARGV[1])
	return ARGV[1]
`)

func Script() {
	redisClient := redis.NewClient(。。。) // 此次内容省略
	ret, err := GetOrSet.Run(context.Background(), redisClient, []string{"123"}, "654").Result()
	if err != nil {
		panic(err)
	}
	res := ret.(string)
	fmt.Println(res)
}

lua function

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的逻辑,存储在服务端,客户端要做的仅仅是调用函数即可

script.lua

lua 复制代码
#!lua name=LibName
-- 注意:这一句设置namespace一定要加,要不然redis加载lua脚本的时候会报错,ERR Missing library metadata,
local function GetOrSet(KEYS, ARGV)
    local key = KEYS[1]
    local value = ARGV[1]
    local ttl = ARGV[2]
    local result = redis.call('GET', key)
    if result  then
        value = result..value
    end
    redis.call('SET', key, value)
    redis.call('EXPIRE', key, ttl)
    return value
end

redis.register_function('GetOrSet', GetOrSet)

redisx.go

复制代码
fs, err := os.Open("./script.lua")
	if err != nil {
		return
	}
	defer func(fs *os.File) {
		err := fs.Close()
		if err != nil {
			panic(err)
		}
	}(fs)
	binData, err := io.ReadAll(fs)
	if err != nil {
		panic(err)
	}
	if len(binData) == 0 {
		panic("binData is empty")
	}

	redisClient := redis.NewClient(。。。) // 此次内容省略
	err = redisClient .FunctionLoadReplace(context.Background(), string(binData)).Err()
	if err != nil {
		panic(err)
	}

	ret, err := redisClient .FCall(context.Background(), "GetOrSet", []string{"123"}, "654", 20).Result()
	if err != nil {
		panic(err)
	}

	res := ret.(string)
	fmt.Println(res)
相关推荐
liguojun20252 天前
软硬一体智慧场馆系统推荐——助力场馆数字化高效升级
java·大数据·人工智能·物联网·1024程序员节
开开心心就好14 天前
吾爱大佬原创的文件时间修改工具
安全·智能手机·pdf·电脑·智能音箱·智能手表·1024程序员节
开开心心就好18 天前
近200个工具的电脑故障修复合集
安全·智能手机·pdf·电脑·consul·memcache·1024程序员节
数据皮皮侠AI20 天前
中国城市可再生能源数据集(2005-2021)|顶刊 Sci Data 11 种能源面板
大数据·人工智能·笔记·能源·1024程序员节
计算机毕业论文辅导23 天前
物联网实战:基于MQTT协议的智能家居数据传输系统设计与实现
1024程序员节
开开心心就好24 天前
支持批量处理的视频分割工具推荐
安全·智能手机·rust·pdf·电脑·1024程序员节·lavarel
liuyao_xianhui1 个月前
Linux开发工具结尾 _make
linux·运维·服务器·数据结构·哈希算法·宽度优先·1024程序员节
学传打活1 个月前
【边打字.边学昆仑正义文化】_21_爱的结晶(1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
数据皮皮侠AI1 个月前
顶刊同款!中国地级市风灾风险与损失数据集(2000-2022)|灾害 / 环境 / 经济研究必备
大数据·人工智能·笔记·能源·1024程序员节
Fab1an1 个月前
Busqueda——Hack The Box 靶机
linux·服务器·学习·1024程序员节