Redis:原理剖析、常用功能与项目实战
Redis 是一款高性能的内存数据库,支持丰富的数据结构,常用于缓存、分布式锁、消息队列等场景。本文从原理、使用方式、常见问题与调优等角度系统介绍 Redis 的核心能力与实战经验。
一、Redis 常见数据结构与使用
类型 | 描述 | 示例用途 |
---|---|---|
String | 字符串类型,基本键值存储 | 缓存单个对象数据 |
Hash | 类似于 Map 的结构 | 存储用户信息 |
List | 链表结构,支持队列操作 | 消息队列、任务列表 |
Set | 无序集合,自动去重 | 标签系统、抽奖活动 |
ZSet | 有序集合,按分值排序 | 排行榜、延迟队列 |
// 示例:存储用户信息
redisTemplate.opsForHash().put("user:1001", "name", "Tom");
redisTemplate.opsForHash().put("user:1001", "age", "20");
二、Redis 高级功能
1. 过期时间与持久化
redisTemplate.opsForValue().set("code:email", "1234", Duration.ofMinutes(5));
2. 分布式锁(简易实现)
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock:order", "1", Duration.ofSeconds(10));
if (Boolean.TRUE.equals(lock)) {
try {
// 执行业务逻辑
} finally {
redisTemplate.delete("lock:order");
}
}
3. 发布订阅(Pub/Sub)
redisTemplate.convertAndSend("chat", "Hello from user1!");
三、项目实战:舆情系统数据加速场景
在舆情监测系统中,为降低 MySQL 压力,我们对以下数据使用 Redis 缓存优化:
- 热门搜索词缓存(ZSet)
- 用户操作记录(List)
- 高频数据快照(String / Hash)
// 热门关键词打分
redisTemplate.opsForZSet().incrementScore("hotwords", "TikTok", 1);
// 获取排行榜
Set<String> topKeywords = redisTemplate.opsForZSet().reverseRange("hotwords", 0, 9);
// 用户行为日志
redisTemplate.opsForList().leftPush("user:log:123", "clicked:news1");
redisTemplate.expire("user:log:123", Duration.ofDays(1));
// 快照缓存
Map<String, String> article = Map.of("title", "事件分析", "content", "详细内容...");
redisTemplate.opsForHash().putAll("article:snapshot:456", article);
redisTemplate.expire("article:snapshot:456", Duration.ofHours(1));
四、常见问题与调优建议
1. 缓存穿透
方案一:缓存空值
String value = redisTemplate.opsForValue().get("user:9999");
if (value == null) {
value = dbService.query("user:9999");
redisTemplate.opsForValue().set("user:9999", "", Duration.ofMinutes(5));
}
方案二:布隆过滤器(Guava)
BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000000);
filter.put("user:1001");
if (!filter.mightContain("user:9999")) {
return null;
}
2. 缓存击穿
方案:互斥锁 + 双重检查
String value = redisTemplate.opsForValue().get("hot:article:1");
if (value == null) {
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock:article:1", "1", Duration.ofSeconds(5));
if (Boolean.TRUE.equals(lock)) {
try {
value = dbLoad("article:1");
redisTemplate.opsForValue().set("hot:article:1", value, Duration.ofMinutes(5));
} finally {
redisTemplate.delete("lock:article:1");
}
} else {
Thread.sleep(50);
return redisTemplate.opsForValue().get("hot:article:1");
}
}
3. 缓存雪崩
方案:过期时间添加随机因子
int base = 300; // 秒
int rand = new Random().nextInt(300);
redisTemplate.opsForValue().set("key", value, Duration.ofSeconds(base + rand));
4. 内存膨胀 / 淘汰失败
- 使用
MEMORY STATS
,INFO
监控内存 - 设置淘汰策略:
allkeys-lru
- 拒绝大 Key(避免 List/Set 里百万元素)
5. 禁止阻塞型命令
- 禁止:
KEYS *
、FLUSHALL
- 替代:
SCAN
进行分页遍历
Cursor<byte[]> cursor = redisTemplate.getConnectionFactory().getConnection()
.scan(ScanOptions.scanOptions().match("user:*").count(100).build());
五、持久化与主从复制
1. 持久化机制
Redis 提供两种主要的持久化机制:
- RDB(快照):周期性保存数据快照至磁盘,性能影响小,适合灾难恢复。
- AOF(追加日志):记录每次写操作,重启时通过日志重放恢复数据,保障更高数据完整性。
混合持久化(RDB + AOF):结合两者优点,在 Redis 7 中已为默认配置。
配置示例(redis.conf):
save 900 1
appendonly yes
appendfilename "appendonly.aof"
2. 主从复制与高可用
- Redis 支持一主多从架构,从节点只读。
- 主节点故障后可通过 Sentinel 实现自动主从切换。
- Redis Cluster 实现数据分片 + 高可用(多主多从)。
部署示意:
主节点(Master)
├── 从节点1(Slave)
└── 从节点2(Slave)
六、Redis 在分布式系统中的应用场景
场景 | 使用方式 | 示例代码/说明 |
---|---|---|
分布式锁 | setIfAbsent + expire | 同上第二章示例 |
缓存(热点/冷数据) | String/Hash + 过期策略 | redisTemplate.opsForValue().set(key, val, timeout); |
排行榜系统 | ZSet 结构,打分 + 排序 | redisTemplate.opsForZSet().incrementScore(key, item, 1); |
计数器/限流器 | incr、lua 脚本控制 | redisTemplate.opsForValue().increment("count"); |
实时推荐/社交关注 | Set/Hash/ZSet 组合 | Set 存关注人列表,ZSet 存推荐分数 |
限流器 Lua 脚本示例(固定窗口):
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then
return 0
else
redis.call("INCR", key)
redis.call("EXPIRE", key, 60)
return 1
end
Java 中执行 Lua 脚本:
DefaultRedisScript<Long> script = new DefaultRedisScript<>();
script.setScriptText(luaScript);
script.setResultType(Long.class);
Long result = redisTemplate.execute(script, List.of("req:ip:127.0.0.1"), "10");
七、总结
Redis 是现代分布式系统中不可或缺的中间件,性能高、功能强、生态丰富。
- 合理选择数据结构,是性能的核心保障
- 针对缓存一致性与雪崩问题需做好应对机制
- 配合 Spring Data Redis,开发效率高,易集成