Jedis/Redis Lua 个脚本的 SocketTimeout 异常

Jedis/Redis SocketTimeout exception on Lua scripts

我们正在使用 lua 脚本对数据库更新执行数据批量删除。 Jedis 使用管道执行 lua 脚本。

local result = redis.call('lrange',key,0,12470)
for i,k in ipairs(result) do
   redis.call('del',k)
   redis.call('ltrim',key,1,k)
end

try (Jedis jedis = jedisPool.getResource()) {
        Pipeline pipeline = jedis.pipelined();
        long len = jedis.llen(table);
         String script = String.format(DELETE_LUA_SCRIPT, table, len);
    LOGGER.info(script);
    pipeline.eval(script);
    pipeline.sync();
    } catch (JedisConnectionException e) {
        LOGGER.info(e.getMessage());
    }

对于大范围,我们注意到 lua 脚本变慢并且我们得到 SocketTimeOutExceptions。

运行 redis-cli slowlog 仅显示 lua 执行时间过长的脚本。

有更好的方法吗?我的 lua 脚本被阻塞了吗?

当我只使用管道进行批量删除时,slowlog 也 returns 慢查询。

try (Jedis jedis = jedisPool.getResource()) {
        Pipeline pipeline = jedis.pipelined();
        long len = jedis.llen(table);
        List<String> queriesContainingTable = jedis.lrange(table,0,len);
        if(queriesContainingTable.size() > 0) {
            for (String query: queriesContainingTable) {
                pipeline.del(query);
                pipeline.lrem(table,1,query);
            }
            pipeline.sync();
        }
    } catch (JedisConnectionException e) {
        LOGGER.info("CACHE INVALIDATE FAIL:"+e.getMessage());
    }

slowlog 能够单独存储前 128 个慢日志(可以在 redis.conf slowlog-max-len 128 中更改)。因此,您使用 LUA 脚本的第一个模型肯定是一个阻塞模型。

如果你把这样一个号码(12470)一个一个地删除,肯定是阻塞的,因为它需要更多的时间才能完成。在 2 个模型中,第 2 个对我来说很好(使用管道),因为你避免了迭代,你所做的就是点击 del 查询 n 次。

您可以对每 100 或 1000 个键使用多个键的删除(经过小型测试后您认为最佳)。您可以将它们一起组合到一个管道中。

或者如果你可以在没有原子性的情况下做同样的事情,你可以在一个循环中一次删除每 100 或 1000 个键,这样它就不会成为阻塞调用。

尝试不同的组合,采用指标并使用优化的指标。