03 键管理与过期
🎯 学习要点
- TTL 设置与查询
- 安全扫描与匹配查找
- 键空间通知与事件监听
📖 名词解释
TTL:键的剩余存活时间,单位秒或毫秒。SCAN:游标扫描命令,分批遍历键空间,避免阻塞。KEYS:一次性全量匹配命令,易阻塞,生产需禁用或谨慎使用。键空间通知:Redis 通过发布消息告知键的事件(过期、删除)。PERSIST:移除键的过期时间,使之持久存在(直到删除)。
🧭 学习方案
- 用
set+expire+ttl 组合练习设置与查询过期时间,理解不同返回值。 - 使用
SCAN 按前缀扫描,对比 KEYS 的风险,形成统一扫描工具方法。 - 开启键空间通知并监听过期事件,在控制台打印观察触发时机。
- 设计合理的键生命周期与回收策略,避免长久不清理导致内存膨胀。
🗺️ 应用场景说明
- 支付待确认:下单后设置一个过期键,到时未支付即关闭订单。
- 清理脏数据:用
SCAN 按业务前缀批量找出旧版本键并删除。 - 定时提醒:利用过期事件监听,到期后发通知或补偿处理。
⚠️ 注意事项
- 避免使用 KEYS 在生产环境
- 使用 SCAN 分批遍历防止阻塞
- 谨慎操作大 Key 与热 Key
⏳ TTL 设置与查询
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.data.redis.core.RedisTemplate;
import java.time.Duration;
@Service
public class TtlOps {
@Autowired
RedisTemplate<String, String> tpl;
public void setTtl(String key) {
tpl.opsForValue().set(key, "v", Duration.ofMinutes(5));
}
public Long ttl(String key) {
return tpl.getExpire(key);
}
}
通俗说明
- TTL 就是“有效期标签”,到点自动失效,避免长期占用内存。
- 查询 TTL 返回
-2 代表键不存在,-1 代表没有设置过期,其它是剩余秒数。 - 热点键建议在基础 TTL 上加一点随机时间,避免同一时刻同时失效(雪崩)。
详细解释
- 业务上应定义不同数据的生命周期,重要数据用较长 TTL,临时数据用短 TTL。
persist 可移除过期时间;批量设置 TTL 建议统一封装工具方法。- 雪崩风险来自集中失效,通过随机抖动与预热减少峰值。
速记口诀
- 口诀:TTL 定生命周期,-1 无过期、-2 不存在
🔎 SCAN 遍历
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.connection.RedisConnection;
import java.util.ArrayList;
import java.util.List;
@Service
public class ScanKeys {
@Autowired
RedisTemplate<String, String> tpl;
public List<String> scanPrefix(String prefix) {
return tpl.execute((RedisConnection conn) -> {
List<String> keys = new ArrayList<>();
ScanOptions options = ScanOptions.scanOptions().match(prefix + ":*").count(100).build();
var cursor = conn.scan(options);
while (cursor.hasNext()) keys.add(new String(cursor.next()));
return keys;
});
}
}
通俗说明
SCAN 是“分批找键”的方式,不会像 KEYS 那样阻塞全局。match 前缀与 count 批次可调;扫描是近似遍历,注意游标使用。
详细解释
- 扫描用游标推进,直到游标回到 0 才结束;
count 是提示值非硬指标。 - 匹配前缀需规范命名,避免扫描出无关键影响效率。
- 不建议边扫描边删除同一键空间,最好先收集再批处理。
📣 键空间通知配置
notify-keyspace-events Ex
通俗说明
Ex 开启“过期事件”,让 Redis 在键过期时发消息通知。- 监听频道与库号有关,默认库 0 的频道为
__keyevent@0__:expired。
详细解释
- 事件类别由组合字母控制(如 K 键事件、E 过期、g 通用),按需开启。
- 过期通知在键真正删除时触发,惰性删除可能延后。
- 开启通知会有少量开销,应仅开启必要事件类别。
🔔 监听过期事件(Spring)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
@Configuration
public class KeyspaceEventsConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory factory) {
RedisMessageListenerContainer c = new RedisMessageListenerContainer();
c.setConnectionFactory(factory);
c.addMessageListener(new MessageListenerAdapter((MessageListener) (pattern, channel, message) -> {}), new PatternTopic("__keyevent@0__:expired"));
return c;
}
interface MessageListener {
void onMessage(byte[] pattern, byte[] channel, byte[] message);
}
}
通俗说明
- 容器里注册监听器,订阅过期事件频道,收到消息后执行回调。
- 适合做到期提醒/补偿清理,但事件触发依赖键实际删除时间。
详细解释
RedisMessageListenerContainer 维护订阅连接,回调逻辑需轻量与线程安全。- 处理函数里建议异步分发或投递到队列,避免阻塞监听线程。
- 注意库号与频道匹配,跨库监听需分别订阅。
🔍 小结
- TTL 查询返回值含义:
-2 表示键不存在,-1 表示没有过期时间,其他为剩余秒数。 - 删除 TTL 可用
persist;对热点键建议设置随机 TTL,缓解雪崩。 - 线上环境使用
SCAN 分批遍历,避免 KEYS 导致阻塞。 - 键空间通知需显式开启,过期事件在键被删除时触发。