redis执行lua脚本

170 阅读2分钟

1. 背景

我们现在有一个场景,获取通道的可用银行配置,目前是用到哪个银行就从redis取一次; 但是在实际使用中,我们存在一次接口获取多个通道的情况,因此期望实现,一次请求redis获取多个通道。

2. 方案

想了下面两个方案:

  • 通过lua脚本实现,一次提交多个key,通过lua遍历key获取;✅
  • 使用jedis的Pipeline 组提交;

2.1 区别总结

  • 原子性:Lua脚本提供原子性操作,而Pipeline中的命令默认不是原子的。
  • 执行位置:Lua脚本在服务器端执行,而Pipeline是客户端-服务器端的协作。
  • 复杂性:Lua脚本更适合复杂的逻辑处理,Pipeline更适合简单的批量操作。
  • 性能:对于少量key的查询,两者性能可能相差不大,但Pipeline在处理大量命令时通常更优。

2.2 选择建议

  • 如果查询操作需要原子性保证,或者涉及复杂的逻辑处理,建议使用Lua脚本。
  • 如果只是需要批量查询少量key,并且不需要原子性保证,Pipeline可能是一个更简单、高效的选择。
  • 在实际应用中,建议根据具体的需求和性能测试结果来选择最合适的方案。

最终选了第一个使用lua脚本的方案,因为项目当中一直没人用过这个,因此选了项目中用的比较多的lua脚本。

3. 编写lua命令

-- Lua脚本:批量获取Redis键值  
-- KEYS 是一个包含所有要获取的键的数组  
  
local result = {} -- 用于存储结果的数组  
  
-- 遍历所有键  
for i, key in ipairs(KEYS) do  
    -- 使用redis.call获取每个键的值  
    local value = redis.call('GET', key)  
    -- 将值添加到结果数组中  
    table.insert(result, value)  
end  
  
-- 返回结果数组  
return result

4. 在redis中执行命令

EVAL "local result = {}; for i, key in ipairs(KEYS) do local value = redis.call('GET', key); table.insert(result, value); end; return result;" 2 key1 key2

5. 编写java代码

以下是一个使用java代码执行lua脚本的demo

@Test
public void evalTest() {
    try(Jedis jedis = new Jedis("127.0.0.1", 6379);) {
        List<String> result = (List<String>)jedis.eval("local result = {}; for i, key in ipairs(KEYS) do local value = redis.call('GET', key); table.insert(result, value); end; return result;",
                Arrays.asList("key1", "key2"), new ArrayList<>());
        for (String s : result) {
            System.out.println(s);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}