冰河技术
导读
♻学习路线
  • 面试必问系列

    • 面试必问
  • 架构与模式

    • Java极简设计模式
    • 实战高并发设计模式
  • Java核心技术

    • Java8新特性
    • IOC核心技术
    • JVM调优技术
  • 容器化核心技术

    • Dockek核心技术
  • 分布式存储

    • Mycat核心技术
  • 数据库核心技术

    • MySQL基础篇
  • 服务器核心技术

    • Nginx核心技术
  • 渗透核心技术

    • 渗透实战技术
  • 底层技术
  • 源码分析
  • 基础案例
  • 实战案例
  • 面试
  • 系统架构
  • Spring6核心技术
  • 分布式事务

    • 分布式事务系列视频
  • SpringBoot
  • SpringCloudAlibaba
  • 🔥AI大模型项目

    • 一站式AI智能平台
    • AI智能客服系统
    • AI智能问答系统
    • 实战AI大模型
  • 中间件项目

    • 手写高性能Redis组件
    • 手写高性能脱敏组件
    • 手写线程池项目
    • 手写高性能SQL引擎
    • 手写高性能Polaris网关
    • 手写高性能RPC项目
  • 高并发项目

    • 分布式IM即时通讯系统(新)
    • 分布式Seckill秒杀系统
    • 实战高并发设计模式
  • 微服务项目

    • 简易电商脚手架项目
  • 手撕源码

    • 手撕Spring6源码
🌍知识星球
  • 总览

    • 《书籍汇总》
  • 出版图书

    • 《深入理解高并发编程:核心原理与案例实战》
    • 《深入理解高并发编程:JDK核心技术》
    • 《深入高平行開發:深度原理&專案實戰》
    • 《深入理解分布式事务:原理与实战》
    • 《MySQL技术大全:开发、优化与运维实战》
    • 《海量数据处理与大数据技术实战》
  • 电子书籍

    • 《实战高并发设计模式》
    • 《深入理解高并发编程(第2版)》
    • 《深入理解高并发编程(第1版)》
    • 《从零开始手写RPC框架(基础篇)》
    • 《SpringCloud Alibaba实战》
    • 《冰河的渗透实战笔记》
    • 《MySQL核心知识手册》
    • 《Spring IOC核心技术》
  • 关于自己
  • 关于学习
  • 关于职场
B站
Github
导读
♻学习路线
  • 面试必问系列

    • 面试必问
  • 架构与模式

    • Java极简设计模式
    • 实战高并发设计模式
  • Java核心技术

    • Java8新特性
    • IOC核心技术
    • JVM调优技术
  • 容器化核心技术

    • Dockek核心技术
  • 分布式存储

    • Mycat核心技术
  • 数据库核心技术

    • MySQL基础篇
  • 服务器核心技术

    • Nginx核心技术
  • 渗透核心技术

    • 渗透实战技术
  • 底层技术
  • 源码分析
  • 基础案例
  • 实战案例
  • 面试
  • 系统架构
  • Spring6核心技术
  • 分布式事务

    • 分布式事务系列视频
  • SpringBoot
  • SpringCloudAlibaba
  • 🔥AI大模型项目

    • 一站式AI智能平台
    • AI智能客服系统
    • AI智能问答系统
    • 实战AI大模型
  • 中间件项目

    • 手写高性能Redis组件
    • 手写高性能脱敏组件
    • 手写线程池项目
    • 手写高性能SQL引擎
    • 手写高性能Polaris网关
    • 手写高性能RPC项目
  • 高并发项目

    • 分布式IM即时通讯系统(新)
    • 分布式Seckill秒杀系统
    • 实战高并发设计模式
  • 微服务项目

    • 简易电商脚手架项目
  • 手撕源码

    • 手撕Spring6源码
🌍知识星球
  • 总览

    • 《书籍汇总》
  • 出版图书

    • 《深入理解高并发编程:核心原理与案例实战》
    • 《深入理解高并发编程:JDK核心技术》
    • 《深入高平行開發:深度原理&專案實戰》
    • 《深入理解分布式事务:原理与实战》
    • 《MySQL技术大全:开发、优化与运维实战》
    • 《海量数据处理与大数据技术实战》
  • 电子书籍

    • 《实战高并发设计模式》
    • 《深入理解高并发编程(第2版)》
    • 《深入理解高并发编程(第1版)》
    • 《从零开始手写RPC框架(基础篇)》
    • 《SpringCloud Alibaba实战》
    • 《冰河的渗透实战笔记》
    • 《MySQL核心知识手册》
    • 《Spring IOC核心技术》
  • 关于自己
  • 关于学习
  • 关于职场
