首页 > 解决方案 > 如何以安全的方式 Xtrim(修剪 redis 流)

问题描述

Redis Xtrim 是保留一些记录并删除较旧的记录。

假设我有 100 条记录,我想保留最新的 10 条。(假设 java/scala API)

redis = new Jedis(...)
redis.xlen("mystream") // returns 100
// new records arrive stream at here
redis.xtrim("mystream", 10)

xlen但是,新记录在 和 的执行之间到达xtrim。因此,例如现在有 105 条记录,它将保留 95 - 105,但是我想保持从 90 开始。所以它也会修剪 90 - 95,这很糟糕。

有任何想法吗?

标签: redis

解决方案


选项 1: 如果您始终只想保留 10 个最新的,请使用:

XADD mystream MAXLEN 10 * field value ...

通过将修剪移至加法,您可以将其始终保持为 10。您可以忘记要修剪的单独逻辑。

在绝地武士中,

xadd(String key, StreamEntryID id, Map<String,String> hash, long maxLen, boolean approximateLength)

选项2: 乐观,使用事务

WATCH mystream 
XLEN mystream
MULTI
XTRIM mystream MAXLEN 10
EXEC

这里,如果流被修改了,事务就会失败,EXEC返回null,然后重试。

Jedis 交易示例

选项 3:

使用Lua 脚本来调整XTRIM目标编号。有了这个,你可以执行XLEN,做你的逻辑来决定你想要的修剪,然后做XTRIM,所有的 Redis 服务器端,原子地,所以你的流没有机会在两者之间改变。

这里有一些绝地武士的评估示例

更新:

像下面这样的 Lua 脚本应该可以解决问题:自动评估当前 myStreams 条目的数量,然后相应地调用 XTRIM。

EVAL "local streamLen = redis.call('XLEN', KEYS[1]) \n if streamLen >= tonumber(ARGV[1]) then \n return redis.call('XTRIM', KEYS[1], 'MAXLEN', streamLen - tonumber(ARGV[1])) \n else return redis.error_reply(KEYS[1]..' has less than '..ARGV[1]..' items') end" 1 myStream 90

让我们看一下Lua脚本:

local streamLen = redis.call('XLEN', KEYS[1])
if streamLen >= tonumber(ARGV[1]) then 
    return redis.call('XTRIM', KEYS[1], 'MAXLEN', streamLen - tonumber(ARGV[1]))
else
    return redis.error_reply(KEYS[1]..' has less than '..ARGV[1]..' items')
end

我发布了有关如何从 Redis 流中删除或删除给定数量的条目的单独问题的更多详细信息?


推荐阅读