引言
Redis是最流行的缓存数据库。本文介绍Redis的缓存设计模式。
一、缓存模式
1.1 Cache-Aside(旁路缓存)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public User getUser(Long id) { User user = redis.get("user:" + id); if (user != null) { return user; } user = userDao.selectById(id); if (user != null) { redis.setex("user:" + id, 3600, user); } return user; }
public void updateUser(User user) { userDao.updateById(user); redis.del("user:" + user.getId()); }
|
1.2 Read-Through
1 2 3 4 5
| @Cacheable(value = "users", key = "#id") public User getUser(Long id) { return userDao.selectById(id); }
|
1.3 Write-Through
1 2 3 4 5 6
| @CachePut(value = "users", key = "#user.id") public User updateUser(User user) { userDao.updateById(user); return user; }
|
二、缓存问题
2.1 缓存穿透
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public User getUser(Long id) { if (!bloomFilter.mightContain(id)) { return null; } User user = redis.get("user:" + id); if (user != null) { return user; } user = userDao.selectById(id); if (user == null) { redis.setex("user:" + id, 60, "null"); return null; } redis.setex("user:" + id, 3600, user); return user; }
|
2.2 缓存雪崩
1 2 3 4 5 6 7 8
|
int expire = 3600 + new Random().nextInt(300); redis.setex(key, expire, value);
data.expireTime = System.currentTimeMillis() + 3600000; redis.set(key, data);
|
2.3 缓存击穿
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public User getUser(Long id) { User user = redis.get("user:" + id); if (user != null) { return user; } String lockKey = "lock:user:" + id; if (redis.setnx(lockKey, "1", 10)) { try { user = userDao.selectById(id); redis.setex("user:" + id, 3600, user); } finally { redis.del(lockKey); } } else { Thread.sleep(50); return getUser(id); } return user; }
|
三、缓存更新策略
1 2 3 4 5 6 7 8 9
| redis.setex(key, 3600, value);
redis.set(key, newValue);
userDao.updateById(user); redis.del("user:" + user.getId());
|
四、缓存预热
1 2 3 4 5 6 7
| @PostConstruct public void warmUp() { List<User> hotUsers = userDao.selectHotUsers(); for (User user : hotUsers) { redis.setex("user:" + user.getId(), 3600, user); } }
|
总结
Redis缓存核心:
- 缓存模式:Cache-Aside最常用
- 三大问题:穿透、雪崩、击穿
- 更新策略:超时、主动更新
- 缓存预热:提前加载热点数据
参考资料