news 2026/5/17 5:24:34

分布式缓存实战:Redis与多级缓存架构的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分布式缓存实战:Redis与多级缓存架构的完整指南

分布式缓存实战:Redis与多级缓存架构的完整指南

大家好,我是迪哥。缓存是提升系统性能的关键组件,从本地缓存到分布式缓存,从 Redis 到多级缓存架构,我们经历了多次优化。今天就聊聊分布式缓存的最佳实践。

多级缓存架构

┌─────────────────────────────────────────────────────────────┐ │ 多级缓存架构 │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 本地缓存 │ │ Redis │ │ 数据库 │ │ │ │ Caffeine │ │ 分布式缓存 │ │ MySQL │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 应用层 │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘

本地缓存:Caffeine

配置示例

@Configuration public class CaffeineConfig { @Bean public Cache<String, 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 Cache<String, 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 BloomFilter<Long> userFilter; public BloomFilterService() { userFilter = BloomFilter.create( Funnels.longFunnel(), 1000000, // 预计元素数量 0.01 // 误判率 ); // 初始化过滤器 List<Long> 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 Map<String, 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 还高 😂

我是迪哥,我们下期再见!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/17 5:23:37

在C++中不用宏怎么打日志的使用建议

使用建议从上面的使用可以看出&#xff0c;std::source_location 可以以函数的形式进行调用&#xff0c;从而避免了使用宏所产生的一些弊端。但是由于使用的方式一般是以默认参数进行的&#xff0c;因此不是适合变参的情况&#xff0c;除非在外部传入 std::source_location::cu…

作者头像 李华
网站建设 2026/5/17 5:22:00

Midjourney树胶重铬酸盐渲染实战手册(从化学机理到Prompt工程)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Midjourney树胶重铬酸盐渲染的起源与本质 树胶重铬酸盐&#xff08;Gum Bichromate&#xff09;是一种起源于19世纪末的古典摄影工艺&#xff0c;其核心原理是利用重铬酸盐在紫外光照射下使阿拉伯树胶发…

作者头像 李华
网站建设 2026/5/17 5:20:09

BigCodeBench:代码生成模型的“硬核”评测基准与工程实践指南

1. 项目概述&#xff1a;当代码生成模型遇上“硬核”评测如果你关注过AI编程助手&#xff0c;比如GitHub Copilot、通义灵码&#xff0c;或者玩过ChatGPT的代码生成功能&#xff0c;你肯定有过这样的体验&#xff1a;让AI写一个“快速排序”或者“反转链表”&#xff0c;它几乎…

作者头像 李华
网站建设 2026/5/17 5:20:04

AI编排与技能提升平台:构建开发者生态的技术架构与实战

1. 项目概述&#xff1a;一个面向AI编排与技能提升的生态协同平台最近在和一些做AI应用开发的朋友聊天&#xff0c;大家普遍有个痛点&#xff1a;现在大模型和AI工具链发展太快了&#xff0c;从提示词工程、智能体&#xff08;Agent&#xff09;编排&#xff0c;到模型微调、应…

作者头像 李华
网站建设 2026/5/17 5:18:48

基于向量检索与代码语义嵌入的智能代码搜索系统构建指南

1. 项目概述&#xff1a;从“Copaw Code”看AI驱动的代码搜索与理解新范式最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“QSEEKING/copaw-code”。光看这个名字&#xff0c;可能有点摸不着头脑。“Copaw”听起来像是个组合词&#xff0c;我猜可能是“Code”和“Paw”&a…

作者头像 李华
网站建设 2026/5/17 5:17:48

Armv8-A架构PMU寄存器解析与性能监控实战

1. AArch64 PMU寄存器架构解析在Armv8-A架构中&#xff0c;性能监控单元(Performance Monitoring Unit, PMU)是处理器微架构的重要组成部分。以Cortex-A78C为例&#xff0c;其PMU实现了6个通用事件计数器和1个专用周期计数器&#xff0c;支持超过50种微架构事件监控。这些寄存器…

作者头像 李华