You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Redis缓存驱逐后校验缓存有效性的实现方法问询

解决方法

为什么getNativeCache没有返回有效内容

Spring Cache是抽象层实现,你通过cacheManager.getCache(cacheName)拿到的Cache实例,在Redis缓存场景下实际类型是RedisCache,它的getNativeCache()返回的是RedisOperations操作对象,不是直接的缓存内容集合,你没有做类型转换就直接调用自然拿不到有效信息。

具体实现步骤

1. 类型转换获取Redis操作实例

先做类型校验与转换,避免强转异常:

import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.core.RedisOperations;

Cache cache = cacheManager.getCache(cacheName);
// 校验缓存实例是否为Redis类型
if (!(cache instanceof RedisCache redisCache)) {
    // 非Redis缓存实例,直接判定缓存无效,触发对应告警逻辑
    throw new IllegalArgumentException("目标缓存非Redis类型");
}
// 转换获取Redis操作工具实例
RedisOperations<String, Object> redisOps = (RedisOperations<String, Object>) redisCache.getNativeCache();

2. 校验Redis缓存是否可正常读写

通过写入测试键、读取验证、删除测试键的流程判断缓存可用性:

import java.time.Duration;

String testKey = "cache_health_check:" + System.currentTimeMillis();
String testValue = "check_value";
try {
    // 构造符合当前缓存规则的Redis Key
    String cacheTestKey = redisCache.createCacheKey(testKey);
    // 写入测试键,设置10秒过期避免残留
    redisOps.opsForValue().set(cacheTestKey, testValue, Duration.ofSeconds(10));
    // 读取验证
    Object readResult = redisOps.opsForValue().get(cacheTestKey);
    if (!testValue.equals(readResult)) {
        // 读写结果不一致,缓存功能异常,触发告警
    }
    // 删除测试键
    redisOps.delete(cacheTestKey);
} catch (Exception e) {
    // Redis操作抛出异常,缓存不可用,触发告警
}

3. 统计缓存条目、校验驱逐后是否有残留

Spring RedisCache默认会给当前缓存下所有Key添加[缓存名]::前缀,我们扫描匹配该前缀的Key即可统计条目数量:

注意:生产环境禁止使用keys命令,大数据量场景下会阻塞Redis,推荐使用scan命令迭代统计

测试环境快速统计(keys命令)

String keyPrefix = cacheName + "::";
Set<String> remainKeys = redisOps.keys(keyPrefix + "*");
int remainSize = remainKeys != null ? remainKeys.size() : 0;
if (remainSize > 0) {
    // 缓存驱逐后仍有残留条目,触发告警
}

生产环境安全统计(scan命令)

import org.springframework.data.redis.core.ScanOptions;
import java.util.concurrent.atomic.AtomicInteger;

String keyPrefix = cacheName + "::";
ScanOptions scanOpts = ScanOptions.scanOptions()
        .match(keyPrefix + "*")
        .count(1000)
        .build();
AtomicInteger remainSize = new AtomicInteger(0);

redisOps.executeWithStickyConnection(conn -> {
    try (var cursor = conn.scan(scanOpts)) {
        while (cursor.hasNext()) {
            cursor.next();
            remainSize.incrementAndGet();
        }
    }
    return null;
});

if (remainSize.get() > 0) {
    // 缓存驱逐后仍有残留条目,触发告警
}

如果是Redis集群部署,需要遍历所有集群节点执行scan操作统计总数。


内容的提问来源于stack exchange,提问作者user2001165

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 05:27:03