6、Redis高并发缓存方案和性能优化

发布于:2025-08-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、主从节点失效问题及解决方案

1. 主从失效问题本质

ClientA Master Slave ClientB SET lock_key clientA_id EX 30 (加锁成功) 同步失败(网络问题) Master宕机 选举为新Master SET lock_key clientB_id EX 30 (加锁成功) ClientA Master Slave ClientB

2. 解决方案对比

方案 原理 优点 缺点 适用场景
min-replicas-to-write 要求写入N个从节点才算成功 保证数据同步性 增加写入延迟 对一致性要求高的场景
Redlock算法 需要半数以上节点写入成功 更高的可靠性 性能损耗大 极端一致性要求的场景
混合持久化 AOF+RDB混合持久化策略 平衡性能与可靠性 仍有数据丢失窗口 通用场景

二、分布式锁优化方案

1. 分段锁设计

比如商品a的id为product_1001_bike,库存有1000个,普通思路是对这个key加锁,key是product_1001_bike,每次请求只能有一个请求同时操作库存。
可以拆分key为product_1001_bike_1、product_1001_bike_2…product_1001_bike_10,每个key的库存是100,每个key就是一把锁,那么这个时候高并发下,可以最多10个请求同时操作库存。
每次选哪个锁呢?每个key放到一个数组里,随机选,或者轮询

// 传统锁
RLock lock = redisson.getLock("product_1001");

// 分段锁优化(10个分段)
String[] segmentKeys = {
    "product_1001_seg1", 
    "product_1001_seg2",
    ...
    "product_1001_seg10"
};

// 随机选择分段
Random rand = new Random();
RLock segmentLock = redisson.getLock(segmentKeys[rand.nextInt(10)]);

2. 读写锁优化

// 写操作(独占锁)
RReadWriteLock rwLock = redisson.getReadWriteLock("product_lock");
rwLock.writeLock().lock();
try {
    // 更新操作
} finally {
    rwLock.writeLock().unlock();
}

// 读操作(共享锁)
rwLock.readLock().lock();
try {
    // 查询操作
} finally {
    rwLock.readLock().unlock();
}

三、缓存问题综合解决方案

1. 缓存问题矩阵

问题类型 现象 解决方案 补充策略
缓存击穿 热点key失效瞬间高并发,大量请求打到数据库 互斥锁重建 永不过期+后台更新
缓存穿透 透(与缓存击穿作区分),查询不存在的数据,即缓存和数据库都没有,
重复请求可能还会消耗缓存和数据库性能
布隆过滤器
缓存空对象
空对象短过期时间
缓存雪崩 大量key同时失效,大量请求打到数据库和后端,
逐渐导致数据库崩溃,后端服务崩溃,甚至整个服务不可用
随机过期时间
多级缓存
熔断降级机制

2. 热点key重建优化流程

获取成功
获取失败
请求到达
缓存是否存在?
返回缓存数据
尝试获取分布式锁
查询DB并重建缓存
短暂等待后重试
释放锁

3. 热数据,读延期

每天都有访问的key,就是热数据,可以做读延期:

// 有数据直接延期 防止key过期访问数据库
String productStr = redisUtil.get(productCacheKey);
if (!StringUtils.isEmpty(productStr)) {
    product = JSON.parse0bject(productStr, Product.class);
    //读延期
    redisUtil.expire(productCacheKey, PRODUCT_CACHE_TIMEOUT, TimeUnit.SECONDS);
    return product;
}

4. 多级缓存架构

客户端请求
↓
CDN缓存 → 命中则返回
↓
Nginx本地缓存 → 命中则返回
↓
Redis集群缓存 → 命中则返回
↓
DB查询 + 回填缓存

四、开发规范与性能优化

1. Key设计规范

  • 命名规则业务:子业务:ID (如 trade:order:123)
  • 长度控制:不超过44字节(Redis优化阈值)
  • 特殊字符:禁止包含空格、换行符等

2. BigKey规避策略

数据类型 危险阈值 优化方案
String >10KB 压缩/分片
Hash/Set >1000元素 拆分为多个key
List/ZSet >5000元素 分页存储

3. 缓存双写一致性方案对比

方案 一致性 复杂度 性能影响
分布式锁 强一致 较大
延迟双删 最终一致 中等
监听binlog 最终一致
设置过期时间 弱一致

五、高级场景解决方案

1. 突发流量处理

// 使用Redisson的tryLock优化热点重建
RLock hotLock = redisson.getLock("hot:"+productId);
if (hotLock.tryLock(0, 30, TimeUnit.SECONDS)) {
    try {
        // 双重检查
        String cache = redis.get(productKey);
        if (cache == null) {
            Product p = db.get(productId);
            redis.setex(productKey, 3600, p);
        }
    } finally {
        hotLock.unlock();
    }
} else {
    // 快速失败或降级处理
    return fallbackProduct;
}

2. 多级缓存实现示例

public Product getProduct(Long id) {
    // 1. 检查本地缓存
    Product product = localCache.get(id);
    if (product != null) return product;
    
    // 2. 检查Redis缓存
    String redisKey = "product:" + id;
    product = redisTemplate.opsForValue().get(redisKey);
    if (product != null) {
        localCache.put(id, product); // 回填本地缓存
        return product;
    }
    
    // 3. 数据库查询
    return getProductFromDBWithLock(id);
}

六、监控与应急方案

1. 关键监控指标

  • 缓存命中率keyspace_hits/(keyspace_hits+keyspace_misses)
  • 大Key扫描:定期执行redis-cli --bigkeys
  • 慢查询:配置slowlog-log-slower-than 10ms

2. 应急预案

  1. 热点Key:提前预热+本地缓存
  2. 缓存雪崩:差异化过期时间+熔断降级
  3. 集群故障:手动切换+只读模式

网站公告

今日签到

点亮在社区的每一天
去签到