B站
Github
  • 开篇:专栏介绍

    • 开篇:我要带你从零开始手搓一个大厂必备的高性能Redis组件
  • 第01部分:需求设计

    • 第01节:为何要学习高性能Redis组件
    • 第02节:高性能Redis组件的目标与挑战
    • 第03节:高性能Redis组件需求与功能梳理
  • 第02部分:总体架构设计

    • 第01节:高性能Redis组件总体方案目标
  • 第03部分:落地实现

    • 第01节:高性能Redis组件基础功能设计与实现
    • 第02节:高性能Redis组件分布式锁设计与实现
    • 第03节:高性能Redis组件防缓存击穿、穿透和雪崩的核心设计与实现
  • 第04部分:测试验证

    • 第01节:高性能Redis组件单元测试场景验证
    • 第02节:高性能Redis组件基准性能测试
  • 专栏总结

    • 总结:高性能Redis组件整体专栏总结

《高性能Redis组件》落地实现-第03节:高性能Redis组件防缓存击穿、穿透和雪崩的核心设计与实现

作者:冰河
星球:http://m6z.cn/6aeFbs
博客:https://binghe.site
文章汇总:https://binghe.site/md/all/all.html
源码获取地址:https://t.zsxq.com/0dhvFs5oR

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★☆☆☆
  • 本章重点:对高性能Redis组件防缓存击穿、穿透和雪崩问题的功能进行设计和实现,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。

大家好,我是冰河~~

高性能Redis组件的亮点不仅仅在于其性能非常高,更多的是其在设计和实现上彻底解决了缓存击穿、穿透和雪崩问题。

一、前言

经历过高并发、大流量生产场景的小伙伴都知道,缓存作为承接高并发、大流量场景下,读取数据的一种核心技术手段,被广泛应用于各大核心系统中。但是缓存的设计并不是想象中的那么简单,稍有不慎,就会引起缓存击穿、穿透,甚至雪崩的问题。

如何设计和实现一个通用的高性能缓存组件,对使用方屏蔽处理缓存击穿、穿透和雪崩问题的实现细节,业务只需要调用组件对外暴露的简单接口,即可在保证性能的同时,又能彻底解决缓存击穿、穿透和雪崩问题。所以,在此背景下,高性能Redis组件诞生了。

二、本节诉求

对高性能Redis组件防缓存击穿、穿透和雪崩问题的功能进行设计和实现,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。

三、核心类设计

注意:本节只给大家展示高性能Redis组件防缓存击穿、穿透和雪崩的的核心类实现关系,其他代码的实现细节,大家可以自行到本节对应的源码分支进行查看,这里不再赘述。

高性能Redis组件分布式锁的核心类设计如图3-1所示。


可以看到,高性能Redis组件中,最核心的实现就是DistributeCacheService接口和RedisDistributeCacheService实现类。

  • DistributeCacheService接口:定义了各种缓存操作方法,并封装了获取Key、Value以及结果数据的默认方法。
  • RedisDistributeCacheService类:组件最核心的实现,实现了DistributeCacheService接口,并在方法的实现中,彻底解决了缓存击穿、穿透和雪崩问题。

四、编码实现

本节只给大家展示高性能Redis组件解的核心类编码实现,其他代码的实现细节,大家可以自行到本节对应的源码分支进行查看,这里不再赘述。

(1)实现DistributeCacheService接口

定义了各种缓存操作方法,并封装了获取Key、Value以及结果数据的默认方法。

源码详见:io.binghe.redis.plugin.cache.DistributeCacheService。

public interface DistributeCacheService {

    /**
     * 永久缓存
     * @param key 缓存key
     * @param value 缓存value
     */
    void set(String key, Object value);

    /**
     * 将数据缓存一段时间
     * @param key 缓存key
     * @param value 缓存value
     * @param timeout 物理缓存的时长
     * @param unit 物理时间单位
     */
    void set(String key, Object value, Long timeout, TimeUnit unit);

    /**
     * 设置缓存过期
     * @param key 缓存key
     * @param timeout 过期时长
     * @param unit 时间单位
     * @return 设置过期时间是否成功
     */
    Boolean expire(String key, final long timeout, final TimeUnit unit);

    /**
     * 保存缓存时设置逻辑过期时间
     * @param key 缓存key
     * @param value 缓存value
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑时间单位
     */
    void setWithLogicalExpire(String key, Object value, Long timeout, TimeUnit unit);

