Redis Lua脚本执行原理和语法示例
Redis Lua脚本语法示例
文章目录
- Redis Lua脚本语法示例
- 0. 前言
- 参考资料
- 1. Redis 执行Lua脚本原理
- 1.1. 对Redis源码中嵌入Lua解释器的简要解析:
- 1.2. Redis Lua 脚本缓存机制
- 2. Redis Lua脚本示例
- 1.1. 场景示例
- 1. 请求限流
- 2. 原子性地从一个list移动元素到另一个list:
- 3. 原子性地更新hash值并返回旧值:
- 4. 如果键不存在,则设置键值:
- 5. 检查一个值是否在set中,并在不存在时添加:
- 6. 删除Sorted Set中的一些元素:
- 7. 原子性地为多个hash字段设置值:
- 8. 列出并删除所有具有特定前缀的键:
- 9. 在不超过最大数量的情况下,向list中添加元素:
- 10. 在Sorted Set中添加元素,但是元素的数量不能超过特定的数量,如果超过则删除分数最低的元素:
- 1.2. 常用示例
- 1. 批量设置多个键的值:
- 2. 使用Lua的math库函数进行数学计算:
- 3. 遍历集合的元素:
- 4. 使用Lua的string库函数进行字符串操作:
- 5. 获取有序集合中指定成员的排名:
- 6. 使用Lua的table库函数对Lua表进行操作:
- 7. 遍历有序集合的成员和分数(按分数递减排序):
- 8. 获取哈希表的字段数量:
- 9. 集合运算(求差集):
- 10. 使用Lua的os库函数进行操作系统相关操作:
- 11. 对Redis键进行模式匹配:
- 12. 获取有序集合指定范围内的成员和分数(按分数递减排序):
- 13. 设置哈希表中不存在的字段的值:
- 14. 获取有序集合指定范围内的成员和分数(按分数递减排序,并限制数量):
- 15. 使用Redis Lua脚本计算布隆过滤器的插入和查询操作:
- 16. 使用Redis Lua脚本实现简单的计数器:
- 17. 获取Redis服务器信息:
- 18. 对列表进行批量插入操作:
- 19. 使用Lua的coroutine库进行协程操作:
- 20. 执行Lua脚本时传递参数:
- 21. 使用Redis Lua脚本计算哈希表的字段数量:
- 22. 使用Lua的io库进行文件操作:
- 23. 使用Redis Lua脚本计算集合的并集的数量:
- 24. 使用Lua的debug库进行调试操作:
- 25. 使用Redis Lua脚本计算有序集合的成员总数:
- 26. 使用Lua的os库进行系统命令执行:
- 27. 在有序集合中插入成员的同时设置其分数:
- 28. 使用Lua的string库进行字符串分割操作:
- 29. 设置Redis键的过期时间(以毫秒为单位):
- 30. 使用Redis Lua脚本计算有序集合指定分数范围内的成员数量:
- 31. 使用Lua的bit库进行位操作:
- 32. 迭代哈希表的字段和值:
- 33. 获取有序集合指定范围内的成员(按分数递减排序,并限制数量):
- 34. 使用Lua的math库函数生成随机数:
- 35. 获取列表的长度:
- 36. 使用Lua的string库函数进行字符串查找操作:
- 37. 从有序集合中移除指定分数范围内的成员:
- 38. 使用Lua的table库函数进行表的深度复制:
- 39. 检查Redis键是否存在:
- 40. 使用Lua的os库函数进行时间戳转换:
- 41. 获取列表中指定范围内的元素:
- 42. 使用Lua的debug库函数获取当前函数信息:
- 43. 判断字符串是否为数字:
- 44. 获取有序集合指定成员的分数:
- 45. 使用Lua的string库函数进行字符串替换操作:
- 46. 遍历哈希表的字段:
- 47. 获取集合的基数(元素数量):
- 48. 使用Lua的io库进行文件写入操作:
- 49. 使用Redis Lua脚本计算有序集合指定分数范围内的成员(包括分数):
- 50. 获取哈希表的所有值:
- 51. 使用Lua的string库函数进行字符串大小写转换:
- 52. 获取有序集合指定范围内的成员(按分数递增排序):
- 53. 使用Lua的table库函数对Lua表进行遍历:
- 54. 移除列表中的元素:
- 55. 使用Lua的string库函数进行字符串连接操作:
- 56. 迭代有序集合的成员和分数(按分数递增排序):
- 57. 获取列表指定索引位置的元素:
- 58. 使用Lua的coroutine库进行协程操作:
- 59. 获取哈希表的所有字段和值:
- 60. 使用Lua的bit库进行位移操作:
- 61. 执行Redis事务操作:
- 62. 获取有序集合指定成员的排名(按分数递增排序):
- 63. 使用Lua的os库函数获取当前时间:
- 64. 使用Redis Lua脚本计算列表的所有元素之和:
- 65. 使用Lua的string库函数进行字符串截取操作:
- 66. 获取有序集合的指定排名范围内的成员(按分数递增排序):
- 67. 使用Lua的math库函数进行四舍五入操作:
- 68. 删除哈希表的字段:
- 69. 使用Lua的string库函数进行字符串比较操作:
- 70. 获取有序集合中指定成员的分数排名:
- 分布式锁
- 3. Redis从入门到精通系列文章
0. 前言
在学习本文之前,我是强烈建议大家了解一下我的其他两篇博客
- 《Redis 从入门到精通【进阶篇】一文学会Lua脚本》
- 《Redis 从入门到精通【进阶篇】之Lua脚本详解》
Redis通过嵌入Lua解释器,实现了对Lua脚本的执行。在执行过程中,Redis保证了脚本的原子性和阻塞性,同时通过脚本缓存和访问限制来提高性能和安全性。这使得Lua脚本成为在Redis中实现复杂逻辑的有效手段
-
嵌入式Lua解释器:Redis内部集成了Lua解释器,这使得Redis可以直接执行Lua脚本。Lua是一种轻量级的脚本语言,性能较高,且易于嵌入到其他程序中。通过嵌入Lua解释器,Redis可以实现更复杂的逻辑,同时保持高性能。
-
原子性:Redis执行Lua脚本时,会保证脚本的原子性。这意味着在执行脚本期间,Redis不会处理其他客户端的请求。这样可以确保脚本执行过程中的数据一致性,避免并发问题。
这个很关键,他保证了,我们执行命令的时候是原子执行,这个是实现分布式锁的前提。
-
阻塞性:由于Redis是单线程模型,执行Lua脚本时会阻塞其他客户端的请求。因此,为了保持Redis的高性能,需要确保Lua脚本的执行时间尽量短。如果脚本执行时间过长,可能会导致Redis性能下降。
-
脚本缓存:为了提高执行效率,Redis会缓存已执行过的Lua脚本。当客户端再次请求执行相同的脚本时,Redis可以直接从缓存中获取脚本,而无需重新加载和编译。这有助于减少脚本执行的开销。
-
限制访问:出于安全和性能的考虑,Redis对Lua脚本的访问权限进行了限制。在Lua脚本中,只能访问到传入的键和参数,不能访问Redis的全局状态。此外,脚本中不能执行一些可能导致阻塞或影响性能的命令,如
BLPOP
、SUBSCRIBE
等。
参考资料
- Redis官方文档:https://redis.io/
- Redis Lua脚本教程:https://redis.io/commands/eval
- 分布式锁的各种实现方式:https://www.cnblogs.com/linjiqin/p/8003838.html
- Redis分布式锁的正确实现方式(Redlock):http://redis.io/topics/distlock
- 分布式系统中的锁:https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
- 如何在Redis中实现分布式锁:https://www.cnblogs.com/liuyang0/p/6747257.html
- 使用Redis和Lua脚本实现分布式锁:https://segmentfault.com/a/1190000012919740
- 使用Redis实现分布式锁:https://www.cnblogs.com/0201zcr/p/5942748.html
1. Redis 执行Lua脚本原理
Redis 执行Lua脚本的核心源码位于src/scripting.c
地址:https://github.com/redis/redis/blob/6.0/src/scripting.c
Redis嵌入Lua解释器是通过将Lua源码与Redis源码结合,进行封装和适配实现的。Redis通过注册特殊的Lua命令,并调用Lua解释器的API函数,实现了Lua脚本在Redis中的执行和与Redis的交互。这样,用户可以在Redis中编写复杂的Lua脚本,利用Lua的强大功能进行数据处理和业务逻辑的实现。
1.1. 对Redis源码中嵌入Lua解释器的简要解析:
我们通过官网和源码浅析一下Redis可以执行Lua脚本的原理,其实和nginx 可以执行lua脚本的原理类似。
-
Lua源码和头文件:Redis使用的是Lua编程语言的官方实现,即LuaJIT或Lua。Redis的源代码中包含了Lua源码文件和相关的头文件,这些文件位于
src/scripting/
目录下。 -
Redis对Lua的封装:Redis通过封装Lua的API,提供了一套与Redis命令交互的接口。这些封装函数位于
src/scripting.c
文件中。
-
Redis命令的注册:Redis将Lua脚本作为一种特殊类型的命令进行处理。在
src/scripting.c
文件中,Redis通过redisCommandTable
数组注册了与Lua相关的命令,例如EVAL
、EVALSHA
等。这些命令与Lua脚本的执行和管理相关。 -
Redis命令的执行:当执行Lua脚本相关的命令时,Redis首先会解析命令参数,获取Lua脚本的内容和参数。然后,Redis将Lua脚本传递给Lua解释器进行解析和执行。
-
Lua解释器的初始化:在Redis的服务器初始化过程中,会调用
luaInit()
函数进行Lua解释器的初始化。该函数位于src/scripting.c
文件中。在初始化过程中,Redis会创建Lua解释器实例,并进行相关的设置和配置。 -
Lua脚本的执行:当执行Lua脚本相关的命令时,Redis会调用
evalGenericCommand()
函数来处理命令。该函数位于src/scripting.c
文件中。在该函数中,Redis会将Lua脚本和参数传递给Lua解释器,并调用Lua的API执行脚本。 -
Redis与Lua的交互:在Lua脚本执行期间,Redis与Lua之间可以进行数据的交互。Redis提供了一些API函数,例如
redis.call()
和redis.pcall()
,用于在Lua脚本中调用Redis命令。这些API函数允许Lua脚本直接访问Redis的键值存储和其他功能。 -
evalGenericCommand()
:执行Lua脚本相关的命令(如EVAL
和EVALSHA
)。该方法接收Lua脚本和参数,并将它们传递给Lua解释器进行执行。 -
luaCreateScriptingCommand()
:注册Lua脚本相关的命令。该方法通过调用Redis的命令注册函数,将Lua脚本命令添加到Redis的命令表中。 -
evalCommand()
:解析和执行EVAL
命令。该方法会解析命令参数,获取Lua脚本和参数,并将它们传递给evalGenericCommand()
方法进行执行。 -
loadCachedScript()
:加载缓存的Lua脚本。在执行EVALSHA
命令时,Redis会尝试从缓存中获取已加载的Lua脚本,以提高执行效率。
1.2. Redis Lua 脚本缓存机制
Redis的Lua脚本缓存机制主要包含以下步骤:
-
当一个Lua脚本被发送到Redis服务器并执行时,Redis不仅会执行这个脚本,同时它还会计算该脚本的SHA1哈希值,并将这个哈希值和对应的Lua脚本内容添加至缓存中。这个过程通常是在使用
EVAL
命令执行脚本时自动完成的。 -
当我们再次执行相同的Lua脚本时,可以使用
EVALSHA
命令,只需要发送之前计算出的SHA1哈希值,而无需再次发送整个脚本内容。 -
Redis会根据
EVALSHA
命令中的哈希值在缓存中搜索对应的Lua脚本,如果找到则直接执行,如果未找到则返回错误。 -
通过这种方式,我们可以避免重复发送大型的Lua脚本,从而减少网络传输的开销。同时,因为Redis直接执行缓存中的脚本,也无需再次解析脚本,从而提高了执行效率。
注意,虽然Redis的缓存可以提高Lua脚本的执行效率,但是它并不会缓存脚本的执行结果。这意味着,即使是相同的Lua脚本,每次执行时都会根据当前的数据重新计算结果。当前Redis并没有提供直接的方式来查看缓存的Lua脚本,也没有提供直接的方式来清除脚本缓存。当我们需要修改脚本时,只能重新计算修改后的脚本的哈希值,并使用新的哈希值来执行脚本。
2. Redis Lua脚本示例
Lua脚本是在Redis服务器上执行的脚本,它可以通过使用Redis提供的特定命令和库函数来与Redis进行交互。以下是一些常见的Redis Lua脚本示例:
1.1. 场景示例
1. 请求限流
使用Lua脚本完成原子递增并设置过期时间,用于API请求限流。
local current = tonumber(redis.call('get', KEYS[1]) or "0") -- 获取当前计数
local max_limit = tonumber(ARGV[1]) -- 最大计数限制
if current + 1 > max_limit then -- 如果超过最大限制则返回0return 0
elseredis.call('incrby', KEYS[1], ARGV[2]) -- 否则计数+1redis.call('expire', KEYS[1], ARGV[3]) -- 设置过期时间return current + 1
end
2. 原子性地从一个list移动元素到另一个list:
local element = redis.call('rpop', KEYS[1]) -- 从list1右侧pop出元素
if element thenredis.call('lpush', KEYS[2], element) -- 如果元素存在则push到list2
end
return element -- 返回被移动的元素
3. 原子性地更新hash值并返回旧值:
local old_val = redis.call('hget', KEYS[1], ARGV[1]) -- 获取旧值
redis.call('hset', KEYS[1], ARGV[1], ARGV[2]) -- 设置新值
return old_val -- 返回旧值
4. 如果键不存在,则设置键值:
local exists = redis.call('exists', KEYS[1]) -- 检查键是否存在
if exists == 0 thenredis.call('set', KEYS[1], ARGV[1]) -- 如果不存在则设置键值
end
return exists -- 返回键是否存在
5. 检查一个值是否在set中,并在不存在时添加:
local exists = redis.call('sismember', KEYS[1], ARGV[1]) -- 检查值是否在set中
if exists == 0 thenredis.call('sadd', KEYS[1], ARGV[1]) -- 如果不存在则添加
end
return exists -- 返回值是否在set中
6. 删除Sorted Set中的一些元素:
local count = 0
for i, member in ipairs(ARGV) docount = count + redis.call('zrem', KEYS[1], member) -- 删除Sorted Set中的元素
end
return count -- 返回被删除元素的数量
7. 原子性地为多个hash字段设置值:
for i = 1, #ARGV, 2 doredis.call('hset', KEYS[1], ARGV[i], ARGV[i + 1]) -- 设置多个hash字段的值
end
return true
8. 列出并删除所有具有特定前缀的键:
local keys = redis.call('keys', ARGV[1]) -- 列出所有具有特定前缀的键
for i, key in ipairs(keys) doredis.call('del', key) -- 删除这些键
end
return keys -- 返回被删除的键
9. 在不超过最大数量的情况下,向list中添加元素:
local size = redis.call('llen', KEYS[1]) -- 获取list的长度
if size < tonumber(ARGV[2]) thenredis.call('rpush', KEYS[1], ARGV[1]) -- 如果未超过最大数量则添加元素
end
return size -- 返回list的长度
10. 在Sorted Set中添加元素,但是元素的数量不能超过特定的数量,如果超过则删除分数最低的元素:
redis.call('zadd', KEYS[1], ARGV[2], ARGV[1]) -- 在Sorted Set中添加元素
if redis.call('zcard', KEYS[1]) > tonumber(ARGV[3]) then -- 如果元素的数量超过最大数量return redis.call('zremrangebyrank', KEYS[1], 0, 0) -- 则删除分数最低的元素
end
return true
1.2. 常用示例
1. 批量设置多个键的值:
local keysValues = {'key1', 'value1', 'key2', 'value2', 'key3', 'value3'}
redis.call('MSET', unpack(keysValues))
2. 使用Lua的math库函数进行数学计算:
local result = math.sqrt(16)
3. 遍历集合的元素:
local members = redis.call('SMEMBERS', 'set')
for i, member in ipairs(members) do-- 处理元素
end
4. 使用Lua的string库函数进行字符串操作:
local substring = string.sub('hello world', 1, 5)
5. 获取有序集合中指定成员的排名:
local rank = redis.call('ZRANK', 'zset', 'member')
6. 使用Lua的table库函数对Lua表进行操作:
local myTable = {key1 = 'value1', key2 = 'value2', key3 = 'value3'}
table.insert(myTable, 'value4')
7. 遍历有序集合的成员和分数(按分数递减排序):
local members = redis.call('ZREVRANGE', 'zset', 0, -1, 'WITHSCORES')
for i = 1, #members, 2 dolocal member = members[i]local score = members[i + 1]-- 处理成员和分数
end
8. 获取哈希表的字段数量:
local count = redis.call('HLEN', 'hash')
9. 集合运算(求差集):
local difference = redis.call('SDIFF', 'set1', 'set2')
10. 使用Lua的os库函数进行操作系统相关操作:
local currentTime = os.date('%Y-%m-%d %H:%M:%S')
11. 对Redis键进行模式匹配:
local keys = redis.call('KEYS', 'pattern*')
for i, key in ipairs(keys) do-- 处理匹配到的键
end
12. 获取有序集合指定范围内的成员和分数(按分数递减排序):
local members = redis.call('ZREVRANGEBYSCORE', 'zset', maxScore, minScore, 'WITHSCORES')
13. 设置哈希表中不存在的字段的值:
redis.call('HSETNX', 'hash', 'field', 'value')
14. 获取有序集合指定范围内的成员和分数(按分数递减排序,并限制数量):
local members = redis.call('ZREVRANGE', 'zset', 0, 10, 'WITHSCORES')
15. 使用Redis Lua脚本计算布隆过滤器的插入和查询操作:
redis.call('EVAL', 'local bf = redis.call("BFINSERT", "filter", "item"); local result = redis.call("BFCHECK", "filter", "item"); return result;', 0)
16. 使用Redis Lua脚本实现简单的计数器:
local count = redis.call('INCR', 'counter')
17. 获取Redis服务器信息:
local info = redis.call('INFO')
18. 对列表进行批量插入操作:
local values = {'value1', 'value2', 'value3'}
redis.call('RPUSH', 'list', unpack(values))
19. 使用Lua的coroutine库进行协程操作:
local co = coroutine.create(function()-- 执行协程操作
end)
coroutine.resume(co)
20. 执行Lua脚本时传递参数:
local key = KEYS[1]
local value = ARGV[1]
redis.call('SET', key, value)
21. 使用Redis Lua脚本计算哈希表的字段数量:
local fieldsCount = 0
local fields = redis.call('HGETALL', 'hash')
for i = 1, #fields, 2 dofieldsCount = fieldsCount + 1
end
return fieldsCount
22. 使用Lua的io库进行文件操作:
local file = io.open('/path/to/file', 'r')
local content = file:read('*a')
file:close()
23. 使用Redis Lua脚本计算集合的并集的数量:
local union = redis.call('SUNION', 'set1', 'set2')
return #union
24. 使用Lua的debug库进行调试操作:
local info = debug.getinfo(2)
25. 使用Redis Lua脚本计算有序集合的成员总数:
local count = redis.call('ZCARD', 'zset')
26. 使用Lua的os库进行系统命令执行:
local result = os.execute('command')
27. 在有序集合中插入成员的同时设置其分数:
redis.call('ZADD', 'zset', score, 'member')
28. 使用Lua的string库进行字符串分割操作:
local str = 'hello world'
local parts = {}
for part in string.gmatch(str, '%S+') dotable.insert(parts, part)
end
29. 设置Redis键的过期时间(以毫秒为单位):
redis.call('PEXPIRE', 'key', 1000)
30. 使用Redis Lua脚本计算有序集合指定分数范围内的成员数量:
local count = redis.call('ZCOUNT', 'zset', minScore, maxScore)
31. 使用Lua的bit库进行位操作:
local result = bit.band(7, 3)
32. 迭代哈希表的字段和值:
local fieldsValues = redis.call('HGETALL', 'hash')
for i = 1, #fieldsValues, 2 dolocal field = fieldsValues[i]local value = fieldsValues[i + 1]-- 处理字段和值
end
33. 获取有序集合指定范围内的成员(按分数递减排序,并限制数量):
local members = redis.call('ZREVRANGE', 'zset', 0, 10)
34. 使用Lua的math库函数生成随机数:
local random = math.random(1, 100)
35. 获取列表的长度:
local length = redis.call('LLEN', 'list')
36. 使用Lua的string库函数进行字符串查找操作:
local index = string.find('hello world', 'world')
37. 从有序集合中移除指定分数范围内的成员:
redis.call('ZREMRANGEBYSCORE', 'zset', minScore, maxScore)
38. 使用Lua的table库函数进行表的深度复制:
local tableCopy = table.deepcopy(originalTable)
39. 检查Redis键是否存在:
local exists = redis.call('EXISTS', 'key')
40. 使用Lua的os库函数进行时间戳转换:
local timestamp = os.time()
local date = os.date('%Y-%m-%d %H:%M:%S', timestamp)
41. 获取列表中指定范围内的元素:
local elements = redis.call('LRANGE', 'list', start, stop)
42. 使用Lua的debug库函数获取当前函数信息:
local info = debug.getinfo(1, 'n')
43. 判断字符串是否为数字:
local isNumber = tonumber('123')
44. 获取有序集合指定成员的分数:
local score = redis.call('ZSCORE', 'zset', 'member')
45. 使用Lua的string库函数进行字符串替换操作:
local replacedString = string.gsub('hello world', 'world', 'redis')
46. 遍历哈希表的字段:
local fields = redis.call('HKEYS', 'hash')
for i, field in ipairs(fields) do-- 处理字段
end
47. 获取集合的基数(元素数量):
local cardinality = redis.call('SCARD', 'set')
48. 使用Lua的io库进行文件写入操作:
local file = io.open('/path/to/file', 'w')
file:write('content')
file:close()
49. 使用Redis Lua脚本计算有序集合指定分数范围内的成员(包括分数):
local members = redis.call('ZRANGEBYSCORE', 'zset', minScore, maxScore, 'WITHSCORES')
50. 获取哈希表的所有值:
local values = redis.call('HVALS', 'hash')
51. 使用Lua的string库函数进行字符串大小写转换:
local lowercase = string.lower('HELLO')
local uppercase = string.upper('world')
52. 获取有序集合指定范围内的成员(按分数递增排序):
local members = redis.call('ZRANGE', 'zset', minScore, maxScore)
53. 使用Lua的table库函数对Lua表进行遍历:
local myTable = {key1 = 'value1', key2 = 'value2', key3 = 'value3'}
for key, value in pairs(myTable) do-- 处理键和值
end
54. 移除列表中的元素:
redis.call('LREM', 'list', count, 'element')
55. 使用Lua的string库函数进行字符串连接操作:
local concatenatedString = string.concat('hello', 'world')
56. 迭代有序集合的成员和分数(按分数递增排序):
local members = redis.call('ZRANGE', 'zset', 0, -1, 'WITHSCORES')
for i = 1, #members, 2 dolocal member = members[i]local score = members[i + 1]-- 处理成员和分数
end
57. 获取列表指定索引位置的元素:
local element = redis.call('LINDEX', 'list', index)
58. 使用Lua的coroutine库进行协程操作:
local co = coroutine.create(function()-- 执行协程操作
end)
coroutine.resume(co)
59. 获取哈希表的所有字段和值:
local fieldsValues = redis.call('HGETALL', 'hash')
60. 使用Lua的bit库进行位移操作:
local result = bit.lshift(7, 2)
61. 执行Redis事务操作:
redis.call('MULTI')
redis.call('SET', 'key1', 'value1')
redis.call('SET', 'key2', 'value2')
redis.call('EXEC')
62. 获取有序集合指定成员的排名(按分数递增排序):
local rank = redis.call('ZRANK', 'zset', 'member')
63. 使用Lua的os库函数获取当前时间:
local currentTime = os.time()
64. 使用Redis Lua脚本计算列表的所有元素之和:
local sum = 0
local elements = redis.call('LRANGE', 'list', 0, -1)
for i, element in ipairs(elements) dosum = sum + tonumber(element)
end
return sum
65. 使用Lua的string库函数进行字符串截取操作:
local substring = string.sub('hello world', 7)
66. 获取有序集合的指定排名范围内的成员(按分数递增排序):
local members = redis.call('ZRANGEBYRANK', 'zset', startRank, endRank)
67. 使用Lua的math库函数进行四舍五入操作:
local roundedNumber = math.round(3.7)
68. 删除哈希表的字段:
redis.call('HDEL', 'hash', 'field')
69. 使用Lua的string库函数进行字符串比较操作:
local result = string.compare('hello', 'world')
70. 获取有序集合中指定成员的分数排名:
local rank = redis.call('ZREVRANK', 'zset', 'member')
分布式锁
不同的语言和类库已经基于Redis实现了分布式锁,大家可以用作参考。
Redlock-rb(Ruby实现)。还有一个Redlock-rb的分支,增加了一个gem以便于分发。
Redlock-py(Python实现)。
Pottery(Python实现)。
Aioredlock(Asyncio Python实现)。
Redlock-php(PHP实现)。
PHPRedisMutex(进一步的PHP实现)。
cheprasov/php-redis-lock(PHP锁库)。
rtckit/react-redlock(异步PHP实现)。
Redsync(Go实现)。
Redisson(Java实现)。
Redis::DistLock(Perl实现)。
Redlock-cpp(C++实现)。
Redis-plus-plus(C++实现)。
Redlock-cs(C#/.NET实现)。
RedLock.net(C#/.NET实现)。包括异步和锁扩展支持。
ScarletLock(C# .NET实现,具有可配置的数据存储)。
Redlock4Net(C# .NET实现)。
node-redlock(NodeJS实现)。包括对锁扩展的支持。
Deno DLM(Deno实现)
Rslock(Rust实现)。包括异步和锁扩展支持。
3. Redis从入门到精通系列文章
- 《Redis 从入门到精通【进阶篇】之Lua脚本详解》
- 《Redis 从入门到精通【实践篇】SpringBoot Redis 配置多数据源》
- 《Redis 从入门到精通【进阶篇】三分钟了解Redis地理位置数据结构GeoHash》
- 《Redis 从入门到精通【进阶篇】一文学会Lua脚本》
- 《Redis使用Lua脚本和Redisson来保证库存扣减中的原子性和一致性》
- 《SpringBoot Redis 使用Lettuce和Jedis配置哨兵模式》
- 《Redis【应用篇】之RedisTemplate基本操作》
- 《Redis 从入门到精通【实践篇】之SpringBoot配置Redis多数据源》
- 《Redis 从入门到精通【进阶篇】之三分钟了解Redis HyperLogLog 数据结构》
- 《Redis 从入门到精通【进阶篇】之三分钟了解Redis地理位置数据结构GeoHash》
- 《Redis 从入门到精通【进阶篇】之高可用哨兵机制(Redis Sentinel)详解》
- 《Redis 从入门到精通【进阶篇】之redis主从复制详解》
- 《Redis 从入门到精通【进阶篇】之Redis事务详解》
- 《Redis从入门到精通【进阶篇】之对象机制详解》
- 《Redis从入门到精通【进阶篇】之消息传递发布订阅模式详解》
- 《Redis从入门到精通【进阶篇】之持久化 AOF详解》
- 《Redis从入门到精通【进阶篇】之持久化RDB详解》
- 《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》
- 《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
- 《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
- 《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
- 《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
大家好,我是冰点,今天的Redis Lua脚本执行原理和语法示例,全部内容就是这些。如果你有疑问或见解可以在评论区留言。
相关文章:
Redis Lua脚本执行原理和语法示例
Redis Lua脚本语法示例 文章目录 Redis Lua脚本语法示例0. 前言参考资料 1. Redis 执行Lua脚本原理1.1. 对Redis源码中嵌入Lua解释器的简要解析:1.2. Redis Lua 脚本缓存机制 2. Redis Lua脚本示例1.1. 场景示例1. 请求限流2. 原子性地从一个list移动元素到另一个li…...
百望云华为云共建零售数字化新生态 聚焦数智新消费升级
零售业是一个充满活力和创新的行业,但也是当前面临很大新挑战和新机遇的行业。数智新消费时代,数字化转型已经成为零售企业必须面对的重要课题。 8 月 20 日-21日,以“云上创新 韧性增长”为主题的华为云数智新消费创新峰会2023在成都隆重召…...
JMETER基本原理
Jmeter基本原理是建立一个线程池,多线程运行取样器产生大量负载,在运行过程中通过断言来验证结果的正确性,可以通过监听来记录测试结果; JMETER是运行在JVM虚拟机上的,每个进程的开销比loadrunner的进程开销大&#x…...
elementUI自定义上传文件 前端后端超详细过程
下面是使用Element UI自定义上传文件的前后端详细过程: 前端过程: 引入Element UI组件库:在前端项目中引入Element UI库,可以通过CDN引入或者通过npm安装并导入。 创建上传组件:在前端代码中创建一个上传组件&#x…...
快速排序笔记
一、quick_sort方法中如果 il,jr 会死循环的分析 1、示例代码 void quick_sort(int a[],int l,int r){if(l>r) return;int il,jr; //此处设置会导致死循环int x num[(lr)>>1];while(i<j){while(a[i] <x); //死循环的地方while(a[--j] >x);if(i<j) swap(a…...
JAVA:(JSON反序列化Long变成了Integer)java.lang.Integer cannot be cast to java.lang.Long
困扰了好几个小时。。。 场景:mybatisplus从数据库取数据,只是用了最基础的 LambdaQueryWrapper 来查询,实体类如下。 TableField(typeHandler JacksonTypeHandler.class) private Set<Long> ids; 得到的Set数据却是Set<Integer…...
ui设计师简历自我评价(合集)
UI设计最新面试题及答案 1、说说你是怎么理解UI的? UI是最直观的把产品展示展现在用户面前的东西,是一个产品的脸面。人开始往往是先会先喜欢上美好的事物后,在去深究内在的东西的。 那么也就意味着一个产品的UI首先要做的好看,无论风格是…...
Nginx 反向代理
一. Nginx 反向代理 1.1 反向代理介绍 在计算机网络中,反向代理一般指代理服务器,其首先代替内网的服务器接收客户端请求 并从一个或多个服务器检索资源,然后将这些资源返回给客户端。在客户端看来,这些资 源就好像来自代理服务…...
[论文阅读笔记25]A Comprehensive Survey on Graph Neural Networks
这是一篇GNN的综述, 发表于2021年的TNNLS. 这篇博客旨在对GNN的基本概念做一些记录. 论文地址: 论文 1. 引言, 背景与定义 对于图像数据来说, CNN具有平移不变性和局部连接性, 因此可以在欧氏空间上良好地学习. 然而, 对于具有图结构的数据(例如社交网络 化学分子等)就需要用…...
iview时间控件 动态不可选日期 可选择24小时范围内 时间往后退24小时
演示 html 设定 起始时间 触发on-change 方法结束时间 options 动态设置不可选择的日期。 <!-- 起始时间 --> <FormItem :label"$t(startTime)" prop"startTime"><DatePickertransfertype"datetime":placeholder"$t(pleas…...
Rest学习环境搭建:服务消费者
建一个子模块 导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…...
JVM内存模型介绍
内存模型 内存模型如下图所示 堆 堆是Java虚拟机所管理的内存最大一块。堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例。所有的对象实例都在这里分配内存 Java堆是垃圾收集器管理的主要区域。从内存回收的角度来看&am…...
2000-2021年地级市产业升级、产业结构高级化面板数据
2000-2021年地级市产业升级、产业结构高级化面板数据 1、时间:2000-2021年 2、范围:地级市 3、指标:年份、地区、行政区划代码、地区、所属省份、地区生产总值、第一产业增加值、第二产业增加值、第三产业增加值、第一产业占GDP比重、第二…...
Java实现密码加密实现步骤【bcrypt算法】
一、SpringBoot和SSM框架均可实现密码加密的方法 在Spring Boot和SSM中实现密码加密可以使用bcrypt算法。bcrypt是一种密码哈希函数,通过将密码与随机生成的盐值进行混合,然后再进行多次迭代的计算,最终生成一个安全的哈希密码。 下面是使用…...
商城-学习整理-集群-K8S(二十三)
目录 一、k8s 集群部署1、k8s 快速入门1)、简介2)、架构1、整体主从方式2、Master 节点架构3、Node 节点架构 3)、概念4)、快速体验1、安装 minikube2、体验 nginx 部署升级 5)、流程叙述 2、k8s 集群安装1、kubeadm2、…...
MATLAB算法实战应用案例精讲-【深度学习】强化学习
目录 基础知识点 马尔科夫决策过程 策略梯度定理 蒙特卡洛策略梯度定理 REINFORCE 算法...
时间和日期--Python
1. 时间:time模块 总结:2. datetime模块 相比与time模块,datetime模块的接口更直观、更容易调用 2.1 datetime模块定义的类 (1)datetime.date:表示日期的类。常用的属性有:year、month、day; ÿ…...
【Git】学习总结
【Git】学习总结 【一】安装【二】Git克隆项目代码【1】idea下载git项目【2】创建新的分支【3】新建的分支推送到远程【4】合并最新代码到主分支【5】切换分支 【三】提交本地项目到远程🚀1. 配置 Git🚀2. 创建项目远程仓库🚀3. 初始化本地仓…...
手写Spring源码——实现一个简单的spring framework
这篇文章主要带大家实现一个简单的Spring框架,包含单例、多例bean的获取,依赖注入、懒加载等功能。文章内容会持续更新,感兴趣的小伙伴可以持续关注一下。 目录 一、创建Java项目 二、开始实现Spring 1、创建BeanFactory接口 2、创建Appl…...
银河麒麟服务器、centos7服务器一键卸载mysql脚本
脚本 # 查看mysql相关的rpm包写到rmsql.sh文件中 rpm -aq | grep -i mysql >rmsql.sh # 修改文件为卸载mysql的脚本文件 sed -i -e s/^/yum remove -y / rmsql.sh # 修改文本权限 chmod 777 rmsql.sh # 全盘查找mysql相关文件,写到my.sh脚本中 find / -name mysq…...
【随笔】- 程序员的40岁后健身计划
【随笔】- 40岁后程序员的健身计划 文章目录 【随笔】- 40岁后程序员的健身计划一、树立健身信心,制订坚持计划二、挑选让你舒适的方式三、调整速度,以间歇式训练为主四、刚开始锻炼,别求太快五、增加力量、柔韧性和平衡练习六、运动多样化七…...
后端项目开发:集成Druid数据源
Druid作为连接池中间件可以监控数据库访问性能,对数据库密码加密,查看SQL执行日志,扩展JDBC。 添加依赖 <!-- druid --> <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter&…...
深度学习11:Transformer
目录 什么是 Transformer? Encoder Decoder Attention Self-Attention Context-Attention 什么是 Transformer(微软研究院笨笨) RNN和Transformer区别 Universal Transformer和Transformer 区别 什么是 Transformer? …...
免费开源跨平台视频下载器 支持数百站点视频和音频下载-ytDownloader
ytDownloader: ytDownloader是一款免费开源跨平台视频下载器,帮助用户从数百个网站下载不同格式的视频和提取音频,使用简单,复制视频链接粘贴即可下载,支持4K画质视频下载,支持Linux、Windows 和 macOS平台…...
R包开发1:RStudio 与 GitHub建立连接
目录 1.安装Git 2-配置Git(只需配置一次) 3-用SSH连接GitHub(只需配置一次) 4-创建Github远程仓库 5-克隆仓库到本地 目标:创建的R包,包含Git版本控制,并且能在远程Github仓库同步,相当于发布在Github。…...
红蓝攻防:浅谈削弱WindowsDefender的各种方式
前言 随着数字技术的日益进步,我们的生活、工作和娱乐越来越依赖于计算机和网络系统。然而,与此同时,恶意软件也日趋猖獗,寻求窃取信息、破坏系统或仅仅为了展现其能力。微软Windows,作为世界上最流行的操作系统&…...
什么是响应式设计(Responsive Design)?如何实现一个响应式网页?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 响应式设计(Responsive Design)⭐ 如何实现一个响应式网页?1. 弹性网格布局2. 媒体查询3. 弹性图像和媒体4. 流式布局5. 优化导航6. 测试和调整7. 图片优化8. 字体优化9. 渐进增强10. 面向移动优先11. …...
QT之应用程序执行脚本
简介 ● Qt中的类QProcess支持在程序中另外开辟线程 ● 其中start方法支持以字符串为参数执行命令 以Linux平台为例: 方式一(后台执行) /// /// \brief MainWindow::cmdLine run a linux command with string format in the bash /// \pa…...
学习文档链接
SpringBoot Activiti 完美结合,快速实现工作流(最详细版) - 知乎 (zhihu.com) easypoi: POI 工具类,Excel的快速导入导出,Excel模板导出,Word模板导出,可以仅仅5行代码就可以完成Excel的导入导出,修改导出格式简单粗暴,快速有效,easypoi值得…...
【Java 高阶】一文精通 Spring MVC - 转换器(五)
👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主 ⛪️ 个人社区&#x…...
nginx 做udp网站/上海网站搜索引擎优化
官方给出的智能合约示例是一个投票程序,候选人candidate的数据类型是Bytes32。利用java SDK调用合约的 voteForCandidate(bytes32 candidate) 接口,发现一个问题: 我输入的参数“simmel”是string类型,而SDK中不提供将string类型…...
做网站包括图片设计吗/设计网站
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。 WaitForSingleObject 函数DWORD WaitForSingleObject( HANDLE hObject, DWORD dwMilliseconds ); 第一个参数hObject标识一个能够支持被通知/未通知的内核对象(前面列出的…...
建设学院网站的通知/竞价托管就选微竞价
http://www.bianceng.cn/webkf/aspx/201102/24785_2.htm转载于:https://www.cnblogs.com/shenzhenjia/archive/2011/07/21/2113323.html...
景安一个空间怎么做多个网站/百度收录链接
spring mvc在普通类中获取HttpServletRequest对象需要做2个步骤: 1、在web.xml文件中加如下配置 <listener> <listener-class>org.springframework.web.context.request.RequestContextListener </listener-class> </listener> 在RequestCo…...
凡科互动平台/开封网站快速排名优化
ASP.NET Core 是一个由微软创建的,用于构建 web 应用、API、微服务 的 web 框架。 通过本文的学习就能快速的入门ASP.NET Core,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 本来这篇只是想简单介…...
彩票自己开盘做网站/谷歌关键词挖掘工具
通过MYSQL查询语句动态的显示图表一、在官网上下载对应的组件,四者均可,并倒入到项目的JS包下二、写MYSQL语句并查询的数量num和名称nameSELECT s.peopleNums,r.name from statistics as s,readrooms as r where s.ReadRoomID r.ID GROUP BY s.ReadRoom…...