redis 的 lua 脚本可以极大提升操作的原子性和效率,特别适用于需要多个 redis 命令组合执行的场景。以下是一些常见的使用场景,并结合代码进行详细说明。
1. 分布式锁
redis 的 lua 脚本常用于实现分布式锁,以确保多个客户端在并发访问时的互斥性。
示例:分布式锁的获取与释放
-- 获取锁 local lock_key = keys[1] local lock_value = argv[1] local ttl = tonumber(argv[2]) if redis.call("setnx", lock_key, lock_value) == 1 then redis.call("pexpire", lock_key, ttl) return 1 else return 0 end
redis-cli eval "local lock_key = keys[1]; local lock_value = argv[1]; local ttl = tonumber(argv[2]); if redis.call('setnx', lock_key, lock_value) == 1 then redis.call('pexpire', lock_key, ttl); return 1; else return 0; end" 1 mylock lock_value 30000
-- 释放锁 local lock_key = keys[1] local lock_value = argv[1] if redis.call("get", lock_key) == lock_value then redis.call("del", lock_key) return 1 else return 0 end
redis-cli eval "local lock_key = keys[1]; local lock_value = argv[1]; if redis.call('get', lock_key) == lock_value then redis.call('del', lock_key); return 1; else return 0; end" 1 mylock lock_value
2. 计数器
实现自增、自减等计数器功能。
示例:原子性的自增操作
local key = keys[1] local increment = tonumber(argv[1]) local current = redis.call("get", key) if current == false then current = 0 else current = tonumber(current) end local new_value = current + increment redis.call("set", key, new_value) return new_value
redis-cli eval "local key = keys[1]; local increment = tonumber(argv[1]); local current = redis.call('get', key); if current == false then current = 0; else current = tonumber(current); end; local new_value = current + increment; redis.call('set', key, new_value); return new_value;" 1 mycounter 1
3. 事务性操作
lua 脚本可以确保多条命令的原子性,避免使用事务的复杂性。
示例:转账操作
local from_account = keys[1] local to_account = keys[2] local amount = tonumber(argv[1]) local from_balance = tonumber(redis.call("get", from_account)) local to_balance = tonumber(redis.call("get", to_account)) if from_balance >= amount then redis.call("decrby", from_account, amount) redis.call("incrby", to_account, amount) return 1 else return 0 end
redis-cli eval "local from_account = keys[1]; local to_account = keys[2]; local amount = tonumber(argv[1]); local from_balance = tonumber(redis.call('get', from_account)); local to_balance = tonumber(redis.call('get', to_account)); if from_balance >= amount then redis.call('decrby', from_account, amount); redis.call('incrby', to_account, amount); return 1; else return 0; end" 2 account1 account2 100
4. 排行榜
操作有序集合(sorted sets)实现排行榜功能。
示例:获取排行榜前 n 名
local key = keys[1] local limit = tonumber(argv[1]) return redis.call("zrange", key, 0, limit - 1, "withscores")
redis-cli eval "local key = keys[1]; local limit = tonumber(argv[1]); return redis.call('zrange', key, 0, limit - 1, 'withscores');" 1 leaderboard 10
5. 队列操作
通过列表(list)实现任务队列。
示例:推送和弹出任务
-- 推送任务到队列 local queue_key = keys[1] local task = argv[1] redis.call("rpush", queue_key, task) return redis.call("llen", queue_key)
redis-cli eval "local queue_key = keys[1]; local task = argv[1]; redis.call('rpush', queue_key, task); return redis.call('llen', queue_key);" 1 task_queue "task1"
-- 弹出任务 local queue_key = keys[1] local task = redis.call("lpop", queue_key) if not task then return nil else return task end
redis-cli eval "local queue_key = keys[1]; local task = redis.call('lpop', queue_key); if not task then return nil; else return task; end" 1 task_queue
6. 限流器
实现简单的限流器,用于控制请求频率。
示例:限流脚本
local key = keys[1] local limit = tonumber(argv[1]) local interval = tonumber(argv[2]) local current = tonumber(redis.call("get", key) or "0") if current + 1 > limit then return false else redis.call("incr", key) if current == 0 then redis.call("expire", key, interval) end return true end
redis-cli eval "local key = keys[1]; local limit = tonumber(argv[1]); local interval = tonumber(argv[2]); local current = tonumber(redis.call('get', key) or '0'); if current + 1 > limit then return false; else redis.call('incr', key); if current == 0 then redis.call('expire', key, interval); end; return true; end" 1 rate_limit_key 10 60
总结
redis 的 lua 脚本强大且灵活,适用于多种场景。通过合理使用 lua 脚本,可以确保操作的原子性、减少网络开销和提高系统性能。上述示例涵盖了常见的分布式锁、计数器、事务性操作、排行榜、队列操作和限流器等场景,为这些应用场景提供了高效、可靠的解决方案。
到此这篇关于redis中lua脚本的常见场景的文章就介绍到这了,更多相关redis lua脚本常见场景内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论