分布式缓存实战Redis与多级缓存架构的完整指南大家好我是迪哥。缓存是提升系统性能的关键组件从本地缓存到分布式缓存从 Redis 到多级缓存架构我们经历了多次优化。今天就聊聊分布式缓存的最佳实践。多级缓存架构┌─────────────────────────────────────────────────────────────┐ │ 多级缓存架构 │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 本地缓存 │ │ Redis │ │ 数据库 │ │ │ │ Caffeine │ │ 分布式缓存 │ │ MySQL │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 应用层 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘本地缓存Caffeine配置示例Configuration public class CaffeineConfig { Bean public CacheString, Object localCache() { return Caffeine.newBuilder() .initialCapacity(1000) .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterAccess(5, TimeUnit.MINUTES) .recordStats() .build(); } }使用示例Service public class UserService { Autowired private CacheString, User localCache; Autowired private StringRedisTemplate redisTemplate; Autowired private UserMapper userMapper; public User getUser(Long userId) { String key user: userId; // 1. 先查本地缓存 User user localCache.getIfPresent(key); if (user ! null) { return user; } // 2. 再查 Redis String json redisTemplate.opsForValue().get(key); if (json ! null) { user JSON.parseObject(json, User.class); localCache.put(key, user); return user; } // 3. 最后查数据库 user userMapper.selectById(userId); if (user ! null) { redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 30, TimeUnit.MINUTES); localCache.put(key, user); } return user; } }Redis 缓存优化缓存策略public enum CacheStrategy { READ_THROUGH, // 读穿透 WRITE_THROUGH, // 写穿透 WRITE_BEHIND, // 写回 CACHE_ASIDE; // 旁路缓存最常用 }缓存更新模式Service public class CacheService { Autowired private StringRedisTemplate redisTemplate; // 模式1先更新数据库再删除缓存 public void updateUser1(User user) { userMapper.updateById(user); redisTemplate.delete(user: user.getId()); } // 模式2先删除缓存再更新数据库 public void updateUser2(User user) { redisTemplate.delete(user: user.getId()); userMapper.updateById(user); } // 模式3延迟双删解决并发问题 Async public void updateUser3(User user) { redisTemplate.delete(user: user.getId()); userMapper.updateById(user); // 延迟一段时间后再次删除 try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } redisTemplate.delete(user: user.getId()); } }缓存问题解决问题 1缓存穿透// 使用布隆过滤器 Component public class BloomFilterService { private final BloomFilterLong userFilter; public BloomFilterService() { userFilter BloomFilter.create( Funnels.longFunnel(), 1000000, // 预计元素数量 0.01 // 误判率 ); // 初始化过滤器 ListLong userIds userMapper.selectAllIds(); userIds.forEach(userFilter::put); } public boolean mightContain(Long userId) { return userFilter.mightContain(userId); } }问题 2缓存击穿Service public class ProductService { Autowired private StringRedisTemplate redisTemplate; private final MapString, Object locks new ConcurrentHashMap(); public Product getProduct(Long productId) { String key product: productId; // 先查缓存 String json redisTemplate.opsForValue().get(key); if (json ! null) { return JSON.parseObject(json, Product.class); } // 加锁防止缓存击穿 synchronized (locks.computeIfAbsent(key, k - new Object())) { try { // 双重检查 json redisTemplate.opsForValue().get(key); if (json ! null) { return JSON.parseObject(json, Product.class); } // 查数据库 Product product productMapper.selectById(productId); if (product ! null) { redisTemplate.opsForValue().set(key, JSON.toJSONString(product), 5, TimeUnit.MINUTES); } return product; } finally { locks.remove(key); } } } }问题 3缓存雪崩// 解决方案设置随机过期时间 public void setCacheWithRandomTTL(String key, Object value) { int ttl 30 ThreadLocalRandom.current().nextInt(30); // 30-60分钟 redisTemplate.opsForValue().set(key, JSON.toJSONString(value), ttl, TimeUnit.MINUTES); }最佳实践清单维度最佳实践多级缓存本地缓存 Redis 数据库缓存策略旁路缓存模式更新模式先更新数据库再删除缓存并发问题延迟双删 分布式锁监控监控缓存命中率、热点Key说到缓存我家那只叫 Docker 的哈士奇最近学会了缓存策略——把喜欢的玩具藏在沙发底下本地缓存饿了才去狗粮碗数据库找吃的这缓存命中率比我们的 Redis 还高 我是迪哥我们下期再见
分布式缓存实战:Redis与多级缓存架构的完整指南
发布时间:2026/5/17 5:24:45
分布式缓存实战Redis与多级缓存架构的完整指南大家好我是迪哥。缓存是提升系统性能的关键组件从本地缓存到分布式缓存从 Redis 到多级缓存架构我们经历了多次优化。今天就聊聊分布式缓存的最佳实践。多级缓存架构┌─────────────────────────────────────────────────────────────┐ │ 多级缓存架构 │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 本地缓存 │ │ Redis │ │ 数据库 │ │ │ │ Caffeine │ │ 分布式缓存 │ │ MySQL │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 应用层 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘本地缓存Caffeine配置示例Configuration public class CaffeineConfig { Bean public CacheString, Object localCache() { return Caffeine.newBuilder() .initialCapacity(1000) .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterAccess(5, TimeUnit.MINUTES) .recordStats() .build(); } }使用示例Service public class UserService { Autowired private CacheString, User localCache; Autowired private StringRedisTemplate redisTemplate; Autowired private UserMapper userMapper; public User getUser(Long userId) { String key user: userId; // 1. 先查本地缓存 User user localCache.getIfPresent(key); if (user ! null) { return user; } // 2. 再查 Redis String json redisTemplate.opsForValue().get(key); if (json ! null) { user JSON.parseObject(json, User.class); localCache.put(key, user); return user; } // 3. 最后查数据库 user userMapper.selectById(userId); if (user ! null) { redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 30, TimeUnit.MINUTES); localCache.put(key, user); } return user; } }Redis 缓存优化缓存策略public enum CacheStrategy { READ_THROUGH, // 读穿透 WRITE_THROUGH, // 写穿透 WRITE_BEHIND, // 写回 CACHE_ASIDE; // 旁路缓存最常用 }缓存更新模式Service public class CacheService { Autowired private StringRedisTemplate redisTemplate; // 模式1先更新数据库再删除缓存 public void updateUser1(User user) { userMapper.updateById(user); redisTemplate.delete(user: user.getId()); } // 模式2先删除缓存再更新数据库 public void updateUser2(User user) { redisTemplate.delete(user: user.getId()); userMapper.updateById(user); } // 模式3延迟双删解决并发问题 Async public void updateUser3(User user) { redisTemplate.delete(user: user.getId()); userMapper.updateById(user); // 延迟一段时间后再次删除 try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } redisTemplate.delete(user: user.getId()); } }缓存问题解决问题 1缓存穿透// 使用布隆过滤器 Component public class BloomFilterService { private final BloomFilterLong userFilter; public BloomFilterService() { userFilter BloomFilter.create( Funnels.longFunnel(), 1000000, // 预计元素数量 0.01 // 误判率 ); // 初始化过滤器 ListLong userIds userMapper.selectAllIds(); userIds.forEach(userFilter::put); } public boolean mightContain(Long userId) { return userFilter.mightContain(userId); } }问题 2缓存击穿Service public class ProductService { Autowired private StringRedisTemplate redisTemplate; private final MapString, Object locks new ConcurrentHashMap(); public Product getProduct(Long productId) { String key product: productId; // 先查缓存 String json redisTemplate.opsForValue().get(key); if (json ! null) { return JSON.parseObject(json, Product.class); } // 加锁防止缓存击穿 synchronized (locks.computeIfAbsent(key, k - new Object())) { try { // 双重检查 json redisTemplate.opsForValue().get(key); if (json ! null) { return JSON.parseObject(json, Product.class); } // 查数据库 Product product productMapper.selectById(productId); if (product ! null) { redisTemplate.opsForValue().set(key, JSON.toJSONString(product), 5, TimeUnit.MINUTES); } return product; } finally { locks.remove(key); } } } }问题 3缓存雪崩// 解决方案设置随机过期时间 public void setCacheWithRandomTTL(String key, Object value) { int ttl 30 ThreadLocalRandom.current().nextInt(30); // 30-60分钟 redisTemplate.opsForValue().set(key, JSON.toJSONString(value), ttl, TimeUnit.MINUTES); }最佳实践清单维度最佳实践多级缓存本地缓存 Redis 数据库缓存策略旁路缓存模式更新模式先更新数据库再删除缓存并发问题延迟双删 分布式锁监控监控缓存命中率、热点Key说到缓存我家那只叫 Docker 的哈士奇最近学会了缓存策略——把喜欢的玩具藏在沙发底下本地缓存饿了才去狗粮碗数据库找吃的这缓存命中率比我们的 Redis 还高 我是迪哥我们下期再见