江苏泰州网站建设,哈尔滨市香坊区建设局网站,wdcp上传网站,辽宁建设厅的证到底在哪个网站查redis的优点 读写性能优异。十万/s的量级#xff1b; 支持数据持久化。AOF,RDB 支持丰富的数据类型#xff1b; 支持集群#xff0c;可以实现主从复制#xff0c;哨兵机制迁移#xff0c;扩容等
缺点#xff1a; 因为是基于内存的#xff0c;所以虽然redis本身有key过期…redis的优点 读写性能优异。十万/s的量级 支持数据持久化。AOF,RDB 支持丰富的数据类型 支持集群可以实现主从复制哨兵机制迁移扩容等
缺点 因为是基于内存的所以虽然redis本身有key过期策略但是还是需要提前预估和节约内存因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。 主从同步时可能会比较慢。在线扩容比较麻烦 redis可能会有一些操作使它变慢
redis应用场景 高性能 计数器对于计数器这种频繁读写的很适合用快速的redis用string类型 缓存各种各样的缓存这是它最重要的应用场景了。数据库的缓存减轻数据库压力会话缓存保存session信息string类型全页缓存让你最快速度加载旧页面
单线程 分布式锁。可以使用 Redis 自带的 SETNX 命令实现分布式锁除此之外还可以使用官方提供的 RedLock 分布式锁实现。 SETNX 命令不存在才插入。一般而言还会对分布式锁加上过期时间。 SET lock_key unique_value NX PX 10000 PX 10000 表示设置 lock_key 的过期时间为 10s这是为了避免客户端发生异常而无法释放锁。 而解锁的过程就是将 lock_key 键删除但不能乱删要保证执行操作的客户端就是加锁的客户端。所以解锁的时候我们要先判断锁的 unique_value 是否为加锁客户端是的话才将 lock_key 键删除。 SETNX 命令的缺点是如果节点由于某些原因发生了主从切换但是这个加锁的key还没有同步到slave节点。那么就会出现锁丢失的情况。正因为如此Redis作者antirez基于分布式环境下提出了一种更高级的分布式锁的实现方式**Redlock**它的主要思想是设置**N个完全独立的主节点**依次尝试从N个Master实例使用相同的key和随机值获取锁当且仅当从大多数的Redis节点都取到锁并且使用的时间小于锁失效时间时锁才算获取成功。获取锁失败在所有Redis实例上进行解锁。我们的业务一般只需要一个Redis Cluster或者一个Sentinel但是这两者都不能承载RedLock的落地。如果你想要使用RedLock方案还需要专门搭建一套环境。所以如果不是对分布式锁可靠性有极高的要求比如金融场景不太建议使用RedLock方案丰富的数据类型 bitmap实现二值信息的存储HyperLogLog实现很小的内存统计大量数据UV,GEO经纬度信息Set 可以实现交集、并集等操作从而实现共同好友等功能。ZSet 可以实现有序性操作从而实现排行榜等功能。
redis为什么性能优异呢
1、首先因为是基于内存的数据库读取数据肯定比在硬盘快 2、数据结构设计的好。主要是基于哈希表的而且有rehash来避免哈希冲突大部分操作都是线性复杂度。当然一些getall,交并集不是线性的。这一点后面会具体说。 3、采用单线程加IO阻塞的网络模型。单线程避免了不必要的上下文切换和竞态消耗不需要加锁了。注意这里的单线程指的是读写一些辅助比如持久化是需要另外开一个线程的IO复用大大提高了效率。
下面说一下redis的基本数据类型和数据结构。 整体来看有一个全局哈希表通过这个表就可以找到对应的键值对有渐进rehash来避免哈希冲突。然后其中的值的类型很多也是基于哈希表的。因此导致大部分操作都是O(1)复杂度的。
string类型 底层是SDS简单字符串二进制方式保存有长度字段拼接时会检查防止溢出 有int,emdstr,raw三种编码方式。int是保存整形数据的字符串对象的ptr会将void*转换成 long emdstr保存短的字符串这样字符串对象和SDS分配一块连续的内存 raw保存长字符串字符串对象后ptr指向SDS。 emdstr不能更改要更改实际上要转换成raw类型的
List 类型的底层数据结构是由双向链表或压缩列表。 压缩列表实际上是数组形式只不过表头有列表长度尾部偏移量项数表尾有结束标志查询第一个最后一个元素比较快查中间的慢
list主要的应用有消息队列。list天然满足消息的顺序性BRPOP可以阻塞式读取防止空队列还在读。 重复消息处理可以实现全局ID然后处理过的ID保存起来List 类型提供了 BRPOPLPUSH 命令这个命令的作用是让消费者程序从一个 List 中读取消息同时Redis 会把这个消息再插入到另一个 List可以叫作备份 List留存。实现可靠性。 List缺点就是一条信息只能一个消费者读取。后来版本的有STREAM类型实现消费组读取。 不过消息队列有更好的组件kafka,rabitMQ等
Hash 是一个键值对key - value集合其中 value 的形式如 value[{field1value1}…{fieldNvalueN}]。Hash 特别适合用于存储对象比如购物车。 Hash 类型的底层数据结构是由压缩列表或哈希表实现的
Set 类型是一个无序并唯一的键值集合它的存储顺序不会按照插入的先后顺序进行存储。所以 Set 类型除了支持集合内的增删改查同时还支持多个集合取交集、并集、差集。Set 类型的底层数据结构是由哈希表或整数集合实现的 主要用于点赞统计共同关注数量抽奖活动。集合操作最好给从库或者客户端进行因为复杂度比较高。
Zset 类型相比于 Set 类型多了一个排序属性 score分值对于有序集合 ZSet 来说每个存储元素相当于有两个值组成的一个是有序结合的元素值一个是排序值。 Zset 类型的底层数据结构是由压缩列表或跳表实现的 有序集合比较典型的使用场景就是排行榜 跳表在链表的基础上增加了多级索引通过索引位置的几个跳转实现数据的快速定位。可以看到这个查找过程就是在多级索引上跳来跳去最后定位到元素。这也正好符合“跳”表的叫法。当数据量很大时跳表的查找复杂度就是 O(logN)。其实是空间换时间的做法而且链表必须是有序的
bitmap,hyperloglog,GEO等
问题整数数组和压缩列表在查找时间复杂度方面并没有很大的优势那为什么 Redis 还会把它们作为底层数据结构呢 **内存利用率数组和压缩列表都是非常紧凑的数据结构**它比链表占用的内存要更少。Redis是内存数据库大量数据存到内存中此时需要做尽可能的优化提高内存的利用率。 数组对CPU高速缓存支持更友好所以Redis在设计时集合数据元素较少情况下默认采用内存紧凑排列的方式存储同时利用CPU高速缓存不会降低访问速度。当数据元素超过设定阈值后避免查询时间复杂度太高转为哈希和跳表数据结构存储保证查询效率。
可以总结数据结构设计的精巧了首先整体上有全局哈希表快速定位键值对的位置。然后值有很多集合类型很多也是基于哈希表的。比如sethash。跳表也可以实现logn的访问。 同时为了节省内存有压缩列表和整数集合的形式并且数组对cache友好所以数据元素少时可以用数组形式不及能节省内存并且cache友好不会降低查询速度。复杂度都是在大量数据才能体现的
redis为什么用单线程 注意一点Redis是单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的这也是Redis对外提供键值存储服务的主要流程。但Redis的其他功能比如持久化、异步删除、集群数据同步等其实是由额外的线程执行的。 主要原因是因为CPU不是瓶颈所在因为是基于内存操作的而且数据结构设计合理复杂度很低的。因此IO复用单线程比多线程更适合。创建切换线程是需要时间的如果很简单一个熟练工自己做就可以分发给很多人做需要时间可能分发的时间代价比自己处理这一个连接请求还大。如果处理过程复杂一点代价比创建切换线程时间大那么可以多线程。 体现了基准测试测量才能提高。要看看分发时间和处理时间比较。以及和连接时间比较
2、而且多线程不可避免会有数据竞态消耗存在加锁的消耗以及死锁消耗等等问题而且对于上层编码来说多线程编程加锁更复杂了。 3、从内存看创建线程需要内存的10M左右redis很有可能有很多并发连接因此内存消耗也大并且redis本来内存资源就比较珍贵。 瓶颈可能是内存大小或者网络带宽。提高性能不如增加网络带宽或者内存。
为什么redis4.0之后又引入了多线程 这主要是为了充分利用多核CPU的能力主要用于特别大的高并发的场景并发量一大CPU可能就成为瓶颈了因为处理需要排队排队时延可能比较长。主线程用来接收客户端的连接然后分配给工作线程多个CPU同时处理并返回结果。
持久化机制 通过AOF日志和RDB快照技术。 AOF只记录写命令操作不记录读命令操作。重启的时候执行一下AOF中的命令。就相当于恢复数据了。 这里涉及到两个问题。一个是写回策略一个是AOF重写。 AOF写操作执行成功但是写AOF失败没来得及写回硬盘就宕机了数据丢失 AOF写操作会给下一个命令阻塞因为是在一个进程执行的。 AOF具体来说:先写到server.aof_buf 用户态缓冲区、写到AOF文件拷贝到了内核缓冲区 page cache、写入硬盘 1 Redis 执行完写操作命令后会将命令追加到 server.aof_buf 缓冲区 2 然后通过 write() 系统调用将 aof_buf 缓冲区的数据写入到 AOF 文件此时数据并没有写入到硬盘而是拷贝到了内核缓冲区 page cache等待内核将数据写入硬盘 3 具体内核缓冲区的数据什么时候写入到硬盘由内核决定。Redis 提供了 3 种写回硬盘的策略控制的就是上面说的第三步的过程。 always:最大程度减少数据丢失但是每次都要写回性能影响很大。写完就调用fsyc()函数 No 策略的话是交由操作系统来决定何时将 AOF 日志内容写回硬盘相比于 Always 策略性能较好但是操作系统写回硬盘的时机是不可预知的如果 AOF 日志内容没有写回硬盘一旦服务器宕机就会丢失不定数量的数据。不调用fsyc() Everysec 策略的话是折中的一种方式。创建一个异步任务来实现fsyc()
Redis 为了避免 AOF 文件越写越大提供了 AOF 重写机制涉及到子进程、重写缓冲区 重写简单来说就是多条命令合并成一条命令从数据库读最新的值把AOF中涉及该项的写删除写到新的AOF文件再覆盖原文件。覆盖原因是因为怕重写失败造成污染 由于重写需要读取所有缓存的键值对数据所以一般不放在主进程中而是由后台子进程 bgrewriteaof 来完成的这么做可以达到两个好处子进程进行 AOF 重写期间主进程可以继续处理命令请求从而避免阻塞主进程为什么不用线程因为共享内存需要加锁保证数据安全降低性能。 另外还有写时复制的优化技术子进程只复制父进程的task_struct和页表虚拟地址空间不复制物理内存子进程修改再重新映射就可以。节约物理内存节约fork的时间。 还有一个问题就是子进程在进行 AOF 重写期间服务器进程还需要继续处理命令请求而新的命令可能会对现有的数据库状态进行修改从而使得服务器当前的数据库状态和重写后的 AOF 文件所保存的数据库状态不一致 Redis 服务器设置了一个 AOF 重写缓冲区这个缓冲区在服务器创建子进程之后开始使用当 Redis 服务器执行完一个写命令之后它会同时将这个写命令发送给 AOF 缓冲区和 AOF 重写缓冲区。重写完成把AOF 重写缓冲区的数据添加到aof中。 AOF三部曲、写回策略、AOF重写以及子进程、写时复制、AOF重写缓冲区保证数据一致
RDB 快照就是记录某一个瞬间的内存数据记录的是实际数据。因此在 Redis 恢复数据时 RDB 恢复数据的效率会比 AOF 高些因为直接将 RDB 文件读入内存就可以不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。 Redis 提供了两个命令来生成 RDB 文件分别是 save 和 bgsave他们的区别就在于是否在「主线程」里执行 执行了 save 命令就会在主线程生成 RDB 文件由于和执行操作命令在同一个线程所以如果写入 RDB 文件的时间太长会阻塞主线程执行了 bgsave 命令会创建一个子进程来生成 RDB 文件这样可以避免主线程的阻塞 RDB 文件的加载工作是在服务器启动时自动执行的Redis 并没有提供专门用于加载 RDB 文件的命令。 这就是 RDB 快照的缺点在服务器发生故障时丢失的数据会比 AOF 持久化的方式更多因为 RDB 快照是全量快照的方式因此执行的频率不能太频繁否则会影响 Redis 性能而 AOF 日志可以以秒级的方式记录操作命令所以丢失的数据就相对更少。
比较RDB因为是实际的数据恢复起来更快而由于是全量的数据所以不可能频繁使用一般几十分钟一天所以如果数据丢失的话也会丢失更多而AOF可以设置写回策略所以丢失地少但是AOF性能差一点因为写AOF会阻塞下一个命令RDB只是创建子进程。 所以有混合持久化。新的AOF文件前半段是RDB格式的全量数据AOF缓冲区的数据后半段是AOF格式的增量数据重写缓冲区的数据
一些大key对于AOF写回磁盘会阻塞下一个命令AOF重写fork子进程复制页表也会阻塞、写时复制拷贝物理内存也会阻塞。网络流量也大阻塞。
过期删除和内存淘汰策略 这两个都是为了内存资源有限服务的。 expire key ttl key persist key 定时删除一到过期时间就删除对内存最好但是性能较差 惰性删除不主动删除过期键每次从数据库访问 key 时都检测 key 是否过期如果过期则删除该 key。 定期删除每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查并删除其中的过期key。 所以 Redis 选择「惰性删除定期删除」这两种策略配和使用以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。
内存淘汰主要是分为在设置过期时间数据淘汰和所有数据淘汰。又分为最早过期随机lru,lfu。 4.0之后用lfu,因为lru有问题。 需要用链表管理所有的缓存数据这会带来额外的空间开销当有数据被访问时需要在链表上把该数据移动到头端如果有大量数据被访问就会带来很多链表移动操作会很耗时进而会降低 Redis 缓存性能。其实用hash双向链表可以实现不耗时 缓存污染问题比如应用一次读取了大量的数据而这些数据只会被读取这一次那么这些数据会留存在 Redis 缓存中很长一段时间造成缓存污染。这个问题在linux有活跃非活跃lru, mysql也是类型的思想 LFU 算法是根据数据访问次数来淘汰数据的它的核心思想是“如果数据过去被访问多次那么将来被访问的频率也更高”。可以解决缓存污染。
数据库和缓存的一致性怎么保证 主从节点一致性怎么保证
由于引入了redis缓存那么在数据更新时不仅要更新数据库而且要更新缓存这两个更新操作存在前后的问题 无论是「先更新数据库再更新缓存」还是「先更新缓存再更新数据库」这两个方案都存在并发问题当两个请求并发更新同一条数据的时候可能会出现缓存和数据库中的数据不一致的现象。
用旁路缓存策略解决 先更新数据库再删除缓存。 读的时候如果缓存有就直接读没有就加载到缓存。为了确保万无一失还给缓存数据加上了「过期时间」就算在这期间存在缓存数据不一致有过期时间来兜底这样也能达到最终一致。 如何保证「先更新数据库 再删除缓存」这两个操作能执行成功 **重试机制。**延时双删 如果应用删除缓存失败可以从消息队列中重新读取数据然后再次删除缓存这个就是重试机制。当然如果重试超过的一定次数还是没有成功我们就需要向业务层发送报错信息了。
订阅 MySQL binlog再操作缓存。 「先更新数据库再删缓存」的策略的第一步是更新数据库那么更新数据库成功就会产生一条变更日志记录在 binlog 里。 于是我们就可以通过订阅 binlog 日志拿到具体要操作的数据然后再执行缓存删除阿里巴巴开源的 Canal 中间件就是基于这个实现的。Canal 模拟 MySQL 主从复制的交互协议把自己伪装成一个 MySQL 的从节点向 MySQL 主节点发送 dump 请求MySQL 收到请求后就会开始推送 Binlog 给 CanalCanal 解析 Binlog 字节流之后转换为便于读取的结构化数据供下游程序订阅使用。
主从模式相关 持久化无法解决单点故障服务器宕机或者硬盘损坏。而集群需要解决数据一致性问题。 Redis 提供了主从复制模式来避免上述的问题。这个模式可以保证多台服务器的数据一致性且主从服务器之间采用的是「读写分离」的方式。主服务器可以进行读写操作当发生写操作时自动将写操作同步给从服务器而从服务器一般是只读并接受主服务器同步过来写操作命令然后执行这条命令。 主从同步机制比较复杂分成三个阶段。先执行 replicaof 命令确定主从 第一阶段建立连接协商同步。执行了 replicaof 命令后从服务器就会给主服务器发送 psync 命令表示要进行数据同步。psync 命令包含两个参数分别是主服务器的 runID 和复制进度 offset。第一次ID是offset是-1。然后主服务器收到 psync 命令后会用 FULLRESYNC 作为响应命令返回给对方。并且这个响应命令会带上两个参数主服务器的 runID 和主服务器目前的复制进度 offset。从服务器收到响应后会记录这两个值。 所以第一阶段的工作时为了全量复制做准备。
第二阶段:主服务器同步数据给从服务器。主服务器会执行 bgsave 命令来生成 RDB 文件然后把文件发送给从服务器。从服务器收到 RDB 文件后会先清空当前的数据然后载入 RDB 文件。 第三阶段主服务器发送新写操作命令给从服务器。完成 RDB 的载入后会回复一个确认消息给主服务器。
mysql也有主从复制主节点dump线程发送binlog从节点开启IO线程接收放到relay日志然后SQL线程执行
接着主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器从服务器执行来自主服务器 replication buffer 缓冲区包括主服务器生成RDB期间发送给从服务器期间从服务器接收期间里发来的命令这时主从服务器的数据就一致了。 主从服务器在完成第一次同步后双方之间就会维护一个 TCP 连接。后续主服务器可以通过这个连接继续将写操作命令传播给从服务器然后从服务器执行该命令使得与主服务器的数据库状态相同。
如何分摊主服务器同步时的压力 代理服务器从服务器可以有自己的从服务器 增量复制如果遇到网络断开增量复制就可以上场了不过这个还跟repl_backlog_size环形缓冲区记录了主服务器写的偏移和从服务器读的偏移。
主从节点数据不一致问题 主从同步的数据丢失不可避免统一持久化的数据丢失也不可避免性能和可靠互斥的 在主从节点命令传播阶段主节点收到新的写命令后会发送给从节点。但是主节点并不会等到从节点实际执行完命令后再把结果返回给客户端而是主节点自己在本地执行完命令后就会向客户端返回结果了。如果从节点还没有执行主节点同步过来的命令主从节点间的数据就不一致了。
如何避免其实没办法完全避免的。这种强一致性就要用到raft协议了。只能从应用层面来限制。比如保持网络良好开发一个监控 程序监控主从节点间的复制进度差很多的话就停止服务
哨兵机制 主节点挂了 从节点是无法自动升级为主节点的这个过程需要人工处理在此期间 Redis 无法对外提供写操作。 此时Redis 哨兵机制就登场了哨兵在发现主节点出现故障时由哨兵自动完成故障发现和故障转移并通知给应用方从而实现高可用性。 它会监测主节点是否存活如果发现主节点挂了它就会选举一个从节点切换为主节点并且把新主节点的相关信息通知给从节点和客户端。监控选主通知
监控哨兵会每隔 1 秒给所有主从节点发送 PING 命令当主从节点收到 PING 命令后会发送一个响应命令给哨兵这样就可以判断它们是否在正常运行。如果主节点或者从节点没有在规定的时间内响应哨兵的 PING 命令哨兵就会将它们标记为「主观下线」。 但是是因为有可能「主节点」其实并没有故障可能只是因为主节点的系统压力比较大或者网络发送了拥塞导致主节点没有在规定时间内响应哨兵的 PING 命令。为了减少误判的情况哨兵在部署的时候不会只部署一个节点而是用多个节点部署成哨兵集群最少需要三台机器来部署哨兵集群通过多个哨兵节点一起判断。其他哨兵收到这个命令后就会根据自身和主节点的网络状况做出赞成投票或者拒绝投票的响应。哨兵判断完主节点客观下线后哨兵就要开始在多个「从节点」中选出一个从节点来做新主节点。 选主选出leader哨兵实现选主 某个哨兵判定主节点客观下线后该哨兵就会发起投票告诉其他哨兵它想成为 leader想成为 leader 的哨兵节点要满足两个条件第一拿到半数以上的赞成票第二拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。 转移过程和k8s调度选服务器也类似的 第一选出新的主节点。首先要排除离线的网络不好的节点再根据优先级、复制进度、ID 号选出最适合的。 然后所有从节点的主节点信息修改通过发布订阅模式通知客户端变化旧的主节点上线后让他成为新的从节点
切片集群相关 从3.0开始官方提供了一个名为Redis Cluster的方案用于实现切片集群。一个redis实例数据太多会造成很多问题哈希冲突AOF持久化fork耗时大等 具体来说Redis Cluster方案采用哈希槽Hash Slot接下来我会直接称之为Slot来处理数据和实例之间的映射关系。 哈希槽和实例的映射关系redis会自动分配平均分配的原则。 Redis实例会把自己的哈希槽信息发给和它相连接的其它实例来完成哈希槽分配信息的扩散。当实例之间相互连接后每个实例就有所有哈希槽的映射关系了。客户端收到哈希槽信息后会把哈希槽信息缓存在本地。当客户端请求键值对时会先计算键所对应的哈希槽然后就可以给相应的实例发送请求了。
还要解决的一个问题就是如何集群变化了比如实例加减为了负载均衡哈希槽要重新分配。这时候客户端再请求就找不到数据了。 这时候。实例会给客户端发送MOVED指令带着最新的哈希槽在哪个实例上的信息重定向后就可以找到了。 如果实例正在迁移。会发ASKING,会让数据迁移完成再读取数据。
redis变慢如何排查 redis有一些阻塞点需要了解 1、客户端阻塞点全量查询操作 HGETALL、LRANGESMEMBERS以及集合的聚合统计操作例如求交、并和差集。这些操作可以作为 Redis 的第一个阻塞点集合全量查询和聚合操作。 删除操作也是潜在的阻塞点。应用程序释放内存时操作系统需要把释放掉的内存块插入一个空闲内存块的链表以便后续进行管理和再分配 那么什么时候会释放大量内存呢其实就是在删除大量键值对数据的时候最典型的就是删除包含了大量元素的集合也称为 bigkey 删除
2、和磁盘交互时的阻塞点持久化 AOF日志同步写回时会阻塞下一步的命令。同时如果大量数据fork子进程页表的时候也会阻塞。 3、主从节点交互时的阻塞点。从库同步主库信息时先要删除自己的全部数据删除需要时间再次RDB加载到内存运行也要时间RDB文件越大越慢。 4、CPU结构 使用多核CPU时可以给Redis实例绑定物理核使用NUMA架构时注意把Redis实例和网络中断处理程序运行在同一个CPU Socket上。 如何排查 首先看看是不是网络带宽、以及基线性能和运行时延迟测试。 是否用了慢查询命令slowlog get 10这个命令可以看 是否存在bigkey?scan操作减缓延迟 AOF配置级别是什么业务层面是否的确需要这一可靠性级别 Redis实例的内存使用是否过大发生swap了吗如果是的话可以使用切片集群或者增加内存 是否运行了Redis主从集群如果是的话把主库实例的数据量大小控制在2~4GB以免主从复制时从库因加载大的RDB文件而阻塞。 是否使用了多核CPU或NUMA架构的机器运行Redis实例使用多核CPU时可以给Redis实例绑定物理核使用NUMA架构时注意把Redis实例和网络中断处理程序运行在同一个CPU Socket上。
首先查后端业务代码。是否有长时间循环等待临界资源等。 先基线测试排除网络异常内存是不是不够慢日志查看是否有bigkeyAOF持久化策略、主从复制RDB文件大小限制,CPU架构绑定物理核
缓存击穿穿透雪崩 缓存穿透缓存和数据库都没有。可能是业务误操作或者黑客恶意攻击。 解决1.非法输入限制。API处就要检查字段是否合法 2、缓存空值或者默认值设置一个过期时间这样一段时间内就不会访问数据库了3 使用布隆过滤器快速判断数据是否存在避免通过查询数据库来判断数据是否存在。最新的布谷鸟过滤器可以解决布隆过滤器删除麻烦 缓存雪崩 当大量缓存数据在同一时间过期失效或者 Redis 故障宕机时如果此时有大量的用户请求都无法在 Redis 中处理于是全部请求都直接访问数据库从而导致数据库的压力骤增。 解决办法 1、均匀设置过期时间2、互斥锁保证同一时间内只有一个请求来构建缓存从数据库读取数据再将数据更新到 Redis 里雪崩发生后进行限流和服务熔断。 缓存击穿 我们的业务通常会有几个数据会被频繁地访问比如秒杀活动这类被频地访问的数据被称为热点数据。 如果缓存中的某个热点数据过期了此时大量的请求访问了该热点数据就无法从缓存中读取直接访问数据库数据库很容易就被高并发的请求冲垮这就是缓存击穿的问题。你可以认为缓存击穿是缓存雪崩的一个子集。 解决方案也是互斥锁或者不给热点数据设置过期时间后台线程来更新缓存。