Redis缓存穿透、雪崩、击穿全解析

📅 发布时间:2026/7/7 21:42:18 👁️ 浏览次数:
Redis缓存穿透、雪崩、击穿全解析
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在这样缓存永远不会生效这些请求都会打到数据库。常见的解决方案有两种1.缓存空对象null值 优点实现简单维护方便缺点额外的内存消耗、可能造成短期的不一致2.布隆过滤器 优点内存占用较少没有多余key缺点实现复杂、存在误判可能增强id的复杂度避免被猜测id规律做好数据的基础格式校验 加强用户权限校验 做好热点参数的限流缓存雪崩是指在同一时段大量的缓存key同时是小或者Redis服务宕机导致大量请求到达数据库带来巨大压力。解决方案给不同的Key的TTL添加随即值利用Redis集群提高服务的可用性给缓存业务添加降级限流策略给业务添加多级缓存缓存击穿也叫热点key问题就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了无数的请求访问会在瞬间给数据库带来巨大的冲击。常见的解决方案两种互斥锁 优点没有额外的内存消耗、保证一致性、实现简单缺点线程需要等待性能受影响、可能有死锁风险逻辑过期 优点线程无需等待性能较好缺点不保证一致性、有额外内存消耗、实现复杂Redis持久化RDB持久化Redis Database Backup fileRedis数据备份文件也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后从磁盘读取快照文件恢复数据。redis-cli SAVE # 同步生成 redis-cli BGSAVE # 异步生成生成方式通过SAVE阻塞主线程或BGSAVE后台异步命令触发也可在配置文件中设置自动保存规则如save 900 1表示900秒内至少1次修改时触发。文件内容二进制格式包含某个时间点的数据快照。优点文件紧凑恢复速度快适合灾难恢复。缺点可能丢失最后一次快照后的数据。bgsave开始时会fork复制页表主进程得到子进程子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。fork采用的是copy-on-write技术当主进程执行读操作时访问共享内存当主进程执行写操作时则会拷贝一份数据执行写操作AOF持久化Append Only File追加文件Redis处理的每一个写命令都会记录在AOF文件可以看做是命令日志文件。AOF默认是关闭的需要修改redis.conf配置文件来开启AOF#是否开启AOF功能默认是no appendonly yes #AOF文件的名称 appendfilename appendonly.aof因为是记录命令AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作名单只有最后一次写操作才有意义。通过执行bgrewriteaof命令可以让AOF文件执行重写功能用最少的命令达到相同效果。生成方式在配置中启用appendonly yesRedis会记录所有写操作命令可配置同步频率appendfsync always/everysec/no。文件内容文本格式记录逐条写命令。优点数据丢失风险低取决于同步频率可重写压缩BGREWRITEAOF。缺点文件体积较大恢复速度慢于RDB。恢复数据RDB恢复将.rdb文件放入Redis工作目录dir配置项指定重启Redis即可自动加载。AOF恢复确保AOF文件存在且配置正确Redis启动时会重新执行命令重建数据。RDB备份文件特点RDB通过生成数据快照实现备份文件格式为二进制压缩文件。优点文件体积小适合全量备份与灾难恢复。恢复速度快适合大数据量场景。对性能影响小通过子进程生成快照主进程继续处理请求。缺点数据可能丢失快照间隔期内宕机会导致未保存的数据丢失。频繁生成快照可能影响性能尤其数据量较大时。AOF备份文件特点AOF通过记录所有写操作命令实现备份文件为文本格式可重写为压缩格式。优点数据安全性高支持每秒同步appendfsync everysec或每次操作同步appendfsync always。可读性强文件内容为Redis命令便于人工审计或修复。支持重写机制BGREWRITEAOF压缩冗余命令减少文件体积。缺点文件体积较大长期运行可能积累大量操作记录。恢复速度较慢需逐条执行命令重建数据。对性能影响较大尤其在appendfsync always模式下。Redis五种数据类型StringString是Redis中最常见的数据存储类型其基本编码方式是RAW基于简单动态字符串SDS实现存储上限为512mb如果存储的SDS长度小于44字节则会采用EMBSTR编码此时object head与SDS是一段连续空间。申请内存时只需要调用一次内存分配函数效率更高。如果存储的字符串是整数值。并且大小在LONG_MAX范围内则会采用INT编码直接将数据保存在RedisObject的ptr指针位置刚好8字节不再需要SDS了。ListRedis的List类型可以从首、尾操作列表中的元素LinkedList普通链表可以从双端访问内存占用较高内存碎片较多ZipList压缩列表可以从双端访问内存占用低存储上限低QuickListLinkedListZipList可以从双端访问内存占用较低包含多个ZipList存储上限高。在3.2版本之前Redis采用ZipList和LinkedList来实现List当元素数量小于512并且元素大小小于64字节时采用ZipList编码超过则采用LinkedList编码在3.2版本之后Redis统一采用QuickList来实现ListSetSet时Redis中的集合不一定确保元素有序可以满足元素唯一、查询效率要求极高为了查询效率和唯一性set采用HT编码Dict。Dict中的Key用来存储元素value统称为null。当存储的所有数据都是整数并且元素数量不超过set-max-intset-entries时Set会采用IntSet编码以节省内存。ZSetZSet也就是SortedSet其中每一个元素都需要指定一个score值和member值可以根据score值排序后 member必须唯一 可以根据member查询分数因此zset底层数据结构必须满足键值存储、键必须唯一、可排序这几个需求SkipList可以排序并且可以同时存储score和ele值memberHTDict可以键值存储并且可以根据key找value当元素数量不多时HT和SkipList的优势不明显而且更耗内存。因此zset还会采用ZipList结构来节省内存不过需要同时满足两个条件1.元素数量小于zset_max_ziplist_entries默认值1282.每个元素都小于zset_max_ziplist_value字节默认值64ziplist本身没有排序功能而且没有键值对的概念因此需要有zset通过编码实现ZipList是连续内存因此score和element是紧挨在一起的两个entryelement在前score在后score越小越接近队首score越大越接近队尾按照score值升序排列HashHash结构与Redis中的Zset非常类似都是键值存储 都需求根据键获取值 键必须唯一区别如下zset的键是member值是scorehash的键和值都是任意值zset要根据score排序hash则无需排序因此Hash底层采用的编码与Zset也基本一致只需要把排序有关的SkipList去掉即可Hash结构默认采用ZipList编码用以节省内存。ZipList中相邻的两个entey分别保存field和value当数据量较大时Hash结构会转为HT编码也就是Dict触发条件有两个ZipList中的元素数量超过了hash-max-ziplist-entries(默认512)ZipList中的任意entry大小超过了hash-max-ziplist-value默认64字节