第 4 天学习任务
Redis
一、Redis核心概述
Redis(Remote Dictionary Server)是一款基于内存的高性能键值对(Key-Value)NoSQL数据库,支持多种数据结构,具备高并发、低延迟、可持久化、支持分布式等特性,广泛应用于缓存、会话存储、分布式锁、限流、消息队列等场景。
核心优势:
- 纯内存操作,读写速度极快(单机QPS可达10万+);
- 单线程模型+IO多路复用,避免线程上下文切换和锁竞争;
- 支持多种数据结构,适配不同业务场景;
- 支持持久化,可将内存数据同步到磁盘,避免宕机数据丢失;
- 支持主从复制、哨兵、集群,具备高可用性;
- 支持Lua脚本,实现原子性操作。
二、Redis 5种基础数据结构(底层实现+命令+应用场景·必考)
Redis的核心竞争力之一是丰富的数据结构,每种结构都有对应的底层实现,适配不同的存储和查询场景,面试中几乎必考底层原理和应用。
1. String(字符串)—— 最基础、最常用
底层实现
基于简单动态字符串(SDS,Simple Dynamic String),是C语言char数组的增强版,结构如下:
- len:记录字符串实际长度(字节数),获取长度O(1);
- alloc:记录数组总容量(字节数),避免频繁扩容;
- buf[]:存储字符串内容,末尾自动追加'\0'(兼容C语言函数);
- flags:标记字符串类型(如是否压缩、编码格式)。
SDS vs C语言字符串的优势(面试必答):
- 获取长度O(1)(C语言需遍历,O(n));
- 杜绝缓冲区溢出(扩容时先检查空间,不足则扩容);
- 空间预分配:扩容时额外分配空间,减少内存重分配次数;
- 惰性释放:删除字符串时不立即释放内存,后续复用,提升性能;
- 二进制安全:可存储图片、视频等二进制数据,不依赖'\0'判断结束。
常用命令(实操+面试必背)
- SET key value [EX seconds] [PX milliseconds] [NX|XX]:设置键值对,EX/PX设置过期时间,NX(仅不存在时设置),XX(仅存在时设置);
- GET key:获取键对应的值,不存在返回nil;
- INCR key:自增1(仅适用于数字类型),返回自增后的值;
- DECR key:自减1,返回自减后的值;
- INCRBY key increment:自增指定数值;
- DECRBY key decrement:自减指定数值;
- MSET key1 value1 key2 value2 ...:批量设置键值对;
- MGET key1 key2 ...:批量获取多个键的值;
- EXPIRE key seconds:设置键的过期时间(秒);
- TTL key:查看键的剩余过期时间(-1:永不过期,-2:已过期/不存在);
- PERSIST key:取消键的过期时间,变为永不过期。
应用场景
- 缓存对象:将JSON格式的对象(如用户信息、商品信息)存储为字符串;
- 分布式ID:通过INCR/INCRBY生成全局唯一ID(如订单ID、用户ID);
- 计数器:文章阅读量、点赞数、接口访问次数等;
- 限流:基于INCR统计单位时间内的请求数,超过阈值则拒绝;
- 会话存储:存储用户登录会话信息,设置过期时间自动失效。
2. Hash(哈希)—— 结构化数据存储
底层实现
两种编码格式,根据数据量自动切换:
- ziplist(压缩列表):当哈希中field-value数量少、值较小时使用(默认阈值:field数≤512,单个value≤64字节);
- hashtable(哈希表):当数据量超过阈值时,自动转为哈希表,查询效率O(1)。
ziplist优势:节省内存,连续存储,减少内存碎片;缺点:查询、修改效率低于哈希表。
常用命令
- HSET key field value:给哈希表设置field-value对;
- HGET key field:获取哈希表中指定field的值;
- HMSET key field1 value1 field2 value2 ...:批量设置哈希表的field-value;
- HMGET key field1 field2 ...:批量获取哈希表中多个field的值;
- HGETALL key:获取哈希表中所有field-value对(数据量大时慎用,会阻塞主线程);
- HKEYS key:获取哈希表中所有field;
- HVALS key:获取哈希表中所有value;
- HDEL key field1 field2 ...:删除哈希表中指定field;
- HLEN key:获取哈希表中field的数量;
- HEXISTS key field:判断哈希表中是否存在指定field。
应用场景
- 存储结构化数据:用户信息(id、name、age、phone)、商品信息(id、name、price、stock);
- 局部更新:无需修改整个对象,仅更新某个field(如修改用户手机号);
- 节省内存:相比String存储JSON,Hash可避免重复存储key,减少内存占用。
3. List(列表)—— 有序可重复集合
底层实现
Redis 3.2版本前:ziplist(元素少、值小)和linkedlist(双向链表);
Redis 3.2版本后:统一使用quicklist(快速列表),是ziplist和linkedlist的结合体,结构如下:
quicklist = 多个ziplist + 双向链表,每个ziplist存储多个元素,链表节点指向各个ziplist,兼顾内存效率和操作效率。
核心特点:有序、可重复、两端操作(LPUSH/LPOP、RPUSH/RPOP)效率高(O(1)),中间插入/删除效率低(O(n))。
常用命令
- LPUSH key value1 value2 ...:从列表左侧插入一个/多个元素;
- RPUSH key value1 value2 ...:从列表右侧插入一个/多个元素;
- LPOP key:从列表左侧弹出一个元素;
- RPOP key:从列表右侧弹出一个元素;
- LRANGE key start stop:获取列表中从start到stop的元素(start=0,stop=-1表示所有元素);
- LLEN key:获取列表的长度;
- LINSERT key BEFORE|AFTER pivot value:在指定元素pivot的前面/后面插入value;
- LREM key count value:删除列表中count个值为value的元素(count>0:从左到右删;count<0:从右到左删;count=0:删除所有);
- LTRIM key start stop:保留列表中start到stop的元素,删除其他元素;
- BLPOP key1 key2 ... timeout:阻塞式从左侧弹出元素,无元素则等待timeout秒(timeout=0表示永久等待);
- BRPOP key1 key2 ... timeout:阻塞式从右侧弹出元素。
应用场景
- 消息队列:基于BLPOP/BRPOP实现简单的阻塞式消息队列;
- 栈/队列:LPUSH+LPOP实现栈(先进后出),LPUSH+RPOP实现队列(先进先出);
- 最新列表:如新闻列表、朋友圈动态,LPUSH插入新内容,LRANGE获取最新N条;
- 任务队列:存储待执行的任务,消费者通过RPOP/BLPOP获取任务执行。
4. Set(集合)—— 无序唯一集合
底层实现
两种编码格式,自动切换:
- intset(整数集合):当集合中所有元素都是整数,且元素个数≤512时使用,节省内存;
- hashtable(哈希表):当元素包含非整数,或个数超过阈值时使用,key为集合元素,value为null,利用哈希表的唯一性特性。
核心特点:无序、元素唯一、支持交、并、差等集合运算,查询元素是否存在效率高(O(1))。
常用命令
- SADD key member1 member2 ...:向集合中添加一个/多个元素(重复元素会自动去重);
- SREM key member1 member2 ...:删除集合中指定元素;
- SMEMBERS key:获取集合中所有元素(数据量大时慎用);
- SISMEMBER key member:判断元素是否在集合中(O(1));
- SCARD key:获取集合中元素的个数;
- SUNION key1 key2 ...:求多个集合的并集,返回所有元素;
- SINTER key1 key2 ...:求多个集合的交集,返回共同元素;
- SDIFF key1 key2 ...:求集合1相对于集合2的差集(只在集合1中存在的元素);
- SRANDMEMBER key [count]:随机获取集合中count个元素(count不写默认1,count为负数时可重复获取);
- SPOP key [count]:随机弹出集合中count个元素。
应用场景
- 去重:如用户点赞、收藏,避免重复操作;
- 共同好友/兴趣标签:通过SINTER求两个用户的共同好友;
- 抽奖:通过SRANDMEMBER/SPOP随机抽取中奖用户;
- 标签管理:给用户/商品打标签,通过集合运算筛选目标用户/商品。
5. ZSet(有序集合)—— 有序唯一集合(面试必考)
底层实现(核心考点)
两种编码格式,自动切换:
- ziplist(压缩列表):当元素个数≤128,单个元素值≤64字节时使用,元素按score排序存储;
- skiplist(跳表)+ hashtable(哈希表):当数据量超过阈值时使用,是ZSet的核心实现。
核心结构解析:
- skiplist(跳表):按score从小到大排序,支持快速范围查询(O(log n)),解决链表范围查询效率低的问题;
- hashtable:存储元素与score的映射,支持快速获取元素的score(O(1)),保证元素唯一性。
面试必问:ZSet为什么用跳表,不用红黑树?
- 跳表实现更简单,红黑树的插入、删除需要维护平衡,逻辑复杂;
- 跳表支持范围查询更高效,红黑树范围查询需要遍历,跳表可直接通过层级指针定位;
- 跳表的插入、删除效率与红黑树相当(均为O(log n)),但实现成本更低。
常用命令
- ZADD key score1 member1 score2 member2 ...:向有序集合中添加元素(score为排序依据,重复member会更新score);
- ZRANGE key start stop [WITHSCORES]:按score从小到大排序,获取start到stop的元素(WITHSCORES显示score);
- ZREVRANGE key start stop [WITHSCORES]:按score从大到小排序,获取元素;
- ZSCORE key member:获取指定member的score;
- ZRANK key member:获取member按score升序的排名(排名从0开始);
- ZREVRANK key member:获取member按score降序的排名;
- ZREM key member1 member2 ...:删除有序集合中的指定元素;
- ZINCRBY key increment member:给指定member的score增加increment;
- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]:按score范围查询元素;
- ZCOUNT key min max:统计score在min到max之间的元素个数;
- ZREMRangeByScore key min max:删除score在min到max之间的元素;
- ZREMRangeByRank key start stop:删除排名在start到stop之间的元素。
应用场景
- 排行榜:如游戏战力榜、文章阅读量榜、商品销量榜(按score排序);
- 优先级队列:按score设置任务优先级,ZRANGEBYSCORE获取最高优先级任务;
- 延时任务:score设置为任务执行时间戳,定期ZRANGEBYSCORE获取到期任务;
- 范围筛选:如筛选分数在90-100分的学生、价格在100-200元的商品。
三、Redis 过期策略(面试必考)
Redis支持给key设置过期时间,但不会实时删除所有过期key(会消耗大量CPU),而是采用「三种策略组合」的方式,平衡CPU和内存开销。
1. 惰性删除(Lazy Expiration)
核心逻辑
不主动删除过期key,只有当用户访问该key时,才检查是否过期:若过期则删除,返回nil;若未过期则正常返回值。
优缺点
- 优点:完全不消耗CPU资源,只在访问时触发检查,对CPU友好;
- 缺点:过期key若长期不被访问,会一直占用内存,导致内存泄漏(“僵尸key”)。
2. 定期删除(Periodic Expiration)
核心逻辑
Redis每隔一段时间(默认100ms),随机抽取一批设置了过期时间的key,检查并删除过期的key,具体流程:
- 从设置了过期时间的key集合中,随机抽取N个key(默认N=20);
- 删除其中过期的key;
- 若过期key的比例超过1/4,则重复步骤1-2,直到比例≤1/4或执行次数达到上限(避免阻塞主线程)。
优缺点
- 优点:平衡CPU和内存,既能删除部分过期key,又不会消耗过多CPU;
- 缺点:无法保证所有过期key都被删除,存在“漏删”情况,仍可能有部分过期key占用内存。
3. 内存淘汰机制(Memory Eviction Policy)
核心逻辑
当Redis内存使用达到配置的maxmemory(最大内存)时,会触发内存淘汰机制,删除部分key,释放内存,避免Redis宕机。
配置方式:通过redis.conf中的maxmemory-policy参数设置,共8种策略,分为4类:
8种淘汰策略(面试必背)
| 策略名称 | 核心逻辑 | 适用场景 |
|---|---|---|
| volatile-lru | 仅对设置了过期时间的key,删除最近最少使用(LRU)的key | 大多数业务场景,优先保留未过期的key |
| allkeys-lru | 对所有key,删除最近最少使用的key | 缓存场景,不区分是否过期,优先保留常用key |
| volatile-lfu | 仅对设置了过期时间的key,删除使用频率最低(LFU)的key | 访问频率不均匀的场景,比LRU更精准 |
| allkeys-lfu | 对所有key,删除使用频率最低的key | 高频访问场景,淘汰低频访问的key |
| volatile-random | 仅对设置了过期时间的key,随机删除 | 无明确访问规律,无需优先保留某些key |
| allkeys-random | 对所有key,随机删除 | 测试场景,生产环境极少使用 |
| volatile-ttl | 仅对设置了过期时间的key,删除剩余过期时间最短(TTL最小)的key | 需要优先保留即将过期的key的场景 |
| noeviction | 不删除任何key,内存满时拒绝所有写操作(返回OOM错误) | 不允许丢失数据的场景(如持久化存储) |
生产环境常用策略:volatile-lru(默认推荐)、allkeys-lru(纯缓存场景)。
四、Redis 持久化(面试必问)
Redis是基于内存的数据库,宕机后内存数据会丢失,持久化机制就是将内存中的数据同步到磁盘,重启后恢复数据,分为RDB、AOF两种方式,以及混合持久化(4.0+)。
1. RDB(Redis Database File,快照持久化)
核心原理
在指定时间点,将Redis内存中的所有数据生成一份二进制快照(dump.rdb文件),存储到磁盘,重启时加载该文件,恢复数据。
触发方式(三种):
-
手动触发:
- save:同步执行,阻塞Redis主线程,直到快照生成完成(不推荐,会导致服务不可用);
- bgsave:异步执行,fork一个子进程,由子进程负责生成快照,主线程正常处理请求(推荐)。
-
自动触发:通过redis.conf配置触发条件,如:
- save 3600 1:3600秒内,至少有1个key被修改,触发bgsave;
- save 300 100:300秒内,至少有100个key被修改,触发bgsave;
- save 60 10000:60秒内,至少有10000个key被修改,触发bgsave。
-
被动触发:
- 主从复制:主节点自动触发bgsave,生成快照发送给从节点;
- Redis关机(shutdown):自动执行save,生成快照后关机;
- 执行flushall:清空所有数据,会生成空的RDB文件。
优缺点
| 优点 | 缺点 |
|---|---|
| 1. 二进制文件,体积小,占用磁盘空间少; | 1. 数据丢失风险:两次快照之间宕机,会丢失这段时间的修改; |
| 2. 恢复速度快,适合大规模数据恢复; | 2. fork子进程时,会占用与主进程相同的内存(写时复制),高内存场景可能阻塞主线程; |
| 3. 适合冷备、灾难恢复,可将RDB文件拷贝到其他服务器恢复; | 3. 不适合实时持久化,无法保证数据零丢失。 |
2. AOF(Append Only File,日志持久化)
核心原理
将Redis执行的每一条写命令(SET、HSET、LPUSH等),以文本格式追加到aof文件中,重启时,Redis会重新执行aof文件中的所有命令,恢复数据。
核心配置:
- appendonly yes:开启AOF持久化(默认关闭);
- appendfilename "appendonly.aof":AOF文件名称;
- appendfsync:刷盘策略(核心,面试必问)。
三种刷盘策略(面试必背)
| 刷盘策略 | 核心逻辑 | 安全性 | 性能 | 适用场景 |
|---|---|---|---|---|
| appendfsync always | 每执行一条写命令,立即将数据刷到磁盘 | 最高(数据几乎不丢失) | 最低(频繁IO,阻塞主线程) | 对数据安全性要求极高的场景(如金融) |
| appendfsync everysec | 每秒刷盘一次,将缓冲区的数据写入磁盘 | 较高(最多丢失1秒数据) | 中等(平衡安全与性能) | 生产环境默认,大多数业务场景 |
| appendfsync no | 不主动刷盘,由操作系统决定何时刷盘 | 最低(可能丢失大量数据) | 最高(无IO阻塞) | 测试场景,生产环境不推荐 |
AOF重写(核心优化)
问题:AOF文件会随着写命令增多而越来越大,导致恢复速度慢、占用磁盘空间多。
解决方案:AOF重写,Redis会扫描内存中的所有数据,生成一份“最小指令集”(如多次SET同一个key,只保留最后一次),替换原来的AOF文件,缩小文件体积。
触发方式:
-
手动触发:bgrewriteaof(异步执行,不阻塞主线程);
-
自动触发:通过配置阈值,如:
- auto-aof-rewrite-percentage 100:AOF文件体积比上次重写后增长100%(翻倍);
- auto-aof-rewrite-min-size 64mb:AOF文件体积至少达到64MB,才触发重写。
优缺点
| 优点 | 缺点 |
|---|---|
| 1. 数据安全性高,最多丢失1秒数据(everysec策略); | 1. 文件体积大,占用磁盘空间多; |
| 2. 文本格式,可手动编辑、修复(如误执行flushall,可删除该命令行恢复数据); | 2. 恢复速度比RDB慢(需要重放所有命令); |
| 3. 支持实时持久化,适合对数据零丢失要求高的场景; | 4. 写命令追加会产生一定的IO开销,性能略低于RDB。 |
3. 混合持久化(Redis 4.0+,生产标配)
核心原理
结合RDB和AOF的优点,开启混合持久化后,AOF重写时,会将当前内存数据以RDB格式写入AOF文件头部,后续的写命令以AOF格式追加到文件尾部。
重启恢复流程:
- 先加载AOF文件头部的RDB数据(快速恢复大量数据);
- 再重放AOF文件尾部的写命令(恢复RDB之后的增量数据)。
核心优势
- 恢复速度快(接近RDB);
- 数据安全性高(接近AOF);
- 文件体积适中(比纯AOF小)。
配置方式:aof-use-rdb-preamble yes(Redis 5.0+默认开启)。
五、缓存三大问题(面试压轴,必背)
在分布式系统中,使用Redis作为缓存时,会遇到穿透、击穿、雪崩三大问题,需掌握每种问题的现象、危害和解决方案。
1. 缓存穿透(Cache Penetration)
现象
用户频繁查询「一定不存在的数据」(如ID=-1的用户、不存在的商品),这类数据既不在缓存中,也不在数据库中,导致所有请求都直接打穿到数据库,造成数据库压力过大,甚至宕机。
危害
- 数据库负载剧增,响应变慢;
- 可能被恶意攻击(如大量查询不存在的ID),导致数据库宕机;
- 缓存失去作用,所有请求都穿透到数据库。
解决方案(必背)
-
缓存空值:查询数据库发现数据不存在时,将空值(或特殊标记)缓存起来,并设置较短的过期时间(如5分钟),避免后续相同请求打穿到数据库;
- 注意:需避免缓存大量空值导致内存浪费,可设置空值的过期时间短一些。
-
布隆过滤器(Bloom Filter):
- 原理:将数据库中所有存在的key,提前存入布隆过滤器(一种概率数据结构);
- 查询时,先通过布隆过滤器判断key是否存在:若不存在,直接返回空,不查询缓存和数据库;若存在,再查询缓存和数据库;
- 优势:占用内存小,查询效率高(O(1));缺点:存在误判率(无法100%准确判断key是否存在)。
-
接口层参数校验:在接口入口处,过滤无效参数(如ID≤0、非法字符),直接拒绝无效请求,避免请求到达缓存和数据库。
-
黑名单限制:对频繁发送无效请求的IP/用户,加入黑名单,限制其访问。
2. 缓存击穿(Cache Breakdown)
现象
一个「热点key」(如热门商品、热门文章)过期时,大量请求同时访问该key,此时缓存中无数据,所有请求都直接打穿到数据库,导致数据库瞬间压力剧增。
与缓存穿透的区别:缓存穿透是查询“不存在的数据”,缓存击穿是查询“存在但过期的数据”。
危害
- 数据库瞬间被大量请求冲击,可能导致数据库宕机;
- 热点key对应的业务不可用,影响用户体验。
解决方案(必背)
-
互斥锁(Mutex Lock):
- 原理:当缓存失效时,只有一个请求能获取到锁,去查询数据库并更新缓存,其他请求则阻塞等待,直到缓存更新完成;
- 实现:使用Redis分布式锁(SET NX PX),查询数据库前获取锁,更新缓存后释放锁;
- 优势:简单可靠;缺点:会增加请求延迟,存在死锁风险(需设置锁过期时间)。
-
热点key永不过期:
- 原理:不设置热点key的过期时间,避免key过期;
- 注意:需在后台异步更新缓存(如定时任务),确保缓存数据与数据库数据一致;
- 优势:无请求阻塞,性能好;缺点:占用内存,需确保缓存数据及时更新。
-
逻辑过期:
- 原理:给key设置一个“逻辑过期时间”(存储在value中),不设置Redis的过期时间;
- 查询时,先判断逻辑过期时间是否到期:若未到期,直接返回缓存数据;若到期,获取互斥锁,异步更新缓存,其他请求仍返回旧数据;
- 优势:无请求阻塞,用户体验好;缺点:存在短时间内数据不一致的情况。
3. 缓存雪崩(Cache Avalanche)
现象
大量key在同一时间过期,或Redis集群宕机,导致所有请求都打穿到数据库,数据库瞬间被压垮,引发系统雪崩。
与缓存击穿的区别:缓存击穿是单个热点key过期,缓存雪崩是大量key同时过期或Redis宕机。
危害
- 数据库宕机,整个系统不可用;
- 引发连锁反应,其他依赖数据库的服务也会瘫痪;
- 系统恢复成本高,影响业务正常运行。
解决方案(必背)
-
过期时间加随机值:给每个key的过期时间加上一个随机值(如1-300秒),避免大量key在同一时间过期;
-
Redis集群高可用:
- 部署主从复制+哨兵模式,或Redis Cluster集群;
- 主节点宕机时,哨兵自动将从节点切换为主节点,保证Redis服务不中断。
-
多级缓存:
- 部署本地缓存(如Caffeine、EhCache)+ Redis分布式缓存;
- 请求先查询本地缓存,再查询Redis,最后查询数据库,即使Redis宕机,本地缓存也能承接部分请求。
-
服务降级与熔断:
- Redis宕机或缓存失效时,通过熔断器(如Sentinel、Resilience4j)拒绝部分请求,或返回兜底数据(如默认商品、提示信息);
- 避免大量请求打穿到数据库,保护数据库。
-
互斥锁:与缓存击穿的互斥锁逻辑类似,限制同时查询数据库的请求数量,避免数据库被瞬间冲击;
-
持久化保障:开启Redis混合持久化,确保Redis宕机后能快速恢复数据,减少服务不可用时间。
六、Redis 分布式锁(面试必写、必问)
在分布式系统中,多个服务节点需要竞争同一资源(如库存扣减、订单创建),需通过分布式锁保证操作的原子性,避免并发问题,Redis是实现分布式锁的常用方案。
1. 分布式锁的核心要求
- 互斥性:同一时间,只有一个服务节点能获取到锁;
- 安全性:不能出现死锁,锁必须能释放(即使服务宕机);
- 唯一性:不能误释放别人的锁;
- 高可用:Redis集群宕机时,锁服务仍能正常工作;
- 原子性:锁的获取、释放操作必须是原子的。
2. 基于Redis的分布式锁实现(核心命令)
获取锁(核心命令)
SET lock_key unique_value NX PX 30000
命令解析(面试必背):
- lock_key:锁的key(如lock:stock:1001,标识具体资源);
- unique_value:唯一值(如UUID+服务IP),用于标识锁的持有者,避免误释放别人的锁;
- NX(Not Exist):只有当lock_key不存在时,才能设置成功(保证互斥性);
- PX 30000:设置锁的过期时间为30000毫秒(30秒),避免服务宕机导致死锁。
返回结果:
- OK:获取锁成功;
- nil:获取锁失败(锁已被其他节点持有)。
释放锁(核心逻辑:Lua脚本原子操作)
不能直接用DEL命令释放锁(会误释放别人的锁),必须先判断锁的持有者是否是自己,再释放,该操作需用Lua脚本保证原子性(Redis执行Lua脚本时,会阻塞其他命令,确保操作原子)。
-- KEYS[1] = lock_key,ARGV[1] = unique_value
if redis.call("get", KEYS[1]) == ARGV[1]
then
-- 锁是自己的,释放锁
return redis.call("del", KEYS[1])
else
-- 锁不是自己的,不做操作
return 0
end
Lua脚本优势:将“判断+删除”两个操作合并为一个原子操作,避免并发场景下的误释放问题。
3. 分布式锁的问题与解决方案(面试必问)
问题1:锁过期,任务还没执行完
现象:锁设置了30秒过期,但任务执行需要40秒,锁过期后,其他节点会获取到锁,导致并发问题。
解决方案:看门狗(Watchdog)自动续期
- 原理:获取锁成功后,启动一个后台线程(看门狗),每隔10秒(锁过期时间的1/3),检查锁是否还在(自己持有),如果在,就将锁的过期时间重置为30秒;
- 实现:Java中可通过Redisson框架实现(Redisson内置看门狗机制);
- 注意:任务执行完成后,需手动关闭看门狗,避免不必要的续期。
问题2:主从切换,锁丢失
现象:主节点持有锁,数据还未同步到从节点,主节点宕机,从节点切换为主节点,新主节点中没有该锁,其他节点可获取到锁,导致并发问题