redis常见数据结构?
1.string 数据类型
string 是Redis的最基本的数据类型,一个key 对应一个 value。string 类型是二进制安全的,意思是 Redis 的 string 可以包含任何数据,比如图片或者序列化的对象,一个 redis 中字符串 value 最多可以是 512M。
2.hash 数据类型
hash 是一个键值对集合,是一个 string 类型的 key和 value 的映射表,key 还是key,但是value是一个键值对(key-value)。类比于 Java里面的 Map
3.list 数据类型
list 列表,它是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际上是个链表
4.set 数据类型
Redis 的 set 是 string 类型的无序集合。
5.zset 数据类型
zset(sorted set 有序集合),和上面的set 数据类型一样,也是 string 类型元素的集合,但是它是有序的。
redis在项目中的使用场景?
redis的key 的数据结构是如何选型的
redis的key的规范是如何设计的
具体业务是怎么样的
如何使用redis解决的业务
redis具体如何使用?
redis的数据存储是key-value格式的,例如,要存储一个名字为zls的用户,用redis来写的话,就是:set name zls 。这里name就是key,而zls就是该key对应的value。说得再简单点,key就相当于php里的变量名,而value就是该变量的值。而set 是redis的一个指令,用来设置key-value,相当于php里的赋值操作。
redis的事务机制的介绍?
Redis的事务本质是一组命令的集合,一个事务中的命令要么全部执行,要么都不执行
#开启事务
multi
添加命令
sadd user:1001:follow 1002
sadd user:1002:follow 1001
sadd user:1001:fans 1002
sadd user:1002:fans 1002
执行事务
exec
# 取消事务
discard
Redis事务是基于队列实现的,创建一个事务队列,然后将事务操作都放入队列中,最后依次执行。
事务处理机制
Redis对于命令执行错误处理,有两种解决方式:
- 语法错误(编译)
语法错误:执行命令的语法不正确
获取正确指令数据
get name
此时整个事务队列中,存在一条正确指令,两条语法错误指令, 当执行exec后,会直接返回错误,正确的命令也不会执行
- 执行错误(运行)
执行错误:命令在运行过程中出现错误
运行之前redis无法发现错误,但是在执行时出现了错误,因此只会错误的命令不执行, 而正确的命令仍然能够正常执行。
redis的持久化机制?
Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。
Redis 的持久化机制有两种,第一种是RDB快照,第二种是 AOF 日志。
RDB(Redis DataBase)是Redis默认存储方式。其基于快照思想,当符合一定条件(手动或自动触发)时,Redis会将这一刻的内存数据进行快照并保存在磁盘上,产生一个经过压缩的二进制文件,文件后缀名.rdb,因为RDB文件是保存在磁盘上的,因此即使Redis进程退出,甚至服务器宕机重启。只要RDB文件存在,就可以利用它来还原Redis数据。
RDB触发条件
在redis.conf文件中配置了一些默认触发机制。save "" # 不使用RDB存储 不能主从# 记忆save 3600 1 #表示1小时内至少1个键被更改则进行快照。save 300 100 #表示5分钟(300秒)内至少100个键被更改则进行快照。save 60 10000 #表示1分钟内至少10000个键被更改则进行快照。
在redis客户端执行save或bgsave命令,手动触发RDB快照。
#进入客户端
bin/redis-cli
#执行save命令(同步执行)
save
#执行bgsave命令(异步子线程执行)
bgsave
那么这两个命令都会触发快照的话,他们两个又有什么区别呢?
- save:同步处理,阻塞Redis服务进程,服务器不会处理任何命令,直到RDB文件保存完毕。
- bgsave:会fork一个和主线程一致的子线程负责操作RDB文件,不会阻塞Redis服务进程,操作RDB文件的同时仍然可以处理命令。
Redis默认使用的是 bgsave 来保存快照数据。
1)Redis服务进程判断,当前是否有子线程在执行save或bgsave。
2)如果有,则直接返回,不做任何处理。
3)如果没有,则以阻塞式创建子线程,在创建子线程期间,Redis不处理任何命令。
4)创建完子线程后,取消阻塞,Redis服务继续响应其他命令。
5)同时基于子线程操作RDB文件,将此刻数据保存到磁盘。
优点:
- 基于二进制文件完成数据备份,占用空间少,便于文件传输。
- 能够自定义规则,根据Redis繁忙状态进行数据备份。
缺点:
- 无法保证数据完整性,会丢失最后一次快照后的所有数据。
- bgsave执行每次执行都会阻塞Redis服务进程创建子线程,频繁执行影响系统吞吐率。
AOF(append only file)是Redis提供了另外一种持久化机制。与RDB记录数据不同,当开启AOF持久化后,Redis会将客户端发送的所有更改数据的命令,记录到磁盘中的AOF文件。 这样的话,当Redis重启后,通过读取AOF文件,按顺序获取到记录的数据修改命令,即可完成数据恢复。

