Redis Pop list item 按项目数
Redis Pop list item By numbers of items
我有一个分布式系统,在一个地方我在 redis 列表中插入大约 10000 个项目,然后调用我的多个应用程序挂钩来处理项目。我需要的是拥有一些带有项目数量的 ListLeftPop 类型的方法。它应该从 redis 列表中删除项目并 return 到我的调用应用程序。
我正在使用 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 和 get,我找到了一个片段
var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer());
var redisValues = cacheClient.ListGetFromRight<T>(key);
但它只适用于单个项目
我假设您正在处理一个 队列,您在一个地方插入 1000 个项目并在多个地方检索它们 它被插入。
你不能用一个命令来实现它,但你可以用 2 个命令来实现。您可以编写 lua 脚本使它们成为原子。
L 范围:http://redis.io/commands/lrange
Lrange list -100 -1
这将列出列表中的前 100 个元素。这里的偏移量是-100。
请注意,这将 return 项目以与插入顺序相反的顺序排列。所以需要反向循环保证队列机制
Ltrim : http://redis.io/commands/ltrim
ltrim list 0 -101
这将 trim 列表中的前 100 个元素。这里 101 是 n+1 所以它必须是 101。这里的偏移量是 101
将它们写在 lua 块中将确保您的原子性。
举个简单的例子
You insert 100 elements in a single place.
lpush list 1 2 3 .. 100
You have multiple clients
each trying to access this lua block. Say your n value is 5 here. 1st
client gets in and gets first 5 elements inserted.
127.0.0.1:6379> lrange list -5 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
You keep them in your lua object and delete them.
127.0.0.1:6379> LTRIM list 0 -6
OK
return 到你的代码,现在你想要的结果是 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。
我的 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 键
我有一个分布式系统,在一个地方我在 redis 列表中插入大约 10000 个项目,然后调用我的多个应用程序挂钩来处理项目。我需要的是拥有一些带有项目数量的 ListLeftPop 类型的方法。它应该从 redis 列表中删除项目并 return 到我的调用应用程序。
我正在使用 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 和 get,我找到了一个片段
var cacheClient = new StackExchangeRedisCacheClient(Muxer, new NewtonsoftSerializer());
var redisValues = cacheClient.ListGetFromRight<T>(key);
但它只适用于单个项目
我假设您正在处理一个 队列,您在一个地方插入 1000 个项目并在多个地方检索它们 它被插入。
你不能用一个命令来实现它,但你可以用 2 个命令来实现。您可以编写 lua 脚本使它们成为原子。
L 范围:http://redis.io/commands/lrange
Lrange list -100 -1
这将列出列表中的前 100 个元素。这里的偏移量是-100。 请注意,这将 return 项目以与插入顺序相反的顺序排列。所以需要反向循环保证队列机制
Ltrim : http://redis.io/commands/ltrim
ltrim list 0 -101
这将 trim 列表中的前 100 个元素。这里 101 是 n+1 所以它必须是 101。这里的偏移量是 101
将它们写在 lua 块中将确保您的原子性。
举个简单的例子
You insert 100 elements in a single place.
lpush list 1 2 3 .. 100
You have multiple clients each trying to access this lua block. Say your n value is 5 here. 1st client gets in and gets first 5 elements inserted.
127.0.0.1:6379> lrange list -5 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
You keep them in your lua object and delete them.
127.0.0.1:6379> LTRIM list 0 -6
OK
return 到你的代码,现在你想要的结果是 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。 我的 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 键