【问题标题】:Redis Pop list item By numbers of itemsRedis 弹出列表项按项数
【发布时间】:2016-10-13 09:40:18
【问题描述】:

我有一个分布式系统,我在一个地方在一个 redis 列表中插入大约 10000 个项目,然后调用我的多个应用程序挂钩来处理项目。我需要的是有一些带有项目数量的 ListLeftPop 类型的方法。它应该从 redis 列表中删除项目并返回到我的调用应用程序。

我正在使用 Stackexchange.Resis.extension

我目前仅用于获取(而不是弹出)的方法是

 public static List<T> GetListItemRange<T>(string key, int start, int chunksize) where T : class
        {
            List<T> obj = default(List<T>);
            try
            {
                if (Muxer != null && Muxer.IsConnected && Muxer.GetDatabase() != null)
                {
                    var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer());
                    var redisValues = cacheClient.Database.ListRange(key, start, (start + chunksize - 1));
                    if (redisValues.Length > 0)
                    {
                        obj = Array.ConvertAll(redisValues, value => JsonConvert.DeserializeObject<T>(value)).ToList();
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex.Message, ex);
            }
            return obj;
        }

对于 Pop 和 get 我找到了一个 sn-p

 var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer());
                    var redisValues = cacheClient.ListGetFromRight<T>(key);

但它只适用于单个项目

【问题讨论】:

  • 所以你想一次从列表中弹出所有项目?
  • 不是全部,而是一些可配置的数字。假设一次 100 个
  • 试过 var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer()); var redisValues = cacheClient.ListGetFromRight(key);但它只会弹出单个项目
  • 是队列还是堆栈?我的意思是 lpush lpop(队列)或 lpush rpop(堆栈)。

标签: c# caching redis stackexchange.redis .net-4.5.2


【解决方案1】:

我假设您正在处理一个队列,您在一个位置插入 1000 个项目并在多个位置检索它们按照插入顺序 .

你不能用一个命令来实现它,但你可以用 2 个命令来实现。您可以编写一个 lua 脚本来使它们具有原子性。

兰格:http://redis.io/commands/lrange

Lrange list -100 -1

这将列出列表中的前 100 个元素。这里的偏移量是-100。 请注意,这将以与其插入相反的顺序返回项目。所以需要反转循环来保证队列机制。

Ltrim : http://redis.io/commands/ltrim

ltrim list 0 -101

这将修剪列表中的前 100 个元素。这里的 101 是 n+1 所以它一定是 101。这里的偏移量是 101

将它们写入 lua 块将确保您的原子性。

让我举一个简单的例子。

您在一个位置插入 100 个元素。

lpush list 1 2 3 .. 100

您有多个客户 每个人都试图访问这个 lua 块。假设您的 n 值为 5。第一 客户端进入并插入前 5 个元素。

127.0.0.1:6379> lrange list -5 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"

您将它们保存在您的 lua 对象中并删除它们。

127.0.0.1:6379> LTRIM list 0 -6
OK

将它们返回到您的代码中,现在您想要的结果是 1 2 3 4 5 但您得到的是 5 4 3 2 1。所以您需要反转循环并执行操作。

当下一个客户端进来时,它会得到下一组值。

127.0.0.1:6379> lrange list -5 -1
1) "10"
2) "9"
3) "8"
4) "7"
5) "6"

通过这种方式,您可以实现您的要求。希望这可以帮助。

编辑:

Lua 脚本:

local result = redis.call('lrange', 'list','-5','-1')
redis.call('ltrim','list','0','-6')
return result

【讨论】:

  • 感谢 Karthikeyan。我的分析与我需要两个命令相同。而且我可能需要单个 lua 脚本来实现它。我将尝试制作可以从 ScriptEvaluate 调用的单个 lua 脚本。但是我直接从 api 寻找解决方案,不需要 Lua 脚本
  • 您能帮我编写一个用于这些操作的组合 Lua 脚本吗?以前我在stackoverflow.com/questions/34871567/… 上只有一次这样的脚本体验
【解决方案2】:

感谢卡西凯扬。 我的 C# 代码与 redis 如下

 public static RedisResult PopListItemRange(int chunksize, string key)
        {
            RedisResult valreturn = null;
            try
            {

                IDatabase db;
                if (Muxer != null && Muxer.IsConnected && (db = Muxer.GetDatabase()) != null)
                {
                    valreturn = db.ScriptEvaluate(@" local result = redis.call('lrange',KEYS[1],ARGV[1], '-1')
                                                          redis.call('ltrim',KEYS[1],'0',ARGV[2])
                                    return result", new RedisKey[] { key }, flags: CommandFlags.HighPriority, values: new RedisValue[] { -chunksize, -chunksize - 1 });
                }

            }
            catch (Exception ex)
            {
                Logger.Fatal(ex.Message, ex);
            }
            return valreturn;
        }

现在只是做一个调整,当列表为空时删除 redis 键

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-22
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多