Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
它支持多种类型的数据结构,如 字符串(strings),散列(hashes), 列表(lists),集合(sets),有序集合(sorted sets)
与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。
Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
1.Redis五种基本数据类型
Redis支持五种数据类型:String(字符串)、hash(哈希)、list(列表)、set(集合)以及zsetsorted set(有序集合)。
- String字符串
Redis 字符串是字节序列。
String的数据结构是简单的Key-Value模型,Value可以是字符串,也可以是数字。
set key value
设置过期时间 setex:setex key 30 value
不存在设置 setnx(set if not exist):setnx key value
如果key不存在,则创建一个key,如果key存在,则创建失败并返回0。
>set name oldou
OK
>get name #获取name中的值
incr命令
让当前键值以 1 的数量递增,并返回递增后的值。
>set num 10
OK
>incr num
11
decr命令
可以指定参数一次递减的数值,并返回递减后的值
>decr num
10
-
Hash散列表
Redis 的哈希是键值对的集合。
Redis 的哈希值是字符串字段和字符串值之间的映射,因此它们被用来表示对象,还有用户信息之类的,经常变动的信息。
Hash更适合用于对象的存储,String更适合字符串存储。 -
List链表
Redis 的链表是简单的字符串列表,排序插入顺序。可以添加元素到 Redis 的列表的头部或尾部
Lpush:表示的是向链表的左添加,也就是向链表的头添加;
Rpush:表示的是向链表的右添加,也就是向链表的尾添加; -
Set( 集合)
Redis 的集合是字符串的无序集合。
在Set集合当中,是不允许有重复的。
set是通过hash table实现的,可以进行添加、删除和查找。对集合我们可以取并集,交集,差集. -
SortedSet( 有序集合) zset
Redis 的有序集合类似于 Redis 的集合,字符串不重复的集合。
操作详细介绍见我的 Redis基础 虽然也不怎么太详细
超详细的使用和说明见 Redis的五种常用数据类型、三种特殊数据类型详解
Redis三种特殊的数据类型
- Geospatial 地理位置
- Hyperloglog 基数统计
基数就是一个可重复集合内不重复元素的个数就是基数。应用场景:适合做页面统计。 - Bitmap位图场景
Bitmap是位图,数据结构,都是操作二进制位来进行记录,就只有0和1两个状态。应用场景:统计用户信息
1.1 一个字符串类型的值能存储最大容量是多少?
一个字符串类型的值能存储的最大容量为512M。
1.2 Redis key 的过期时间和永久有效分别怎么设置?
使用expire命令对key的过期时间进行设置;
使用persist命令对key永久有效进行设置;
1.3 Redis 最适合的场景?
(1)会话缓存(最常用的一种使用 Redis 的情景是会话缓存(session cache)。
用 Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。
(2)全页缓存(FPC)
除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。
(3)队列
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis能作为一个很好的消息队列平台来使用。
Redis 作为队列使用的操作,就类似于本地程序语言(如 Python)对 list 的 push/pop 操作。
(4)排行榜/计数器
Redis 在内存中对数字进行递增或递减的操作实现的非常好。
集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。
(5)发布/订阅
发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用 Redis 的发布/订阅功能来建立聊天系统!
1.4Redis 做异步队列怎么用的?
一般使用list结构作为队列,rpush生产消息,lpop消费消息。
当lpop没有消息的时候,要适当sleep一会儿再重试。
1.5Redis 分布式锁是什么回事?
先拿setnx来争抢锁,抢到之后再用expire给锁加一个过期时间防止锁忘记了释放。
2.Redis的两种持久化策略
由于 Redis 的数据都存放在内存中,如果没有配置持久化,redis 重启后数据就全部丢失了,这时候就需要 Redis 持久化功能,将数据保存到磁盘上,当 redis 重启后,可以从磁盘中恢复数据。
redis 提供两种方式进行持久化:
- RDB 持久化(原理是将Redis在内存中的记录定时dump到磁盘的持久化)
- AOF 持久化(原理是将Redis的操作日志)
RDB机制
RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入到磁盘。也是 redis 的默认持久化方式。这种方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为:dump.rdb
RDB 来说,提供了三种机制:save、bgsave、自动化。
- save触发方式:该命令会阻塞当前 Redis 服务器,执行 save 命令前,Redis不能处理其它命令,直到 RDB 过程完成为止。
执行完成,会把原先的 dump.rdb 给替换掉。如果我们客户端有成千上万连接,这时候使用 save 方式,会造成很大的阻塞。 - bgsave触发方式
执行该命令时,redis 会在后台异步进行快照操作。基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。 - 自动触发:自动触发是由我们的配置文件来完成的。
AOF 机制
全量备份总是耗时的,有时候我们提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。为了压缩aof的持久化文件。redis提供了 bgrewriteaof 命令。将内存中的数据以命令的方式保存到临时文件中,同时会fork出一条新进程来将文件重写。
两者优势劣势
RDB 的优势和劣势
- 优势:
RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 - 劣势:
RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。
AOF 的优势和劣势
- 优势:
AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据 - 缺点:
对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大。
AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。
混合持久化
1、什么是混合持久化?
Redis 4.0 之后新增了混合持久化的方式。
在开启混合持久化的情况下,AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后的数据再以 AOF 的格式化追加的文件的末尾。
可以将其理解为,在 aof 持久化的基础上,进行的一些优化,本身也依然是基于 aof 持久化。
Redis重启后是如何重新加载数据的?
如果你开启了 RDB,Redis重启后会加载 RDB 文件。
如果你开启了 AOF,Redis重启后加载 AOF文件。
如果同时开启了 RDB 和 AOF ,那么Redis会优先加载 aof,其次加载 rdb。
Redis如何进行数据迁移的?
RDB 和 AOF 文件复制到目标服务器的redis文件夹中,设置目标服务器Redis的持久化方式(如果你要迁移rdb,配置文件中就开启rdb同步,如果你要迁移aof,配置文件中就开启aof文件同步)。
开启后,重启 Redis 服务将会自动读取 aof 或者 rdb文件。
3.Redis 内存回收机制
Redis 的内存回收主要由两部分组成:
- Redis过期策略:删除过期时间的key值。本质是处理过期的缓存数据。
- Redis淘汰策略:内存使用到达maxmemory上限时触发内存淘汰数据。本事是处理内存不足时的需要申请额外空间的数据。
Redis的过期策略和内存淘汰策略不是一件事
Redis过期策略
-
定时过期
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。 -
惰性过期
只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。 -
定期过期
**每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。**该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
Redis中同时使用了惰性过期和定期过期两种过期策略。
Redis淘汰策略
Redis的内存淘汰策略,是指当内存使用达到maxmemory极限时,需要使用LAU淘汰算法来决定清理掉哪些数据,以保证新数据的存入。
Redis默认情况下就是使用LRU策略算法。
LRU算法(least RecentlyUsed),最近最少使用算法,也就是说默认删除最近最少使用的键。
但是一定要注意一点!redis中并不会准确的删除所有键中最近最少使用的键,而是随机抽取3个键,删除这三个键中最近最少使用的键。
那么3这个数字也是可以可以设置采样的大小,如果设置为10,那么效果会更好,不过也会耗费更多的CPU资源。对应位置是配置文件中的maxmeory-samples。
缓存清理的流程
客户端执行数据写入操作,redis server接收到写入操作之后,检查maxmemory的限制,如果超过了限制,那么就根据对应的策略清理掉部分数据,写入操作完成执行。
4.Redis三种高可用模式:主从、哨兵、集群
Redis服务器的高可用,如何保证备份的机器是原始服务器的完整备份呢?这时候就需要哨兵和复制。
1.主从模式
(1).主从模式的定义
Redis的主从模式是一种数据备份和读写分离的模式。在这种模式下,有一个主节点(Master)和一个或多个从节点(Slave)。所有的写操作都在主节点上进行,而读操作可以在主节点和从节点上进行。从节点会复制主节点的数据,实现数据的备份。
(2)工作原理:在主从模式下,主节点负责处理所有的写操作,并将写操作记录在内存中的缓冲区。从节点从主节点获取这些写操作记录,并在自己的数据库上执行这些操作,从而保持与主节点的数据一致。此外,读请求可以在主节点和从节点上进行,从而实现读写分离,提高系统的读取性能。
(3)主从复制(同步)流程:
【1】向Master机器发送一个“sync command”命令,请求同步连接。
【2】Master机器都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作),同时Master还会记录修改数据的所有命令并缓存在数据文件中。
【3】Maste机器就会向Slave机器发送数据文件,Slave端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着Master机器就会将修改数据的所有操作一并发送给Slave端机器。
(3)主从模式的配置和使用:
配置主从模式相对简单,只需要在从节点的配置文件中设置主节点的IP地址和端口号,然后启动从节点即可。从节点会自动连接到主节点,并开始复制数据。在使用上,用户可以直接向主节点发送写请求,而读请求可以发送到主节点或从节点。
(4)主从模式的优点和局限性
优点:
可以实现数据的备份,提高数据的安全性;
读写分离,提高系统的读取性能
局限性:
不能自动切换,如果主节点发生故障,从节点不能自动切换为主节点,需要人工干预;
所有的写操作都在主节点上进行,如果写请求量大,主节点可能会成为性能瓶颈。
2.哨兵模式
(1)哨兵模式的定义
Redis的哨兵模式是在主从模式的基础上,增加了故障转移的功能。
哨兵模式下,除了主节点和从节点,还有一个或多个哨兵节点(Sentinel)。哨兵节点的主要任务是监控主节点和从节点的运行状态,并在主节点发生故障时,自动将从节点提升为主节点。
(2)哨兵模式的工作原理
在哨兵模式下,哨兵节点会定期检查主节点和从节点的运行状态。如果发现主节点发生故障,哨兵节点会在从节点中选举出一个新的主节点,并通知其他的从节点和哨兵节点。此外,哨兵节点还可以接收客户端的查询请求,返回当前的主节点信息,从而实现客户端的透明切换。
(3)Sentinel哨兵主要负责三个方面的任务:
监控:通过发送命令,不间断的监控Redis服务器运行状态,包括主服务器和从服务器。
提醒:当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障转移(核心任务):当哨兵监测到主服务器宕机,会自动在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器将其转换为主服务器(自动切换)。然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
(4)哨兵模式的优点和局限性
优点:
哨兵模式可以实现故障转移,提高系统的可用性
哨兵模式可以实现客户端的透明切换,提高系统的可维护性。
局限性:
哨兵节点需要额外的资源和维护,增加了系统的复杂性;
主节点发生故障后,新的主节点可能会有一段时间的数据不一致,影响数据的准确性。
3.集群模式
(1)集群模式的定义
为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。
Redis的集群模式是一种分布式的解决方案,它允许多个Redis节点(服务器)协同工作,提供更高的性能和可用性。
在这种模式下,数据被分片存储在多个节点上,每个节点负责一部分数据的读写。
如果要保证所有数据的高可用还需要配合主从模式。
(2)集群模式的工作原理:
在集群模式下,Redis使用一种叫做哈希槽的技术来实现数据的分片。整个哈希空间被分成16384个哈希槽,每个节点负责一部分哈希槽。当一个键需要被存储时,Redis会根据键的值计算出一个哈希值,然后根据哈希值决定将这个键存储在哪个节点上。这样,读写请求就可以在多个节点上并行处理,提高了系统的性能。
在Redis集群模式下,任意一个Master节点都可以接受客户端的请求。当客户端向某个Master节点发送请求时,如果这个请求的键所对应的哈希槽不在这个Master节点负责的范围内,那么这个Master节点会返回一个重定向信息,告诉客户端应该向哪个节点发送请求。这个过程对客户端来说是透明的,客户端只需要按照重定向信息重新发送请求即可。这种方式确保了Redis集群可以有效地处理并分发客户端的请求,提高了系统的性能和可用性。
(3)集群的作用
-
数据分区:数据分区(或称数据分片)是集群最核心的功能。
集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及;例如,如果单机内存太大,bgsave和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出。 -
高可用:集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群仍然可以对外提供服务。=
三种模式的比较和选择
主从模式、哨兵模式和集群模式的比较
-
主从模式是最基础的模式,配置简单,主要用于数据备份和读写分离,提高系统的读取性能。但是,主从模式无法处理主节点故障的情况。主要应用于:读取数据,数据量不大,对数据的一致性要求不高。
-
哨兵模式在主从模式的基础上增加了故障转移的功能,可以自动处理主节点故障的情况,提高了系统的可用性。但是,哨兵模式需要额外的哨兵节点,增加了系统的复杂性。应用于:应用场景需要高可用性,即使在主节点发生故障的情况下也需要保证服务的正常运行。
-
集群模式是一种分布式的解决方案,可以实现数据的水平扩展,提高了系统的性能和存储容量。同时,集群模式也可以实现高可用性,即使某个节点发生故障,系统仍然可以继续提供服务。但是,集群模式的配置和维护相对复杂,需要管理多个节点。
应用场景数据量大,需要高性能和高可用性,那么集群模式可能是最好的选择。集群模式可以提供更高的性能,更大的存储容量,以及更好的故障容忍能力。
5.缓存穿透、缓存击穿、缓存雪崩
缓存穿透是指数据库原本就没有的数据,请求直接落入数据库。
缓存击穿是指数据库有数据,缓存过期后请求直接落入数据库。
缓存雪崩是指很多缓存同时失效,流量全部涌入数据库,造成数据库压力。
缓存穿透
(1)缓存穿透是指用户请求的数据在缓存中不存在即没有命中,同时在数据库中也不存在,导致用户每次请求该数据都要去数据库中查询一遍。如果有恶意攻击者不断请求系统中不存在的数据,会导致短时间大量请求落在数据库上,造成数据库压力过大,甚至导致数据库承受不住而宕机崩溃。(缓存穿透其实就是恶意攻击)
因此,在日常开发实践中,对请求参数进行严格的校验是至关重要的。对于那些非法或明显不可能存在的key,系统应该立即返回一个错误提示,而不是让这些请求到达数据库层面。这样不仅可以提升系统的安全性,还能够维护数据库的稳定性和性能。
(2)解决方案
- 缓存空数据:当出现Redis查不到数据,数据库也查不到数据的情况,我们就把这个key保存到Redis中,设置value=“null”,并设置其一个较短的过期时间,后面再出现查询这个key的请求的时候,直接返回null,就不需要再查询数据库了。
优点:实现简单。
缺点:耗费内存并且会有失效的情况。 - 布隆过滤器
布隆过滤器用于判断一个元素是否可能在一个集合内。它的工作原理是:当布隆过滤器断言某个键(key)不存在时,这个结论是绝对可靠的;但当它认为某个键存在时,只表示有很高的可能性确实存在,尽管有一定的误判几率。
为了缓解缓存穿透的问题,我们可以在Redis缓存层之前部署一道布隆过滤器的防线。将数据库中所有的键导入布隆过滤器中,这样在任何查询到达Redis之前,系统会首先检查键是否在布隆过滤器中。如果键在布隆过滤器中不存在,那么查询将不会继续前往数据库,而是直接返回结果,以此避免对数据库的不必要访问和潜在的查询压力。
优点:占用内存小。布隆过滤器不需要存储具体的数据项,只需要存储数据的哈希值。
缺点:存在一定的误判情况。
缓存击穿
(1)什么是缓存击穿?
缓存击穿通常发生在高并发系统中,当某个被频繁访问的数据在缓存中的有效期过了,恰好在这个时候有大量的并发请求需要访问这个数据。由于缓存中的数据已经失效,这些并发请求就会直接转发到数据库上,如果数据库的处理能力不足以应对这种突然增加的压力,就可能导致系统响应缓慢甚至崩溃。
(2)解决方案
- 互斥锁:在缓存失效后,通过互斥锁控制读数据写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待。这种方式会阻塞其他的线程。
优点:1)强一致。互斥锁能够确保在缓存重建过程中,只有一个线程可以访问数据库并更新缓存,避免多个线程同时读取到过期的缓存数据,从而保证了数据的强一致性。2)实现相对简单。互斥锁的实现相对简单,不需要复杂的逻辑处理
缺点: 吞吐量低。在高并发的场景下,互斥锁可能会导致系统的可用性降低
- 逻辑过期
逻辑过期方案与互斥锁方案在应对缓存击穿问题上确实有着相似之处,它们都通过使用互斥锁来防止同时对同一热点key的缓存进行更新。然而,它们的工作细节和重点略有不同。在逻辑过期方案中,每个缓存项旁边附加了一个额外的字段来表示其逻辑上的过期状态,而不是物理地从缓存系统中移除该数据。这样,即使一个缓存项已标记为逻辑上过期,它仍然存在于缓存中并可以被访问到。这种方法避免了因等待重新加载数据而导致的缓存缺失情况。当一个线程查询某个key的缓存数据时,如果该数据已经处于逻辑过期状态,无论该线程是否成功获取互斥锁,系统都会先返回这个逻辑上过期的数据。这样做的好处是即使在数据更新过程中,也能保证用户能立即得到响应,虽然数据可能是旧的。与此同时,如果某个线程成功获取了互斥锁,这意味着它获得了更新缓存数据的权限。这个线程会创建一个单独的工作线程来负责从数据库检索最新数据、更新缓存,并重置该key的逻辑过期时间。一旦这个过程完成,互斥锁便会被释放。
优点:吞吐量高。在逻辑过期方案中,即使数据已过期,系统仍会返回过期数据给客户端,而不是等待锁释放后再去数据库拉取最新数据。
缺点: 1)牺牲数据一致性。 2)实现复杂。 3)耗费更多的内存。因为增加了一个字段来维护逻辑过期的时间,这必定会造成额外的空间占用。
总结:我们追求数据的强一致的时候,就使用互斥锁方案。当我们要求数据更高的吞吐量,并且对数据的一致性要求不高的时候,就使用逻辑过期的方案。
缓存雪崩
(1)什么是缓存雪崩?
缓存雪崩是指由于缓存系统的整体失效,导致大量请求直接到达后端数据库,进而可能造成数据库崩溃和整个系统的崩溃。这种现象通常发生在缓存服务器重启或宕机时,或者是大规模的key同时失效导致的结果。
(2)解决方案
-
过期时间随机
在设置失效时间的时候加上一个随机值,比如1-5分钟随机。这样就可以避免了由于使用相同的过期时间导致在某一时刻大量key过期引发的缓存雪崩问题。 -
使用熔断机制
当系统流量达到预定的极限时,为避免对数据库造成过大压力,我们将自动显示“系统繁忙”提示。这样做可以确保至少有一部分用户能够顺畅地使用我们的服务。对于未能即时访问的用户,只要多刷新几次,也是可以获得正常访问的。 -
缓存预热
缓存预热是一种关键技术,它在系统启动前预先加载关键数据到缓存中,以减少系统上线时对后端数据库的冲击。
实施缓存预热通常涉及编写批处理任务,这些任务可以在系统启动期间执行,或者通过定时任务定期去执行。定期执行更能保证数据的实时性,但是,同样会耗费系统的部分性能,尤其是在数据量大的时候。所以,具体选择如何进行预热数据,还是需要综合考虑预热数据量的大小以及预热数据更新的是否频繁等因素。 -
redis集群
保证Redis缓存的高可用,防止Redis宕机导致缓存雪崩的问题。可以使用主从+ 哨兵,Redis集群来避免单个Redis服务器宕机导致整个缓存直接失效。 -
多级缓存
通过实施多级缓存策略降低因缓存失效导致的风险。在这种策略中,本地进程内的缓存充当第一级缓存,而Redis则作为第二级远程缓存。每一级缓存都设定有独立且差异化的超时时间。
这种层级化的缓存机制为系统提供了额外的弹性层,当一层缓存遇到问题时,其他层级能够起到“安全网”的作用,从而可以有效避免雪崩现象。 -
互斥锁
这个和缓存击穿比较类似 ,都是通过互斥锁来控制读数据写缓存的线程数量,这样就避免大量请求同时击中数据库。同样,这样虽然可以避免大量key同时失效导致的缓存雪崩问题。但是,同样性能也会因为加锁的原因受到影响。如果,系统对吞吐量要求不高的情况下,这种方式其实还是不错的。因为它即解决了缓存击穿的问题,也解决了缓存雪崩的问题。可谓一举两得。