C#使用StackExchange.Redis批量处理与按前缀查询首条key相关问题
问题1:批量写入时CreateBatch是否比单独ExecuteAsync更优
首先需要明确你当前代码使用的CreateTransaction()是Redis事务实现,和CreateBatch()的定位完全不同,二者的差异和选择逻辑如下:
CreateTransaction():保证所有队列命令的原子性,要么全部执行成功,要么全部失败,支持附加条件约束,执行时会将所有命令一次性发送到Redis,执行期间不会插入其他客户端的命令,有事务额外开销。CreateBatch():仅做命令打包批量发送,不保证原子性,Redis处理批内命令时可能穿插其他客户端的命令,无事务开销,性能比事务更高。- 选择建议:
- 如果你的批量写入要求操作原子性,继续使用当前事务方案即可
- 如果不需要原子性,仅需要降低网络往返开销提升批量写入性能,
CreateBatch()是更优选择
CreateBatch示例代码:
var batch = _database.CreateBatch(); var tasks = new List<Task<bool>>(); foreach (var item in toWriteItems) { var key = GenerateYourKey(item); tasks.Add(batch.StringSetAsync( key, JsonConvert.SerializeObject(item.Value), TimeSpan.FromTicks(absoluteExpiration.Value.Ticks) )); } // 批量发送所有命令 batch.Execute(); // 可await所有Task获取执行结果 await Task.WhenAll(tasks);
问题2:前缀匹配查询第一个key的实现方案
生产环境绝对禁止直接调用Keys()方法,该命令会全量遍历所有key,数据量大会直接阻塞Redis实例,可用方案如下:
- 无需FIFO顺序,仅需要任意一个匹配前缀的key:
使用Redis的SCAN增量遍历命令,StackExchange.Redis中可直接调用:
SCAN支持分片迭代,不会阻塞Redis,拿到第一个匹配结果即可终止遍历,不需要全量拉取所有匹配key。var firstMatchKey = _database.Execute("SCAN", "0", "MATCH", "[G:A][SG:B]*", "COUNT", "100") .ToDictionary()["results"] .ToRedisValueArray() .FirstOrDefault(); - 需要FIFO顺序(返回最早写入的前缀匹配key):
单独维护前缀对应的索引结构:每次写入[G:A][SG:B]前缀的key时,同时将key追加到专门的List结构中,比如List的key为Index:[G:A][SG:B],写入时调用ListRightPushAsync("Index:[G:A][SG:B]", newKey),需要查询时直接调用ListGetByIndexAsync("Index:[G:A][SG:B]", 0)即可O(1)拿到最早写入的匹配key,性能最优。
内容的提问来源于stack exchange,提问作者Punit
相关产品推荐
相关产品推荐

