欢迎光临
我们一直在努力

亿级流量电商网站Redis缓存设计与性能优化全解析

一、缓存穿透:当查询不存在的数据时

缓存穿透是指查询一个数据库中根本不存在的数据,导致请求直接穿透缓存层直达数据库,失去缓存保护作用。

主要原因:

  • 业务代码或数据问题

  • 恶意攻击、爬虫大量请求不存在的数据

  • 解决方案:

    1. 缓存空对象

    将查询为空的Key也缓存起来,并设置较短的过期时间(如300秒),避免频繁查询数据库。

    String get(String key) {
    String cacheValue = cache.get(key);
    if (StringUtils.isBlank(cacheValue)) {
    String storageValue = storage.get(key);
    cache.set(key, storageValue);
    if (storageValue == null) {
    cache.expire(key, 60 * 5); // 空值缓存300秒
    }
    return storageValue;
    }
    return cacheValue;
    }

    2. 布隆过滤器(Bloom Filter)

    使用布隆过滤器预先过滤掉肯定不存在的数据请求。

    特点:

    • 当过滤器说某个值不存在时,肯定不存在

    • 当过滤器说存在时,可能不存在(存在误判率)

    Redisson实现示例:

    RBloomFilter<String> bloomFilter = redisson.getBloomFilter("nameList");
    bloomFilter.tryInit(100000000L, 0.03); // 预计元素1亿,误差率3%
    bloomFilter.add("zhuge");

    // 查询前先判断
    if (!bloomFilter.contains(key)) {
    return "";
    }

    二、缓存击穿:热点Key突然失效

    大量缓存同时在某一时刻失效,导致所有请求直接访问数据库。

    解决方案:错峰过期

    int expireTime = new Random().nextInt(300) + 300; // 300-600秒随机
    cache.expire(key, expireTime);

    三、缓存雪崩:缓存层整体失效

    缓存层无法提供服务(如Redis集群宕机),导致流量直接冲击数据库层。

    防御策略:

  • 保证高可用:使用Redis Sentinel或Cluster

  • 限流降级:引入Sentinel/Hystrix,对非核心数据直接返回降级信息

  • 提前演练:模拟缓存宕机场景,制定应急预案

  • 四、热点Key重建优化

    热点Key失效时,大量线程同时重建缓存可能导致服务崩溃。

    解决方案:互斥锁

    String get(String key) {
    String value = redis.get(key);
    if (value == null) {
    String mutexKey = "mutex:key:" + key;
    if (redis.set(mutexKey, "1", "ex 180", "nx")) {
    value = db.get(key);
    redis.setex(key, timeout, value);
    redis.delete(mutexKey);
    } else {
    Thread.sleep(50);
    return get(key);
    }
    }
    return value;
    }

    五、缓存与数据库双写不一致

    常见场景:

  • 先更新数据库,后删除缓存 → 可能导致读取旧数据

  • 先删除缓存,后更新数据库 → 并发读可能重建旧缓存

  • 解决方案:

  • 容忍短期不一致:为缓存设置过期时间

  • 分布式锁:保证读写顺序性

  • 监听Binlog:通过Canal等工具异步更新缓存

  • 六、Redis开发规范与性能优化

    1. 键值设计规范

    • Key命名:业务名:表名:id(如trade:order:1)

    • 避免BigKey:

      • String类型 ≤ 10KB

      • 集合元素 ≤ 5000个

    • 渐进式删除BigKey:使用hscan、sscan等分批删除

    2. 命令使用建议

    • 警惕O(N)命令:如hgetall、smembers

    • 禁用危险命令:keys、flushall

    • 善用批量操作:mget、mset、pipeline

    • 事务较弱,推荐使用Lua脚本

    3. 客户端连接池优化

    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(50); // 最大连接数
    config.setMaxIdle(20); // 最大空闲连接
    config.setMinIdle(5); // 最小空闲连接
    config.setTestOnBorrow(true);

    连接池大小计算公式:
    maxTotal ≈ (QPS / 单连接QPS) * 冗余系数

    4. 内存淘汰策略(8种)

    • volatile-lru(推荐):从已设置过期时间的Key中使用LRU淘汰

    • allkeys-lru:从所有Key中使用LRU淘汰

    • noeviction:不淘汰,内存满时拒绝写入

    5. Linux内核参数优化

    # 减少SWAP使用倾向
    echo 1 > /proc/sys/vm/swappiness
    echo "vm.swappiness=1" >> /etc/sysctl.conf

    # 允许内存超分配,避免fork失败
    echo "vm.overcommit_memory=1" >> /etc/sysctl.conf

    # 增加文件句柄数
    ulimit -n 65535

    6. 慢查询监控

    # 设置慢查询阈值(1毫秒)
    config set slowlog-log-slower-than 1000
    # 查看慢查询日志
    slowlog get 5

    七、总结与实践建议

  • 读多写少才用缓存:写多读多且要求强一致性的场景,直接使用数据库

  • 缓存不是银弹:合理设置过期时间,容忍短期不一致

  • 监控告警不可少:关注缓存命中率、慢查询、内存使用率

  • 设计阶段考虑容灾:缓存宕机后,系统要有降级策略

  • 缓存设计是门艺术,需要在性能、一致性、复杂度之间找到平衡点。避免过度设计,让解决方案保持简洁高效,才是工程实践的真谛。

    赞(0)
    未经允许不得转载:171主机测评 » 亿级流量电商网站Redis缓存设计与性能优化全解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址