Redis(64)Redis的Lua脚本有哪些常见场景?

Redis 的 Lua 脚本可以极大提升操作的原子性和效率,特别适用于需要多个 Redis 命令组合执行的场景。以下是一些常见的使用场景,并结合代码进行详细说明。

1. 分布式锁

Redis 的 Lua 脚本常用于实现分布式锁,以确保多个客户端在并发访问时的互斥性。

示例:分布式锁的获取与释放

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
sh 复制代码
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
lua 复制代码
-- 释放锁
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
sh 复制代码
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. 计数器

实现自增、自减等计数器功能。

示例:原子性的自增操作

lua 复制代码
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
sh 复制代码
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 脚本可以确保多条命令的原子性,避免使用事务的复杂性。

示例:转账操作

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
sh 复制代码
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 名

lua 复制代码
local key = KEYS[1]
local limit = tonumber(ARGV[1])

return redis.call("ZRANGE", key, 0, limit - 1, "WITHSCORES")
sh 复制代码
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)实现任务队列。

示例:推送和弹出任务

lua 复制代码
-- 推送任务到队列
local queue_key = KEYS[1]
local task = ARGV[1]

redis.call("RPUSH", queue_key, task)
return redis.call("LLEN", queue_key)
sh 复制代码
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"
lua 复制代码
-- 弹出任务
local queue_key = KEYS[1]

local task = redis.call("LPOP", queue_key)
if not task then
    return nil
else
    return task
end
sh 复制代码
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. 限流器

实现简单的限流器,用于控制请求频率。

示例:限流脚本

lua 复制代码
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
sh 复制代码
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 脚本,可以确保操作的原子性、减少网络开销和提高系统性能。上述示例涵盖了常见的分布式锁、计数器、事务性操作、排行榜、队列操作和限流器等场景,为这些应用场景提供了高效、可靠的解决方案。

相关推荐
小翰子_10 分钟前
Spring Boot整合Sharding-JDBC实现日志表按月按周分表实战
java·spring boot·后端
踏浪无痕1 小时前
SQLInsight:从JDBC底层到API调用的零侵入SQL监控方案
数据库·后端·开源
superman超哥2 小时前
Rust HashSet与BTreeSet的实现细节:集合类型的底层逻辑
开发语言·后端·rust·编程语言·rust hashset·rust btreeset·集合类型
superman超哥3 小时前
Rust String与&str的内部实现差异:所有权与借用的典型案例
开发语言·后端·rust·rust string·string与str·内部实现·所有权与借用
愈努力俞幸运3 小时前
rust安装
开发语言·后端·rust
踏浪无痕3 小时前
JobFlow 负载感知调度:把任务分给最闲的机器
后端·架构·开源
UrbanJazzerati3 小时前
Python自动化统计工具实战:Python批量分析Salesforce DML操作与错误处理
后端·面试
我爱娃哈哈3 小时前
SpringBoot + Seata + Nacos:分布式事务落地实战,订单-库存一致性全解析
spring boot·分布式·后端
nil4 小时前
记录protoc生成代码将optional改成omitepty问题
后端·go·protobuf
superman超哥4 小时前
Rust 范围模式(Range Patterns):边界检查的优雅表达
开发语言·后端·rust·编程语言·rust范围模式·range patterns·边界检查