    /**
     * 获取缓存中的数据
     * @param key 缓存key
     * @return 缓存value
     */
    String get(String key);

    /**
     * 获取缓存数据
     * @param key 缓存的key
     * @param targetClass 目标对象Class
     * @param <T> 泛型
     * @return 返回的数据
     */
    <T> T getObject(String key, Class<T> targetClass);

    /**
     * 根据key列表批量获取value
     * @param keys key列表
     * @return value集合
     */
    List<String> multiGet(Collection<String> keys);

    /**
     * 根据正则表达式获取所有的key集合
     * @param pattern 正则表达式
     * @return key的集合
     */
    Set<String> keys(String pattern);

    /**
     * 删除指定的key
     * @param key key
     * @return 删除是否成功
     */
    Boolean delete(String key);
    /**
     * 带参数查询对象和简单类型数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存的业务标识,
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     * @param <ID> 查询数据库参数泛型,也是参数泛型类型
     */
    <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询对象和简单类型数据,防止缓存穿透
     * @param keyPrefix key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithPassThroughWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询集合数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存的业务标识,
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     * @param <ID> 查询数据库参数泛型,也是参数泛型类型
     */
    <R,ID> List<R> queryWithPassThroughList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询集合数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithPassThroughListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 带参数查询数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑过期时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithLogicalExpireWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询集合数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑过期时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> List<R> queryWithLogicalExpireList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询集合数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithLogicalExpireListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> R queryWithMutex(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithMutexWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> List<R> queryWithMutexList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithMutexListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 将对象类型的json字符串转换成泛型类型
     * @param obj 未知类型对象
     * @param type 泛型Class类型
     * @return 泛型对象
     * @param <R> 泛型
     */
    default <R> R getResult(Object obj, Class<R> type){
        if (obj == null){
            return null;
        }
        //简单类型
        if (TypeConversion.isSimpleType(obj)){
            return Convert.convert(type, obj);
        }
        return JSONUtil.toBean(JSONUtil.toJsonStr(obj), type);
    }

    /**
     * 将对象类型的json字符串转换成泛型类型的List集合
     * @param str json字符串
     * @param type 泛型Class类型
     * @return 泛型List集合
     * @param <R> 泛型
     */
    default <R> List<R> getResultList(String str, Class<R> type){
        if (StrUtil.isEmpty(str)){
            return null;
        }
        return JSONUtil.toList(JSONUtil.parseArray(str), type);
    }

    /**
     * 获取简单的key
     * @param key key
     * @return 返回key
     */
    default String getKey(String key){
        return getKey(key, null);
    }

    /**
     * 不确定参数类型的情况下,使用MD5计算参数的拼接到Redis中的唯一Key
     * @param keyPrefix 缓存key的前缀
     * @param id 泛型参数
     * @return 拼接好的缓存key
     * @param <ID> 参数泛型类型
     */
    default <ID> String getKey(String keyPrefix, ID id){
        if (id == null){
            return keyPrefix;
        }
        String key = "";
        //简单数据类型与简单字符串
        if (TypeConversion.isSimpleType(id)){
            key = StrUtil.toString(id);
        }else {
            key = MD5.create().digestHex(JSONUtil.toJsonStr(id));
        }
        if (StrUtil.isEmpty(key)){
            key = "";
        }
        return keyPrefix.concat(key);
    }

    /**
     * 获取要保存到缓存中的value字符串,可能是简单类型,也可能是对象类型,也可能是集合数组等
     * @param value 要保存的value值
     * @return 处理好的字符串
     */
    default String getValue(Object value){
        return TypeConversion.isSimpleType(value) ? String.valueOf(value) : JSONUtil.toJsonStr(value);
    }
}

(2)实现RedisDistributeCacheService类

RedisDistributeCacheService类是组件最核心的实现,实现了DistributeCacheService接口,并在方法的实现中,彻底解决了缓存击穿、穿透和雪崩问题。

源码详见:io.binghe.redis.plugin.cache.redis.RedisDistributeCacheService。

查看完整文章

加入冰河技术知识星球,解锁完整技术文章、小册、视频与完整代码

在 GitHub 上编辑此页
上次更新: 2026/4/29 16:18
Contributors: binghe001
Prev
第02节:高性能Redis组件分布式锁设计与实现
阅读全文
×

扫码或搜索:冰河技术
发送:290992
即可立即永久解锁本站全部文章

星球会员
跳转链接