谈谈使用Redis缓存时批量删除的几种实现

简介: 原文:谈谈使用Redis缓存时批量删除的几种实现前言 在使用缓存的时候,我们时不时会遇到这样一个需求,根据缓存键的规则去批量删除这些数据,比较常见的就是按前缀去删除。 举个简单的例子,Redis中现在有几百个商品的数据,这些数据的key值是有一定规律的,都是以product:id的形式存在的。
原文: 谈谈使用Redis缓存时批量删除的几种实现

前言

在使用缓存的时候,我们时不时会遇到这样一个需求,根据缓存键的规则去批量删除这些数据,比较常见的就是按前缀去删除。

举个简单的例子,Redis中现在有几百个商品的数据,这些数据的key值是有一定规律的,都是以product:id的形式存在的。

现在由于不得以为的原因要删除这几百个商品的数据,这个时候我们肯定就要把缓存键以product:开头的给全部删除掉。

其实这个需求在Redis中是可以很容易去实现的。

来看看几种常见的做法。

常见的几种做法

  1. 用Keys命令找到key之后执行删除操作
  2. 用Scan命令找到key之后执行删除操作(2.8.0版本之后)
  3. 添加缓存数据的时候,可以同时将key存放到一个SET中,然后依据这个SET来执行删除操作

对于Keys命令,网上有不少血的教训,对于生产环境还是要谨慎谨慎再谨慎!能不用就别用。

Scan命令的话是大部分人推荐的做法,是增量式迭代的一个命令。

存到SET中就相对繁琐一点,而且额外占用了一部分内存。而且在进行删除的时候还要从这里读取出相应的key,同时也要移除这部分key的数据。

下面来看看如何在.NET Core中来处理,主要还是针对SCAN的做法。

示例操作Redis用的是StackExchange.Redis

使用IServer.Keys

可能有人会有疑惑,不是说Keys命令尽量不要用吗?怎么你还用?

这个还真的要解释一下!

可能从方法上,我们找遍所有IServer和IDataBase接口都找不到纯粹的SCAN命令(SetScan,HashScan等除外)。

但是如果看过里面的实现,你就会知道是为什么了!

传送门:Keys

可以看看下图高亮的两行代码:

img_da42897c350567ed78e007265f529b0e.png

大致意思就是,如果你用的Redis的版本支持SCAN命令,走的就是SCAN,反之只能是KEYS了。

下面定义一个查找RedisKey的方法。

private static RedisKey[] SearchRedisKeys(IServer server, string pattern)
{
    var keys = server.Keys(pattern: pattern).ToArray();
    Console.WriteLine("Search Count-{0}",keys.Length);
    return keys;
}

知道那些Key要删除,剩下的就比较简单了!

private static void KeysOrScanSolution(IServer server,IDatabase db, string pattern)
{            
    db.KeyDelete(SearchRedisKeys(server, pattern));                        
}

使用IDatabase.Execute

IServer.Keys可以说是隐式的调用了SCAN命令,那么我们自然也可以显式的去调用这个命令来完成这些。

private static RedisKey[] SearchRedisKeys(IDatabase db,string pattern)
{
    var keys = new HashSet<RedisKey>();

    int nextCursor = 0;
    do
    {
        RedisResult redisResult = db.Execute("SCAN", nextCursor.ToString(), "MATCH", pattern, "COUNT", "1000");
        var innerResult = (RedisResult[])redisResult;

        nextCursor = int.Parse((string)innerResult[0]);

        List<RedisKey> resultLines = ((RedisKey[])innerResult[1]).ToList();

        keys.UnionWith(resultLines);
    }
    while (nextCursor != 0);

    return keys.ToArray();
}

删除的代码。

private static void ExecuteSolution(IDatabase db, string pattern)
{
    db.KeyDelete(SearchRedisKeys(db, pattern));
}

当然还有一种做法是调用lua脚本去完成,这里就不细说了。

总结

虽然上面几种做法能比较简单的处理这个问题,但是在拿出这些Keys的时候,客户端的内存占用可能会比较大,尤其是有大量符合条件的缓存项的时候。

涉及缓存的诸多操作(包含根据前缀去删除缓存项),我也在EasyCaching中实现了相应的操作,后面也会不断的抽时间来完善这一项目,有兴趣的朋友可以关注一下。

文中的示例代码 RedisBatchRemoveSolution

目录
相关文章
|
8月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
3月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
4月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
225 1
Redis专题-实战篇二-商户查询缓存
|
3月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
4月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
7月前
|
NoSQL 测试技术 Redis
Redis批量删除Key的三种方式
Redis批量删除Key是优化数据库性能的重要操作,本文介绍三种高效方法:1) 使用通配符匹配(KEYS/SCAN+DEL),适合不同数据规模;2) Lua脚本实现原子化删除,适用于需要事务保障的场景;3) 管道批量处理提升效率。根据实际需求选择合适方案,注意操作不可逆,建议先备份数据,避免内存溢出或阻塞。
|
存储 缓存 NoSQL
Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存|学习笔记
快速学习 Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存
Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存|学习笔记
|
缓存 NoSQL 安全
6.0Spring Boot 2.0实战 Redis 分布式缓存6.0|学习笔记
快速学习6.0Spring Boot 2.0实战 Redis 分布式缓存6.0。
572 0
6.0Spring Boot 2.0实战 Redis 分布式缓存6.0|学习笔记
|
缓存 NoSQL Redis
首页数据显示-添加 redis 缓存(3)| 学习笔记
快速学习 首页数据显示-添加 redis 缓存(3)
257 0
首页数据显示-添加 redis 缓存(3)| 学习笔记
|
缓存 NoSQL Java
首页数据显示-添加 redis 缓存(1) | 学习笔记
快速学习 首页数据显示-添加 redis 缓存(1)
337 0
首页数据显示-添加 redis 缓存(1) | 学习笔记