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

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

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

多级缓存架构

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

本地缓存:Caffeine

配置示例

java 复制代码
@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();
    }
}

使用示例

java 复制代码
@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 缓存优化

缓存策略

java 复制代码
public enum CacheStrategy {
    READ_THROUGH,    // 读穿透
    WRITE_THROUGH,   // 写穿透
    WRITE_BEHIND,    // 写回
    CACHE_ASIDE;     // 旁路缓存(最常用)
}

缓存更新模式

java 复制代码
@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:缓存穿透

java 复制代码
// 使用布隆过滤器
@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:缓存击穿

java 复制代码
@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:缓存雪崩

java 复制代码
// 解决方案:设置随机过期时间
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 还高 😂

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

相关推荐
吃饱了得干活14 小时前
扫码登录如何实现?从原理到实战
java·spring boot·redis
JRedisX14 小时前
JRedisX 项目骨架搭建指南 从零开始 — 手把手教你搭
java
zx11545014 小时前
Java 反射 (SpringBoot篇)
java·架构
2301_7944615715 小时前
Activiti/BPMN 2.0 的 4 种网关
java·服务器·开发语言
她的男孩15 小时前
低代码只能做单表 CRUD?我们一行代码没写,搭了个完整进销存
java·后端·架构
147API15 小时前
Claude Tag 进入 Slack 后,团队智能体需要哪些任务与审计字段
java·开发语言·数据库
dyonggan15 小时前
IDEA从零搭建SpringCloud Alibaba完整工程
java·spring cloud·intellij-idea
代码雕刻家15 小时前
编程语法细节
java·c语言·开发语言
SimonKing15 小时前
Agnes AI出桌面版了,可图可视频,免费用
java·后端·程序员
左左右右左右摇晃15 小时前
手写Tomcat原理整理
java·开发语言·笔记·tomcat