博客参考:Redis 从入门到精通【进阶篇】之Lua脚本详解
重点:
redis对lua脚本语言有很好的支持,对于开发者,如果要处理的数据涉及到只是简单的计算逻辑,就不必将redis中的数据拿到应用程序中执行了,直接写一段lua脚本程序就可以**在redis服务端完成**逻辑处理。
127.0.0.1:6379> eval "if redis.call('exists', KEYS[1]) > 0 then return redis.call('get', KEYS[1]); else return ''; end;" 1 lua_key
"lua_val"
优点
原子性操作:Lua脚本在Redis中的执行是原子性的,能够保证多个命令的原子性执行,避免并发带来的问题。
减少网络开销:通过将多个命令封装在一个Lua脚本中执行,可以减少网络开销。
复杂计算逻辑:Lua脚本可以编写计算逻辑,减轻Redis负载。
原子性操作:通过使用Lua脚本,可以实现事务处理、乐观锁、排他锁等原子性操作。
(补充知识: 乐观锁 CAS ABA 版本号机制)
分布式锁:使用Lua脚本可实现分布式锁,防止多个客户端同时访问共享资源。
分为加载脚本、编译脚本和执行脚本三个阶段。
Redis脚本缓存的目的是为了提高脚本的执行效率,避免每次执行脚本都需要重新加载和编译。
实现方式是将脚本的SHA1散列值和脚本内容一起保存在Redis服务器的脚本缓存中。
在使用脚本时,可以通过脚本的SHA1散列值来引用脚本,而不需要每次都传输脚本内容。
Lua脚本是基于Lua语言的一种脚本语言,具有自己的语法规则。
常用的Lua语法元素包括变量、表达式、控制结构、函数等。
脚本编译的原理是将Lua脚本解析为一种中间表示形式(可执行的字节码)。
Redis Lua脚本具有原子性特点,即脚本中的所有操作要么全部执行成功,要么全部不执行。
(补充知识:reids的事务本来是不具备全部成功或者全部失败的)
Redis在执行脚本时会将脚本作为一个整体进行执行,不会被其他操作中断。
在Lua脚本中,可以使用Redis事务的命令(如MULTI、EXEC、WATCH等)来实现
(补充知识: WATCH key 可以监听一个键 如果exec前这个键变了 那么exec事务会被取消)
使用Lua脚本实现排他锁的案例:
-- 加锁脚本
local key = KEYS[1]
local value = ARGV[1]
local ttl = tonumber(ARGV[2])
local lock = redis.call('set', key, value, 'NX', 'PX', ttl)
if lock then
return true
else
return false
end
(补充知识: redis实例是分布式的,真要保证加锁成功,要集群一半以上都设置了才算,呼应之前博客写的red lock)
利用Lua脚本处理复杂数据结构的示例:
-- 计算列表中所有元素的总和
local key = KEYS[1]
local sum = 0
local values = redis.call('lrange', key, 0, -1)
for i, value in ipairs(values) do
sum = sum + tonumber(value)
end
return sum
Lua脚本可以在Redis中实现批量操作,例如批量插入、批量删除等,案例:
-- 批量删除指定前缀的键
local prefix = ARGV[1]
local keys = redis.call('keys', prefix .. '*')
for i, key in ipairs(keys) do
redis.call('del', key)
end
return #keys
Redis Lua脚本的执行机制是什么?
在执行Lua脚本时,会将脚本发送到服务器端进行编译和执行。
如果脚本已经被编译过,Redis会使用脚本的SHA1散列值来执行,减少网络传输。
脚本可以访问Redis的数据结构和命令,并且可以通过redis.call和redis.pcall函数调用Redis命令。
Redis Lua脚本的错误处理如何?
当Lua脚本执行出错时,Redis会返回一个错误信息。可以通过检查返回值来判断脚本是否执行成功。
可以使用pcall函数来调用Redis命令,并通过判断返回值来处理错误情况。