Jedis/Redis Lua脚本中的SocketTimeout异常

我们正在使用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脚本变慢并且出现SocketTimeOut异常。

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

是否有更好的方法来解决这个问题?我的lua脚本会阻塞吗?

当我只使用管道进行批量删除时,慢查询日志还会返回慢查询。

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());
    }
点赞
用户4483094
用户4483094

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

如果你一次一次地删除这么多数据(12470),那么这显然是一种阻塞型的模型,因为它需要更长的时间来完成。在这两种模型中,第二种方式更好(使用pipeline),因为您避免了迭代,所有你只需要用del查询n次。

您可以为每100或1000个键使用del对多个键进行删除(在小的测试后选择最优的值),将它们一起分组到pipeline中。

或者,如果您可以在不保持原子性的情况下执行相同的操作,您可以在循环中一次删除100或1000个键,这样它就不会成为一个阻塞式调用。

尝试使用不同的组合进行测试并记录度量数据,然后选择最优化的方式。

2016-06-08 09:35:11