AOF方式需要手动开启,修改redis.conf
# 是否开启AOF,默认为no
appendonly yes
#设置AOF文件名称
appendfilename appendonly.aof
当开启了AOF机制之后,Redis何时会向aof文件中记录内容呢?
对于AOF的触发方式有三种:always、everysec、no。 默认使用everysec。可以通过redis.conf中appendfsync属性进行配置。
那么这三种参数各自都代表什么意思呢? 为什么默认使用everysec呢?这里我们做一个预留,因为涉及到一些其他知识,后面再给大家详细介绍。
开启AOF后,重启Redis,进入Redis客户端并执行多条写命令,这些命令会被保存到appendonly.aof文件中。
通过文件查看,可以看到,在aof文件中,记录了对redis操作的所有写命令,读命令并不会记录。
AOF功能实现的整个执行过程可以分为三个部分:命令追加,文件写入,文件同
步.
命令
追加
REDIS
保存至缓冲
发送写命令
区文件末尾
AOF BUF
文件
写入AOF文件
写入
根据策略向磁盘同步
磁盘
AOF
文件
同步
1)客户端向Redis发送写命令。
2)Redis将接收到的写命令保存到缓冲文件aof_buf的末尾。 这个过程是命令追加。
3)redis将缓冲区文件内容写入到AOF文件,这个过程是文件写入。
4)redis根据策略将AOF文件保存到磁盘,这个过程是文件同步。
5)何时将AOF文件同步到磁盘的策略依据就是redis.conf文件中appendfsync属性值:always、everysec、no
●always:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,并将AOF文件同步到磁盘。该方式效率最低,安全性最高。
●everysec:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中。 并且每隔一秒会由子线程将AOF文件同步到磁盘。该方式兼备了效率与安全,即使出现宕机重启,也只会丢失不超过两秒的数据。
●no:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,但并不对AOF文件进行同步磁盘。 同步操作交由操作系统完成(每30秒一次),该方式最快,但最不安全。
AOF重写优化
AOF会将对Redis操作的所有写命令都记录下来,随着服务器的运行,AOF文件内保存的内容会越来越多。这样就会造成两个比较严重的问题:占用大量存储空间、数据还原花费的时间多。
触发配置
那么AOF文件达到多大时,会对其进行重写呢? 对于重写阈值的配置,可以通过修改redis.conf进行配置。
Java复制代码
1
当前aof文
#当前aof文件大小超过上一次aof文件大小的百分之多少时进行重写。如果之前没有重写过,以
启动时aof文件大小为准
auto-aof-rewrite-percentage 100
#限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
RDB和AOF持久化的区别?
- RDB默认开启,AOF需手动开启。
- RDB性能优于AOF。
- AOF安全性优于RDB。
- AOF优先级高于RDB。
- RDB存储某个时刻的数据快照,AOF存储写命令。
- RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF默认使用everysec,每秒保存一次,最多丢失两秒以内的数据。
redis高可用(集群策略)?
Redis的高可用策略从根本上来讲是为了保证数据的安全主从模式
主从模式中,Redis部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。从节点的数据来自主节点,实现原理就是主从复制机制
主从复制包括全量复制,增量复制两种。一般当slave第一次启动连接master,或者认为是第一次连接,就采用全量复制,全量复制流程如下:
- 1.slave发送sync命令到master。
- 2.master接收到SYNC命令后,执行bgsave命令,生成RDB全量文件。
- 3.master使用缓冲区,记录RDB快照生成期间的所有写命令。
- 4.master执行完bgsave后,向所有slave发送RDB快照文件。
- 5.slave收到RDB快照文件后,载入、解析收到的快照。
- 6.master使用缓冲区,记录RDB同步期间生成的所有写的命令。
- 7.master快照发送完毕后,开始向slave发送缓冲区中的写命令;
- 8.salve接受命令请求,并执行来自master缓冲区的写命令
redis2.8版本之后,已经使用psync来替代sync,因为sync命令非常消耗系统资源,psync的效率更高。
slave与master全量同步之后,master上的数据,如果再次发生更新,就会触发增量复制。
当master节点发生数据增减时,就会触发replicationFeedSalves()函数,接下来在 Master节点上调用的每一个命令会使用replicationFeedSlaves()来同步到Slave节点。执行此函数之前呢,master节点会判断用户执行的命令是否有数据更新,如果有数据更新的话,并且slave节点不为空,就会执行此函数。这个函数作用就是:把用户执行的命令发送到所有的slave节点,让slave节点执行。流程如下:
哨兵模式
主从模式中,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址。显然,多数业务场景都不能接受这种故障处理方式。Redis从2.8开始正式提供了Redis Sentinel(哨兵)架构来解决这个问题。
哨兵模式,由一个或多个Sentinel实例组成的Sentinel系统,它可以监视所有的Redis主节点和从节点,并在被监视的主节点进入下线状态时,自动将下线主服务器属下的某个从节点升级为新的主节点。但是呢,一个哨兵进程对Redis节点进行监控,就可能会出现问题(单点问题),因此,可以使用多个哨兵来进行监控Redis节点,并且各个哨兵之间还会进行监控。
Sentinel哨兵模式
简单来说,哨兵模式就三个作用:
- 发送命令,等待Redis服务器(包括主服务器和从服务器)返回监控其运行状态;
- 哨兵监测到主节点宕机,会自动将从节点切换成主节点,然后通过发布订阅模式通知其他的从节点,修改配置文件,让它们切换主机;
- 哨兵之间还会相互监控,从而达到高可用。
故障切换的过程是怎样的呢
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行 failover 过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行 failover 操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
哨兵的工作模式如下:
- 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他Sentinel实例发送一个 PING命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel标记为主观下线。
- 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
- 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线。
- 在一般情况下, 每个 Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
- 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
- 若没有足够数量的 Sentinel同意Master已经下线, Master的客观下线状态就会被移除;若Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
Cluster集群模式
哨兵模式基于主从模式,实现读写分离,它还可以自动切换,系统可用性更高。但是它每个节点存储的数据是一样的,浪费内存,并且不好在线扩容。因此,Cluster集群应运而生,它在Redis3.0加入的,实现了Redis的分布式存储。对数据进行分片,也就是说每台Redis节点上存储不同的内容,来解决在线扩容的问题。并且,它也提供复制和故障转移的功能。Cluster集群节点的通讯
一个Redis集群由多个节点组成,各个节点之间是怎么通信的呢?通过Gossip协议!
Redis Cluster集群通过Gossip协议进行通信,节点之前不断交换信息,交换的信息内容包括节点出现故障、新节点加入、主从节点变更信息、slot信息等等。常用的Gossip消息分为4种,分别是:ping、pong、meet、fail。
- meet消息:通知新节点加入。消息发送者通知接收者加入到当前集群,meet消息通信正常完成后,接收节点会加入到集群中并进行周期性的ping、pong消息交换。
- ping消息:集群内交换最频繁的消息,集群内每个节点每秒向多个其他节点发送ping消息,用于检测节点是否在线和交换彼此状态信息。
- pong消息:当接收到ping、meet消息时,作为响应消息回复给发送方确认消息正常通信。pong消息内部封装了自身状态数据。节点也可以向集群内广播自身的pong消息来通知整个集群对自身状态进行更新。
- fail消息:当节点判定集群内另一个节点下线时,会向集群内广播一个fail消息,其他节点接收到fail消息之后把对应节点更新为下线状态。
特别的,每个节点是通过集群总线(cluster bus) 与其他的节点进行通信的。通讯时,使用特殊的端口号,即对外服务端口号加10000。例如如果某个node的端口号是6379,那么它与其它nodes通信的端口号是 16379。nodes 之间的通信采用特殊的二进制协议。
Hash Slot插槽算法
既然是分布式存储,Cluster集群使用的分布式算法是一致性Hash嘛?并不是,而是Hash Slot插槽算法。
插槽算法把整个数据库被分为16384个slot(槽),每个进入Redis的键值对,根据key进行散列,分配到这16384插槽中的一个。使用的哈希映射也比较简单,用CRC16算法计算出一个16 位的值,再对16384取模。数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点都可以处理这16384个槽。
集群中的每个节点负责一部分的hash槽,比如当前集群有A、B、C个节点,每个节点上的哈希槽数 =16384/3,那么就有:
- 节点A负责0~5460号哈希槽
- 节点B负责5461~10922号哈希槽
-
Redis Cluster集群
Redis Cluster集群中,需要确保16384个槽对应的node都正常工作,如果某个node出现故障,它负责的slot也会失效,整个集群将不能工作。
因此为了保证高可用,Cluster集群引入了主从复制,一个主节点对应一个或者多个从节点。当其它主节点 ping 一个主节点 A 时,如果半数以上的主节点与 A 通信超时,那么认为主节点 A 宕机了。如果主节点宕机时,就会启用从节点。
在Redis的每一个节点上,都有两个玩意,一个是插槽(slot),它的取值范围是0~16383。另外一个是cluster,可以理解为一个集群管理的插件。当我们存取的key到达时,Redis 会根据CRC16算法得出一个16 bit的值,然后把结果对16384取模。酱紫每个key都会对应一个编号在 0~16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
虽然数据是分开存储在不同节点上的,但是对客户端来说,整个集群Cluster,被看做一个整体。客户端端连接任意一个node,看起来跟操作单实例的Redis一样。当客户端操作的key没有被分配到正确的node节点时,Redis会返回转向指令,最后指向正确的node,这就有点像浏览器页面的302 重定向跳转。
故障转移
Redis集群实现了高可用,当集群内节点出现故障时,通过故障转移,以保证集群正常对外提供服务。
redis集群通过ping/pong消息,实现故障发现。这个环境包括主观下线和客观下线。
主观下线: 某个节点认为另一个节点不可用,即下线状态,这个状态并不是最终的故障判定,只能代表一个节点的意见,可能存在误判情况。
主观下线
客观下线: 指标记一个节点真正的下线,集群内多个节点都认为该节点不可用,从而达成共识的结果。如果是持有槽的主节点故障,需要为该节点进行故障转移。 假如节点A标记节点B为主观下线,一段时间后,节点A通过消息把节点B的状态发到其它节点,当节点C接受到消息并解析出消息体时,如果发现节点B的pfail状态时,会触发客观下线流程;
- 当下线为主节点时,此时Redis Cluster集群为统计持有槽的主节点投票,看投票数是否达到一半,当下线报告统计数大于一半时,被标记为客观下线状态。
流程如下:
客观下线
故障恢复:故障发现后,如果下线节点的是主节点,则需要在它的从节点中选一个替换它,以保证集群的高可用。流程如下:
- 资格检查:检查从节点是否具备替换故障主节点的条件。
- 准备选举时间:资格检查通过后,更新触发故障选举时间。
- 发起选举:到了故障选举时间,进行选举。
选举投票:只有持有槽的主节点才有票,从节点收集到足够的选票(大于一半),触发替换主节点操作
redis key的过期淘汰策略?
1. 定时删除
原理:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作
- 优点:能够很及时的删除过期的Key,能够最大限度的节约内存
缺点:对CPU时间不友好,如果过期的Key比较多时,可能会占用相当一部分CPU时间,对服务器的响应时间和吞吐量造成影响
2. 惰性删除
原理:在取出键时才对键进行过期检查,如果发现过期了就会被删除
- 优点:对CPU友好,能够最大限度的节约CPU时间
-
3. 定期删除
原理:定期删除策略是定时删除策略和惰性删除策略的一个折中。定期删除策略每隔一段时间执行一次删除过期键的操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响
- 优点:对CPU时间和内存空间的一种权衡,可以根据实际使用情况来调整删除操作执行的时长和频率
- 缺点:确定删除操作执行的时长和频率很难。如果删除操作执行的太频繁,或者执行的时间太长,退化成定时删除策略;如果删除操作执行的太少,或者执行时间太短,退化成惰性删除策略
Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,服务器可以很好地在合理使用CPU时间和避免浪费内存空间之间取得平衡。Redis默认每隔100ms随机抽取一些设置了过期时间的key,检查是否过期,如果过期就删除。
redis 内存淘汰策略?
有一些已经过期的key,定期扫描一直都没有扫描到它,而且这些key也一直没有被使用。 那么它们就会一直在内存中存在。同时继续向Redis不断插入新数据,最终造成内存空间不足的问题。
对于这种问题的解决,就用到了内存淘汰策略
当客户端执行命令,添加数据时,Redis会检查内存空间大小,如超过最大内存,则触发内存淘汰策略
策略设置
**redis默认使用noeviction**,我们可以通过修改**redis.conf**中**maxmemory-policy**属性值设置不同的内存淘汰策略
不同策略的使用场景
1、Redis只做缓存,不做DB持久化,使用allkeys。如状态性信息,经常被访问,但数据库不会修改。
2、同时用于缓存和DB持久化,使用volatile。如商品详情页。
3、存在冷热数据区分,则选择LRU或LFU。如热点新闻,热搜话题等。
4、每个key被访问概率基本相同,选择使用random。如企业内部系统,访问量不大,删除谁对数据库也造成太大压力。
5、根据超时时间长久淘汰数据,选择选用ttl。如微信过期好友请求。
redis缓存穿透的问题?
我们说当发送请求来查询某个数据时,首先会从Redis缓存中查询,如果缓存中有就直接返回,如果没有请求才会到数据库中查询。而缓存穿透指的就是当访问一个redis缓存和数据库都不存在的key时,此时这个请求就会直接到数据库中查询,但是数据库中也查不到任何数据,而且也没有办法写缓存。这样情况缓存相当于没起作用,当请求量过大时,数据库很有可能会挂掉。
Redis缓存本来想起到一个“半路拦截”的作用,替数据库缓解一下压力,缓存穿透的发生,请求就当Redis缓存不存在,直接穿过了Redis缓存,缓存相当于拦了个寂寞,还是得有数据库来处理请求。
解决方案
接口校验
在调用接口时,可以在最外层先做一层校验,比如用户鉴权、数据合法性校验等等,提前过滤掉一些非法的接口请求。例如商品查询中,商品的ID是正整数,则可以直接对非正整数ID的请求直接过滤掉。
缓存空值
当访问缓存和数据库都没有的数据时,可以将一个空值写入缓存,并给这个空值设置较短的过期时间,防止这个无效值一直占有内存。
布隆过滤器
可以使用布隆过滤器存储所有可能访问的key,当用户请求过来,先判断用户发来的请求的key是否存在于布隆过滤器中,不存在的key直接被过滤掉,存在的key则进一步查询缓存和数据库。布隆过滤器相当于在Redis缓存前面又进行了一次拦截校验。
[
](https://blog.csdn.net/ThinkWon/article/details/103402008)
布隆过滤器(推荐)
布隆过滤器在Redis中的数据结构就是一个大型的位数组+多个随机映射的哈希函数。
向布隆过滤器中添加key时,会使用多个hash函数计算这个key的hash值,并转换为数组中对应的索引值,然后对数组长度进行取模运算得到具体的存放位置,每一个hash函数都会计算出不同的位置,然后把数组中对应的位置置为1,就相当于完成添加操作。
当一个请求向布隆过滤器查询一个key是否存在时,跟添加操作一样,会把这个要查询的key通过hash函数计算出数组中对应的索引位置,看看数组中这个位置是否都为1,只要有一个位置为0,则说明布隆过滤器中不存在这个key。如果这几个位置都为1,并不能说明这个key一定存在,只是有非常大概率存在,因为这些位置为1很有可能是因为其它key存在所导致的。如果这个数组比较稀疏,那么布隆过滤器判断正确的概率还是很大的,如果说这个位数组比较密集,那么判断正确的概率就会降低。
布隆过滤器空间占用的大小,可能会影响到判断元素是否存在的精准度。
redis缓存击穿的问题?
缓存击穿是指某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。
要区分开缓存穿透和缓存击穿,穿透更像是一把散弹枪,大量的请求瞄准不同的key进行“射击”。而击穿,更像是一把AK47冲着墙上一个点进行连续射击,缓存过期的那一瞬间,相当于墙上被打出一个洞,直接击穿了Redis这面墙,大量请求查询同一个key。
解决方案
- 加互斥锁
在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,其它请求直接走缓存查询数据。
- 热点数据设置不过期
直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存。这种方式适用于比较极端的场景,例如流量特别特别大的场景。很有可能发生异常,缓存无法更新
[
](https://blog.csdn.net/qq_39794062/article/details/120434626)
redis缓存雪崩的问题?
缓存雪崩是指大量的热点 key 设置了相同的过期时间,导致缓存在同一时刻全部失效,造成瞬时数据库请求量大、压力骤增,引起雪崩,甚至导致数据库被打挂。缓存雪崩其实有点像“升级版的缓存击穿”,缓存击穿是一个热点 key,缓存雪崩是一组热点 key。
解决方案
- 分散过期时间
可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。
- 热点数据不过期
该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的情况。
- 加互斥锁
该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。
[
](https://blog.csdn.net/qq_39794062/article/details/120434626)
