Redis 的 Lua 脚本可以极大提升操作的原子性和效率,特别适用于需要多个 Redis 命令组合执行的场景。以下是一些常见的使用场景,并结合代码进行详细说明。
1. 分布式锁
Redis 的 Lua 脚本常用于实现分布式锁,以确保多个客户端在并发访问时的互斥性。
示例:分布式锁的获取与释放
1-- 获取锁 2local lock_key = KEYS[1] 3local lock_value = ARGV[1] 4local ttl = tonumber(ARGV[2]) 5 6if redis.call("SETNX", lock_key, lock_value) == 1 then 7 redis.call("PEXPIRE", lock_key, ttl) 8 return 1 9else 10 return 0 11end 12
1redis-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 2
1-- 释放锁 2local lock_key = KEYS[1] 3local lock_value = ARGV[1] 4 5if redis.call("GET", lock_key) == lock_value then 6 redis.call("DEL", lock_key) 7 return 1 8else 9 return 0 10end 11
1redis-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
2. 计数器
实现自增、自减等计数器功能。
示例:原子性的自增操作
1local key = KEYS[1] 2local increment = tonumber(ARGV[1]) 3 4local current = redis.call("GET", key) 5if current == false then 6 current = 0 7else 8 current = tonumber(current) 9end 10 11local new_value = current + increment 12redis.call("SET", key, new_value) 13return new_value 14
1redis-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 2
3. 事务性操作
Lua 脚本可以确保多条命令的原子性,避免使用事务的复杂性。
示例:转账操作
1local from_account = KEYS[1] 2local to_account = KEYS[2] 3local amount = tonumber(ARGV[1]) 4 5local from_balance = tonumber(redis.call("GET", from_account)) 6local to_balance = tonumber(redis.call("GET", to_account)) 7 8if from_balance >= amount then 9 redis.call("DECRBY", from_account, amount) 10 redis.call("INCRBY", to_account, amount) 11 return 1 12else 13 return 0 14end 15
1redis-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 2
4. 排行榜
操作有序集合(sorted sets)实现排行榜功能。
示例:获取排行榜前 N 名
1local key = KEYS[1] 2local limit = tonumber(ARGV[1]) 3 4return redis.call("ZRANGE", key, 0, limit - 1, "WITHSCORES") 5
1redis-cli EVAL "local key = KEYS[1]; local limit = tonumber(ARGV[1]); return redis.call('ZRANGE', key, 0, limit - 1, 'WITHSCORES');" 1 leaderboard 10 2
5. 队列操作
通过列表(list)实现任务队列。
示例:推送和弹出任务
1-- 推送任务到队列 2local queue_key = KEYS[1] 3local task = ARGV[1] 4 5redis.call("RPUSH", queue_key, task) 6return redis.call("LLEN", queue_key) 7
1redis-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" 2
1-- 弹出任务 2local queue_key = KEYS[1] 3 4local task = redis.call("LPOP", queue_key) 5if not task then 6 return nil 7else 8 return task 9end 10
1redis-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 2
6. 限流器
实现简单的限流器,用于控制请求频率。
示例:限流脚本
1local key = KEYS[1] 2local limit = tonumber(ARGV[1]) 3local interval = tonumber(ARGV[2]) 4 5local current = tonumber(redis.call("GET", key) or "0") 6if current + 1 > limit then 7 return false 8else 9 redis.call("INCR", key) 10 if current == 0 then 11 redis.call("EXPIRE", key, interval) 12 end 13 return true 14end 15
1redis-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 2
总结
Redis 的 Lua 脚本强大且灵活,适用于多种场景。通过合理使用 Lua 脚本,可以确保操作的原子性、减少网络开销和提高系统性能。上述示例涵盖了常见的分布式锁、计数器、事务性操作、排行榜、队列操作和限流器等场景,为这些应用场景提供了高效、可靠的解决方案。
《Redis(64)Redis的Lua脚本有哪些常见场景?》 是转载文章,点击查看原文。