尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Redis基础面试题全解析:从数据类型到分布式锁的原理与实战

Redis基础面试题全解析:从数据类型到分布式锁的原理与实战 前段时间帮团队做技术面试连续面了十几个候选人发现一个很有意思的现象聊到Redis基础面试题几乎所有人都能说出五种数据类型RDB和AOF缓存穿透、击穿、雪崩但再往深问一层比如为什么ZSet用跳表不用红黑树AOF重写期间会不会阻塞主进程分布式锁在哨兵模式下有什么隐患能答出所以然的人就明显变少了。这篇文章我把自己在面试中经常问的、以及候选人频繁踩坑的Redis基础题整体梳理一遍。目的不是让你背答案而是把每道题背后的原理、常见追问、和实际项目中的关联全部串起来。准备面试的同学可以把它当查漏补缺清单已经工作的工程师也可以借这个机会把Redis基础体系补完整。这里先说明一个前提我默认你已经会基本的Redis命令比如SET、GET、DEL、LPUSH、ZADD这种。如果连这些都不熟建议先装一个Redis用redis-cli把这些常用命令挨个敲一遍再往下看。基础命令的熟练度在面试里很重要因为面试官现场出场景题时你除了说思路往往还要直接在白板上写命令写不出来或者命令写错印象分会大打折扣。1. 数据类型题面试官问有哪几种时其实在问你会不会用1.1 五种类型的高分答法命令、结构、场景三件套Redis基础题的雷打不动第一问就是Redis有哪些数据类型。这个问题的出题逻辑很简单数据类型是Redis一切功能的地基面试官需要通过它判断你只是背过八股还是真的用Redis写过东西。低分答法是报出五个名字string、hash、list、set、zset。及格答法是每个类型补上一两个核心命令和对应场景。高分答法是命令 底层结构 典型场景 复杂度四位一体地讲。我建议你这样组织答案有条理、不容易被追问打乱节奏String最基础的类型value可以是字符串、数字或二进制数据。核心命令SET、GET、INCR、DECR、SETNX。应用场景包括对象缓存JSON序列化、计数器点赞数、库存、分布式ID、分布式锁的基础。这里要主动提一句INCR/DECR是原子操作底层依赖Redis单线程执行命令模型所以不会出现并发扣减超卖这是它比先GET再SET高明的地方。Hash适合存对象。HSET、HGET、HGETALL、HDEL可以单独读写某个字段。比如用户信息、商品详情用一个key表示对象字段表示属性。相比String存整个JSONHash最大的好处是修改单个字段不用把整个对象反序列化出来IO开销小很多。List双向链表结构。LPUSH、RPUSH、LPOP、RPOP、LRANGE、BLPOP。可以做简单的消息队列、最新消息列表、时间线。BRPOP/BLPOP是阻塞读这也是早期Redis实现简单队列的经典方式。注意List的索引访问是O(N)级别的别拿它当数组用。Set无序去重集合。SADD、SREM、SISMEMBER、SINTER、SUNION、SCARD。适用场景是去重、共同好友/共同关注交集运算、抽奖。这里有个容易被忽略的点SMEMBERS命令时间复杂度是O(N)集合很大时要小心面试官问到亿级用户关注列表怎么做交集你得能答出不能全量SINTER要分阈值处理或换思路。ZSet有序集合每个成员带一个score。ZADD、ZRANGE、ZREVRANGE、ZRANGEBYSCORE、ZINCRBY。排行榜、延迟队列、限流、滑动窗口全都靠它。这是五种类型里信息量最大的一个也是后续追问的爆破点。1.2 底层编码问题跳表为什么能平替红黑树数据类型答完面试官十有八九会追问底层ZSet的底层实现是什么为什么用跳表很多人在这里卡住因为只记了ZSet是有序集合就结束了。先拆结构ZSet由dict哈希表 skiplist跳表组成。dict负责存储成员和score的映射保证按成员O(1)查scoreskiplist负责按score排序。跳表是一个多层级链表通过随机晋升的方式让查询复杂度做到O(logN)。那为什么不用红黑树几个原因跳表实现更简单调试起来更容易跳表对范围查找特别友好ZRANGEBYSCORE这类操作天然适合跳表的多层链表结构红黑树要找范围得中序遍历相对麻烦跳表支持灵活的区间操作删除和插入策略也好控制。Redis作者自己也在注释里说过跳表实现比平衡树简单性能完全够用。面试能说到这个层次面试官会觉得你真的看过源码。除了ZSetString底层的SDS简单动态字符串也是高频考点。SDS和C字符串的区别主要有三点SDS有单独的len字段取字符串长度是O(1)SDS二进制安全可以存\0SDS有空间预分配和惰性空间释放机制减少内存重分配次数。为什么Redis要自己造一个字符串结构而不是直接用C的char*因为C字符串取长度要遍历、追加容易缓冲区溢出、还不能存二进制数据这在缓存场景下都是致命的。这个点可以类比Java里的ArrayList和StringBuilder的关系来理解。1.3 场景题拆解排行榜、延迟队列、限流基础面试的数据类型题通常以场景题收尾。我挑两个最高频的展开。排行榜题用Redis实现一个用户积分排行榜支持分数相同按先到先得排序。答案是ZSetscore存积分member存用户ID。分数相同怎么处理两种常见方案一是组合score法比如score 实际积分 (截止时间 - 时间戳) / 一个足够大的数让先到达的人排在前面二是直接用ZREVRANGE取排名Redis对相同score会按member的字典序排序如果member本身能表达先后顺序比如拼接上时间戳或序号就不用额外处理。ZRANGE相关操作的时间复杂度是O(log(N)M)Redis官方文档里可以查到回答时点一下复杂度会加分。延迟队列题订单下单后15分钟未支付自动关闭。经典实现是ZSetscore存到期时间戳member存订单ID用一个轮询任务不断ZRANGEBYSCORE取出score小于当前时间的所有订单逐个处理关闭逻辑。这里要提一嘴Redis的阻塞命令BLPOP实现不了延迟因为它是有数据就弹所以延迟队列用ZSet轮询是目前最主流的轻量方案。有候选人会问为什么不用定时任务扫数据库答案很明显ZSet轮询是O(logN)数据库全表扫可能O(N)量大了差距是数量级的。这两种题想考察的核心是你知不知道数据结构的核心特性以及能不能和业务场景对上号。答的时候不要只说用ZSet把score、member怎么设计复杂度多少边界情况怎么处理都说清楚分数自然就上去了。2. 持久化题RDB和AOF面试官要的是会权衡而不是会背概念2.1 先分清两种持久化的运作机制Redis持久化是基础面试必考题考察点在理解而不是记忆。很多候选人能说出RDB是快照、AOF是日志但问到重写过程会不会阻塞最多丢多少数据fork子进程有什么代价就卡壳。我给一套回答框架。RDBRedis DataBase把某一时刻的完整内存快照写入磁盘默认文件是dump.rdb。触发方式有手动触发save/bgsave和自动触发save m n配置比如save 900 1表示900秒内至少1次修改就触发。RDB的核心机制是fork一个子进程子进程负责写文件父进程继续服务。fork出来的子进程利用操作系统的COW写时复制Copy On Write机制把某一时刻的内存数据固化下来。AOFAppend Only File记录每一条写命令启动时重放日志恢复数据。AOF默认关闭需要配置appendonly yes。AOF的核心是追加写性能高有三种刷盘策略appendfsync决定了最多可能丢多少数据。此外AOF文件会越来越大所以有AOF重写机制用子进程重新生成一份最精简的日志文件把中间过程命令合并成最终结果命令。2.2 一个表把RDB和AOF讲透面试时用表格对比着讲信息密度高也方便面试官快速抓重点对比项RDBAOF数据格式二进制快照文本协议命令恢复速度快直接加载慢需要重放命令数据丢失范围取决于快照频率可能丢较多取决于appendfsync策略最多秒级对性能影响fork子进程写盘父进程基本无感追加写按策略fsync有磁盘IO文件大小压缩后较小通常较大需要重写是否便于排查不可读文本协议可读面试时主动提到生产环境通常两者都开而且Redis 4.0之后支持混合持久化会显得你不仅知道概念还知道它们怎么配合。单纯说RDB好或AOF好都是不对的正确的态度是按业务需求权衡。2.3 宕机丢数据这个追问绕不开面试官很爱问Redis宕机重启会丢多少数据答RDB由save配置决定。比如默认配置是save 900 1、save 300 10、save 60 10000意思是900秒内1次修改、300秒内10次修改、60秒内10000次修改满足任一条件就触发快照。极端情况下最后一次快照之后的所有写入都会丢可能是一分钟甚至更久的数据。所以RDB适合对数据丢失不太敏感、追求快速恢复的场景。答AOF取决于appendfsync策略。always是每个命令都fsync最多丢一个命令性能损失最大everysec是每秒fsync最多丢1秒数据性能和安全性权衡最好生产环境最常用no是交给操作系统决定什么时候落盘可能丢几秒甚至更多数据。答混合持久化Redis 4.0引入了aof-use-rdb-preamble配置开启后AOF文件前半段是RDB格式的完整快照后面追加增量命令。重启时先加载RDB部分快再重放少量增量命令准兼顾了恢复速度和少丢数据。Redis 7.0之后AOF文件进一步变成multi-part结构由manifest文件管理多个aof/rdb文件重写不再需要写临时文件再rename这也是一个很加分的进阶点。我补一个实际项目经验曾经遇到过AOF文件不断膨胀导致磁盘告警触发AOF重写时如果有大量并发写子进程写新AOF和主进程写原AOF同时存在磁盘IO压力大时可能造成主进程阻塞。7.0的multi-part manifest结构对这类问题改善很大面试时能把这个演进路径讲出来说明你不是背的。2.4 持久化配置里的几个易错点实操中配置持久化有几个坑面试也常被问只开RDB时要评估数据能接受的丢失窗口不要用默认save配置拍脑袋。比如业务对丢失1秒数据都受不了那必须开AOF everysec。fork操作什么时候会卡顿当Redis占用内存大、物理机CPU核数少时fork本身有耗时可能造成毫秒级卡顿。所以大实例要评估是否适合频繁bgsave这也是为什么有些团队会把RDB周期拉长把快速恢复的任务交给备份系统。AOF重写会fork子进程COW机制需要复制页表内存接近上限时可能触发内存超卖注意给系统留余量。云厂商的Redis如果做了持久化自己要搞清楚底层是RDB还是AOF有些默认配置和生产需求不匹配出问题再查就晚了。3. 缓存治理题穿透、击穿、雪崩到底怎么区分3.1 三个概念的一句话说清版本缓存三大问题是Redis面试的高频区但很多人会混淆。其实用一句话就能切分清楚缓存穿透查一个缓存和数据库里都不存在的key所有请求绕过缓存直接打到数据库。缓存击穿一个热点key在缓存过期的瞬间大量并发请求直接打到数据库。缓存雪崩大量key同时过期或者Redis实例宕机导致大量请求落到数据库。区别的关键词是穿透是这个key本来就不存在属于异常或恶意请求击穿是单个热key过期的瞬间是时间点上的竞争问题雪崩是一批key同时过期或整个缓存不可用是面状故障。这三个问题经常被混着考先把这个区别说清楚后面答方案才不会乱。3.2 穿透的完整应对方案缓存空值到布隆过滤器应对穿透最常用的两个方案缓存空值和布隆过滤器。缓存空值查询数据库后如果没查到也在缓存里写一个空值比如null并设置短过期时间比如60秒。这样同样的请求不会再穿透到数据库。但这个方案会引入一个新问题大量不存在的key被缓存占用内存。所以要根据业务控制空值缓存的过期时间甚至可以设一个独立的较短TTL并对不存在的key做数量上限控制。布隆过滤器在缓存前面加一层存在性判断。布隆过滤器用多个哈希函数把key映射到位数组上判断为不存在则直接返回判断为可能存在才继续走缓存和数据库。为什么是可能存在因为哈希冲突会导致误判布隆过滤器只能保证一定不存在和大概率存在。误判率通过位数组大小和哈希函数个数来控制一般可以做到1%以下。实际项目中通常在请求入口用布隆过滤器拦一层或者在数据库写入时同步更新过滤器。它的代价是需要额外维护一个Bloom结构不是所有场景都划算。还有一个容易忽略的补充方案参数合法性校验。比如用户ID必须符合规定格式非法参数直接拒绝。这虽然简单但能挡住很大一部分乱传参数造成的穿透面试时可以提显得你有防御性编程意识。3.3 击穿互斥锁与逻辑过期热点key过期的瞬间大量请求同时打到数据库解决思路有两个方向让并发请求之间互斥或者让key尽量不瞬时失效。互斥锁方案当缓存中没有数据时不让每个请求都去查数据库而是先尝试获取分布式锁。抢到锁的请求去查库并重建缓存其他请求短暂等待或返回默认值。Redis里可以用SET key value NX EX来实现锁。这个方案的缺点是引入额外延迟如果持锁线程异常挂了要靠锁的过期时间兜底所以过期时间不能设得太短也不能太长。逻辑过期方案缓存中不设置物理过期时间而是把业务数据 过期时间戳一起作为value存进去。读的时候发现逻辑过期了直接返回旧数据同时异步起一个线程去更新缓存。这个方案适合读多写少、能容忍短暂不一致的场景。面试时可以说它是用短暂的一致性问题换取可用性这是一个典型的trade-off说出来会显得你理解分布式系统的取舍。3.4 雪崩过期时间随机化是关键雪崩最常见的原因是同一时刻大量key过期。最经典的解法是设置过期时间时加随机值比如基础TTL是10分钟每个key再加0到300秒的随机偏移量让过期时间均匀散开。这个方案实现成本极低效果立竿见影。如果雪崩是因为Redis实例宕机那就要上升到高可用层面部署主从哨兵或Redis Cluster保证单点故障后能自动切换。还有多级缓存方案本地缓存比如Caffeine Redis缓存Redis不可用时本地缓存还能扛一波但要处理好本地缓存和Redis之间的一致性问题否则会出现脏数据。有个面试加分话术可以记住雪崩要从三方面防过期时间打散、服务高可用、降级限流兜底。这样回答会让面试官觉得你有架构思维而不是零散地背了几个方案。4. 分布式锁基础面试里最容易被追问深的配角4.1 SETNX到SET EX NX一条命令解决原子性Redis分布式锁几乎是基础面试必考题而且追问链条很长。第一问通常是怎么用Redis实现分布式锁。简单版本是SETNX加锁但面试官马上会追问setnx之后如果程序挂了锁没释放怎么办于是就有了SET key value EX seconds NX一条命令保证加锁和设置过期时间的原子性。这是分布式锁题目的第一个关键点加锁和设置过期时间必须原子。以前有人先SETNX再EXPIRE两步之间进程崩溃锁就永远不释放这属于会被面试官直接记错的错误答案。正确命令长这样SET lockKey uniqueValue NX EX 30NX表示key不存在时才设置成功EX 30表示过期时间是30秒两个参数同时用是因为Redis 2.6.12之后SET命令支持这两个选项旧版本才需要靠Lua脚本解决。4.2 释放锁为什么不能简单用DEL第二个关键点是释放锁。很多人第一反应是DEL但这里有一个经典的并发问题线程A加锁后执行时间比较久锁因为过期自动释放了线程B拿到同一把锁开始执行。这时线程A执行完了调DEL把线程B的锁给删了锁形同虚设。解决办法有一个标准套路value设置成一个唯一标识比如UUID或请求ID释放锁前先GET比较value是不是自己的再DEL。但这里又有一个陷阱GETDEL是两步操作不是原子的。假设线程A执行完了先GET判断是自己的值还没来得及DEL锁刚好过期线程B加锁成功线程A再执行DEL删掉的就是线程B的锁。所以必须用Lua脚本把比较删除合并成一个原子操作脚本如下if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end这个脚本是分布式锁面试的标配答案建议直接背下来。实际项目中用Redisson的RLock内部已经实现了这套逻辑但面试时能默写出这段Lua脚本效果完全不同。4.3 Redisson看门狗机制给锁自动续期答到这里面试官通常会顺着问业务执行超过锁的过期时间怎么办比如锁过期时间设了30秒但执行业务要50秒锁在30秒时被自动释放另一个线程就能拿到锁两个线程同时跑分布式锁名存实亡。Redisson解决了这个问题加锁后后台会启动一个定时任务称为看门狗watchdog。默认锁的leaseTime是30秒看门狗每10秒leaseTime / 3检查一次如果锁还在就把过期时间续到30秒。业务执行完主动释放锁看门狗也随之取消。如果进程宕机看门狗线程死了锁最多30秒自动释放不会死锁。这个机制的本质是用一个后台线程给锁续命既防止业务没执行完锁就过期又防止宕机后锁永久不释放。基础面试能讲到这个层次就已经超过大多数人。记住三个数字默认30秒每10秒续一次看门狗就是定时续期的调度器。4.4 延伸追问主从切换锁会丢怎么办能问到这一步的面试官已经不满足于基础API而是想看你对分布式系统问题的敏感度。大厂面试官常问上面这套锁在哨兵模式下主节点宕机、从节点升主锁会怎样答案是锁可能丢失。因为Redis主从复制是异步的线程A在主节点写入锁主节点还没来得及把数据复制给从节点就宕机了哨兵把从节点提升为主节点此时新的主节点上没有这把锁线程B就能加锁成功两个线程同时持有锁分布式锁的互斥性被破坏。业界方案有RedLock红锁向多个独立Redis节点同时加锁超过半数节点成功才算加锁成功。但RedLock本身有争议很多架构师并不推荐原因是它在极端场景下依然不严格安全而且部署复杂度高。基础面试里你能清楚地分析出异步复制导致锁丢失的原因已经能拿到这题的分数如果能补充一句如果要严格保证互斥需要在业务侧做幂等或引入更强一致性的协调服务那就更出彩了。5. 高可用题主从、哨兵、集群这样讲才显档次5.1 主从复制全量同步和增量同步Redis高可用要从主从复制说起。一台主节点负责写多台从节点负责读读写分离可以缓解读压力同时为故障转移做准备。面试常问主从复制的同步过程是什么样的分两种情况。全量同步发生在从节点第一次连接主节点或者复制中断严重时。主节点fork子进程生成RDB快照发给从节点从节点加载同时主节点把新写入的命令缓存到repl_backlog缓冲区之后再同步给从节点。这个过程对主节点有一定性能开销所以不要让从节点频繁断线重连。增量同步复制断线恢复后主从通过各自维护的复制偏移量offset和复制积压缓冲区repl_backlog只同步缺失的部分。这里有个高频考点如果从节点断线时间太长主节点的repl_backlog缓冲区被新数据覆盖了从节点就要重新做全量复制。所以缓冲区的大小配置要根据网络稳定性来设置。如果面试官问docker部署主从有什么坑你要能点出容器重启后run_id会变化可能导致从节点触发全量复制所以生产环境部署时要固定节点身份这也是很多人用docker部署主从后性能莫名其妙下降的原因。5.2 哨兵监控、通知、故障转移三件事主从复制解决了读写压力但主节点挂了不会自动切换需要人工干预。哨兵Sentinel解决的就是自动故障转移。哨兵的作用概括成三件事监控不停检查主从节点是否存活。通知节点故障时通知其他节点和管理员。故障转移主节点挂了从从节点中选一个提升为新主节点改配置通知其他从节点复制新主。哨兵的高频考点是主观下线subjectively down和客观下线objectively down。单个哨兵发现自己联系不上主节点这叫主观下线多个哨兵通过sentinel is-master-down-by-addr命令相互确认都认为主节点挂了达到quorum数量后就叫客观下线此时才会真正触发故障转移。这个设计是为了避免单个哨兵网络抖动导致的误判quorum的取值一般是哨兵数量的一半以上生产环境通常部署3个哨兵节点。另一个高频考点是哨兵选新主节点的依据先看从节点的优先级slave-priority配置值越小越优先再看复制偏移量数据越新越优先最后看run_id值越小越优先。答出这个顺序面试官就知道你是真的理解故障转移过程而不是只背了概念。5.3 Redis Cluster为什么用哈希槽而不是一致性哈希当单机内存和写入量到瓶颈时就需要Redis Cluster做水平扩展。Redis Cluster把整个数据空间划分为16384个槽key通过CRC16(key) mod 16384计算属于哪个槽槽再分配给不同的节点客户端访问时路由到对应节点。很多人分不清哈希槽和一致性哈希的区别。一致性哈希是每个key哈希后落在环上按顺时针找最近的节点节点增减只影响少量key但可能出现数据倾斜。哈希槽则是固定16384个槽位key映射到槽槽映射到节点节点增减时只需要迁移槽以及槽内的key不需要重新哈希全部数据槽粒度也方便做负载均衡。Cluster相关的面试常考点为什么是16384个槽官方解释提到几个原因心跳包要带完整的槽位信息16384个槽的位图大小约2KB消息体可控节点规模设计上限是1000个节点左右16384足够了槽数量足够多时数据分布更均匀。客户端访问某个key时key不在当前节点会返回MOVED错误客户端要重新路由到正确节点。这也是为什么很多Redis客户端库都要维护槽位路由表。批量操作mget在key跨槽时会失败所以设计key时要考虑哈希标签hash tag让相关key落到同一槽。Cluster模式下每个主节点可以配从节点形成主从结构保证故障转移。数据迁移按槽为单位进行可以在线扩容缩容。5.4 选型判断单机、主从哨兵、Cluster怎么选面试里经常出场景题你们公司数据量多大用了什么架构这就要求你会选型而不是只会背架构名称。数据量小比如几十GB以内、QPS中等、能容忍小时级故障单机Redis加上持久化和备份恢复成本最低运维最简单。数据量中等、QPS高、需要自动故障转移主从3个哨兵节点读写分离这是最常见的小规模生产架构。默认读操作走从节点写操作走主节点从节点挂了一个仍有余量。数据量大比如几百GB甚至上TB、需要水平扩展Redis Cluster按槽迁移支持在线扩容缩容但客户端逻辑和运维复杂度都会明显上升。这里可以补充一个实际经验不是所有业务都适合上Cluster有些团队几台机器就够用为了上集群而上集群反而会引入key迁移、批量操作限制、客户端路由维护等一堆麻烦。面试时能说出根据数据量、QPS、可用性要求做权衡比直接说我们直接上Cluster评分高得多。6. 实战细节基础面试里容易翻车的Redis操作与序列化问题6.1 RedisTemplate序列化为什么可视化工具里看到一堆乱码Java面试几乎必考Spring Data Redis最经典的翻车现场是用RedisTemplate存数据在Redis Desktop Manager里看到key变成\xac\xed\x00\x05t\x00开头的一串乱码。原因很简单RedisTemplate默认使用JdkSerializationRedisSerializer序列化key和value。Java原生序列化会把对象变成一段带类型信息的二进制流key自然就不是你写的字符串了。这不仅影响可视化查看还影响跨系统读取因为其他语言根本无法解析Java的序列化格式。解决办法是显式设置序列化器RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(connectionFactory); // key用String序列化器 template.setKeySerializer(new StringRedisSerializer()); // value用JSON序列化器 template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet();面试中要能说清为什么key和hashKey用Stringvalue用JSON。核心原因是key需要人类可读、跨语言可读String序列化最合适value可能需要存储复杂对象JSON序列化在兼容性和可读性上都有优势。另外注意用GenericJackson2JsonRedisSerializer时value里会多出一个class字段用于反序列化时还原类型但也意味着反序列化不可信来源的JSON时要有类型校验意识防止安全隐患。6.2 increment报错not integer or out of range的真相热搜词里出现频率很高的一个报错是使用RedisTemplate的increment()时报not integer or out of range。这个错表面看是值不是整数实际排查时原因往往更隐蔽。最常见场景value被默认的JdkSerializationRedisSerializer序列化成了二进制increment内部尝试把已存在的值转成Long读出来的是一段Java序列化后的字节数组自然解析失败。第二个场景value被GenericJackson2JsonRedisSerializer序列化成了带引号的JSON字符串在Redis里看到的是10而不是10。Redis的INCR命令要求key的值必须是字符串形式的十进制整数引号会导致转换失败。第三个场景值本身不是整数格式比如存了带小数点的字符串、带空格的字符串、或者根本不是数字。我的排查思路是先看这个key在Redis里的原始值长什么样用redis-cli GET看。如果是乱码查序列化器配置如果是带引号调整序列化器或者改用StringRedisTemplate。检查写入数据的代码确认写入的确实是没有引号、没有小数点的整数。如果项目里同时用了多个RedisTemplate实例确认操作同一个key时用的序列化器是一致的否则很容易出现存得进去、读不出来的问题。还有一个高频报错是java中使用Redistemplate将Redis的数减一本质就是increment(key, -1)的用法。很多人不知道increment传负数就是减一会先GET再SET两个非原子操作之间如果有并发请求就会出现数据不一致。面试主动提这个点能一下展示出你对原子性的理解深度。6.3 可视化客户端与基础操作习惯关于Redis Desktop Manager、Another Redis Desktop Manager这类可视化工具基础面试偶尔会问你们平时怎么连Redis。我的看法是工具层面谁顺手用谁但面试时不要停留在我会用可视化工具重点是我会用redis-cli排查问题。工具上Redis Desktop Manager早先免费后来商业化现在很多人转向Another Redis Desktop Manager或者Redis官方出的Redis Insight都能满足浏览key、看TTL、执行命令的需求。可视化工具的好处是直观但真到线上排障时还是命令最可靠。我实际工作中最常用的几个命令习惯redis-cli -a 密码 --no-auth-warning避免明文密码告警。redis-cli --bigkeys找大key很多缓存问题最后都定位到大key导致的阻塞。redis-cli --hotkeys找热点key配合缓存击穿分析很有用。INFO memory看内存碎片率INFO stats看命中率。用SCAN而不是KEYS *生产环境执行KEYS会阻塞Redis因为它是O(N)的全量扫描。SCAN是游标式非阻塞分批遍历但SCAN可能返回重复key需要客户端去重。这个知识点本身也是高频面试题。另外提一个安全习惯生产环境要设置密码requirepass并把FLUSHALL、KEYS这类危险命令通过rename-command重命名或禁用。未授权访问导致数据库被清空、被写入恶意数据的事件每年都有基础面试问到底层配置时能主动说出安全配置也是加分项。最后说点我自己的体会。面了这么多人我发现Redis基础面试题答得好的人有一个共同点不是死记命令而是结合项目讲过我为什么用它这个问题在什么业务背景下出现我当时是怎么排查的。所以准备时我建议每道题都套一个自己的真实场景或者贴近场景的伪代码答出来才有说服力。如果你现在时间有限优先把数据类型、持久化、缓存三大问题、分布式锁这四块过一遍它们出现频率最高。主从、哨兵、集群最好能自己画一遍启动流程和故障转移流程不一定画给别人看自己画得出来说明真的懂了。另外可以本地搭一个Redis写一个Java或Go的demo把序列化乱码问题和increment报错亲手复现一次印象会比看十篇文章都深。祝面试顺利。
返回列表