2016-06-13 51 views
0

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

我使用Stackexchange.Resis.extension

我目前的方法只是GET(不是POP)是

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和得到我有找到一个片段

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

但它只会做单个项目

+0

所以,你想一下子从列表中流行的所有项目? –

+0

不是所有的,但由一些可配置的号码。比方说,100一次 –

+0

已尝试var cacheClient = new StackExchangeRedisCacheClient(Muxer,new NewtonsoftSerializer()); var redisValues = cacheClient.ListGetFromRight (key);但它只会弹出单个项目 –

回答

1

我假设你正在研究一个队列,您可以在一个位置插入1000个项目,并按照插入顺序在多个位置检索它们。

你不能用一个命令来实现它,但你可以用两个命令来完成它。你可以写一个lua脚本来使它们成为原子。

Lrange: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 

您有多个客户端 每个试图访问这个卢阿块。说你的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 
+0

谢谢Karthikeyan。我的分析是一样的,我需要两个命令。我可能需要一个lua脚本来实现它。我将尝试制作一个可以从ScriptEvaluate调用的单个lua脚本。但我直接从api寻找解决方案而无需使用Lua脚本 –

+0

您可以帮助我为这些操作组合使用Lua脚本。以前我只有这种脚本的一个经验,在http://stackoverflow.com/questions/34871567/redis-distributed-increment-with-locking –

0

感谢卡菲基恩。 与Redis的我的C#代码如下

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的关键