Redis 之 【常见面试题总结】(从数据类型到高可用、缓存一致性全解析)

目录

[1. 面试考点地图](#1. 面试考点地图)

[2. Redis 基础认知](#2. Redis 基础认知)

[2.1. 什么是 Redis?有什么特点?](#2.1. 什么是 Redis?有什么特点?)

[2.2. Redis 为什么把数据放到内存中](#2.2. Redis 为什么把数据放到内存中)

[2.3. Redis 常见应用场景](#2.3. Redis 常见应用场景)

[3. 数据类型与底层编码](#3. 数据类型与底层编码)

[3.1. Redis 支持哪些数据类型](#3.1. Redis 支持哪些数据类型)

[3.2. 底层数据结构和编码方式](#3.2. 底层数据结构和编码方式)

[3.3. ZSet 为什么用跳表,不用红黑树](#3.3. ZSet 为什么用跳表,不用红黑树)

[4. 线程模型与网络 IO](#4. 线程模型与网络 IO)

[4.1. Redis 为什么是单线程模型](#4.1. Redis 为什么是单线程模型)

[4.2. Redis 的 IO 多路复用是怎么回事](#4.2. Redis 的 IO 多路复用是怎么回事)

[5. 持久化机制](#5. 持久化机制)

[5.1. RDB](#5.1. RDB)

[5.2. AOF](#5.2. AOF)

[5.3. AOF 重写机制](#5.3. AOF 重写机制)

[5.4. RDB 和 AOF 如何选择](#5.4. RDB 和 AOF 如何选择)

[6. 过期、淘汰与内存管理](#6. 过期、淘汰与内存管理)

[6.1. 如何设置 key 过期时间](#6.1. 如何设置 key 过期时间)

[6.2. Redis 的 key 过期删除策略](#6.2. Redis 的 key 过期删除策略)

[6.3. 大量 key 同时过期会怎样](#6.3. 大量 key 同时过期会怎样)

[6.4. Redis 淘汰策略](#6.4. Redis 淘汰策略)

[7. 高可用:主从、哨兵、集群](#7. 高可用:主从、哨兵、集群)

[7.1. 主从复制](#7.1. 主从复制)

[7.2. 哨兵 Sentinel](#7.2. 哨兵 Sentinel)

[7.3. Redis Cluster 集群](#7.3. Redis Cluster 集群)

[7.4. 一致性哈希](#7.4. 一致性哈希)

[8. 事务、Pipeline 与消息队列](#8. 事务、Pipeline 与消息队列)

[8.1. Redis 事务](#8.1. Redis 事务)

[8.2. Pipeline](#8.2. Pipeline)

[8.3. Redis 作为消息队列](#8.3. Redis 作为消息队列)

[9. 缓存与分布式实战](#9. 缓存与分布式实战)

[9.1. 分布式锁](#9.1. 分布式锁)

[9.2. 缓存穿透、雪崩、击穿](#9.2. 缓存穿透、雪崩、击穿)

[9.3. 热 key 问题](#9.3. 热 key 问题)

[9.4. Redis 和 MySQL 双写一致性](#9.4. Redis 和 MySQL 双写一致性)

[9.5. bigkey 问题](#9.5. bigkey 问题)

[10. 运维、协议与高级命令](#10. 运维、协议与高级命令)

[10.1. 测试连通性](#10.1. 测试连通性)

[10.2. 常用管理命令](#10.2. 常用管理命令)

[10.3. 为什么生产禁用 KEYS *](#10.3. 为什么生产禁用 KEYS *)

[10.4. Redis 网络协议](#10.4. Redis 网络协议)

[10.5. 查找附近的人](#10.5. 查找附近的人)

[11. 面试速查表](#11. 面试速查表)


1. 面试考点地图

Redis 面试通常围绕以下主线展开:

  1. 基础认知:是什么、为什么快、为什么放内存、应用场景
  2. 数据类型:String、List、Hash、Set、ZSet,以及 Bitmap、HyperLogLog、GEO、Stream
  3. 底层编码:raw、int、embstr、ziplist、listpack、quicklist、hashtable、intset、skiplist
  4. 线程模型:单线程、6.0 多线程、IO 多路复用、epoll
  5. 持久化:RDB、AOF、混合持久化、AOF 重写
  6. 内存管理:过期删除、淘汰策略、内存用尽
  7. 高可用:主从复制、哨兵、集群、哈希槽、一致性哈希
  8. 功能特性:事务、Pipeline、消息队列、分布式锁
  9. 缓存实战:穿透、雪崩、击穿、热 key、bigkey、双写一致性
  10. 运维与协议:常用命令、RESP、SCAN、GEO

面试时不要只背答案,最好按"结论 → 原理 → 场景 → 权衡 → 版本差异"回答

2. Redis 基础认知

2.1. 什么是 Redis?有什么特点?

Redis 是一个高性能的key-value内存数据库。它不同于 MySQL 这类关系型数据库:

  • 数据主要存储在内存中,也支持持久化到硬盘
  • 不使用"表"组织数据,而是使用键值对
  • 没有复杂查询、外键、事务隔离级别等关系型数据库能力,换来的是简单、灵活和高性能

Redis 的典型特点:

  • 内存存储,性能极高
  • 支持多种数据结构
  • 支持持久化:RDB、AOF
  • 核心命令执行是单线程模型
  • 支持主从复制、哨兵、集群
  • 支持事务、Lua 脚本、Pipeline
  • 支持多语言客户端
  • 支持发布订阅、Stream 消息队列
  • 高版本支持多线程网络 IO

Redis 本质是一个基于内存的 KV 数据库,常用于缓存、计数器、排行榜、分布式锁、消息队列等场景。它的核心优势是快,原因是内存访问、单线程无锁、IO 多路复用、高效数据结构。缺点主要是内存成本高、容量有限、持久化和主从复制存在一致性权衡

2.2. Redis 为什么把数据放到内存中

核心原因是 效率

内存随机访问大约 100ns,硬盘随机访问大约 10,000,000ns,差距 3 到 4 个数量级。因此 Redis 比 MySQL 等磁盘数据库有显著性能优势

但内存存储也有劣势:

  • 内存容量比硬盘小,成本更高
  • 掉电易失,所以需要 RDB/AOF 持久化
  • 数据量受内存限制,需要淘汰策略和集群分片

2.3. Redis 常见应用场景

  • 缓存:热点数据缓存,降低数据库压力
  • 计数器:点击量、访问量、收藏数
  • 排行榜:基于 ZSet 实现
  • 分布式会话:多模块共享 Session
  • 分布式锁:SET NX + 过期时间 + Lua 释放
  • 消息队列:List、Pub/Sub、Stream
  • 附近的人:GEO
  • 签到、UV 统计:Bitmap、HyperLogLog
  • 限流:计数器、滑动窗口、令牌桶

3. 数据类型与底层编码

3.1. Redis 支持哪些数据类型

类型 说明 典型场景
String 字符串、整数、二进制 缓存、计数器、分布式锁
List 双向列表 消息队列、时间线
Hash 哈希表 对象属性、购物车
Set 无序集合 去重、共同好友、标签
ZSet 有序集合 排行榜、延迟队列

扩展类型:

  • Bitmap:二进制位,适合签到、活跃用户统计
  • Bitfield:把字符串当位图并进行位操作
  • HyperLogLog:基数统计,用极小内存估算 UV,有误差
  • Geospatial:地理经纬度,支持附近查询
  • Stream:消息队列,支持消费组、ACK、持久化

前五种是通用类型,后几种是特定场景类型

3.2. 底层数据结构和编码方式

Redis 会根据数据量、元素长度、版本自动选择编码。常用查看命令:

复制代码
object encoding key

常见对应关系:

数据类型 内部编码
String int、embstr、raw
Hash ziplist/listpack、hashtable
List ziplist、linkedlist、quicklist
Set intset、hashtable、listpack
ZSet ziplist/listpack、skiplist

关键点:

  • int:字符串是整数且范围合适时,直接存整数
  • embstr:短字符串优化,通常小于等于 39 字节
  • raw:长字符串
  • ziplist:压缩列表,本质是字节数组,省内存,但增删可能连锁更新
  • listpack:Redis 7 开始引入,用来替代 ziplist,解决连锁更新问题
  • quicklist:链表,每个节点是 ziplist/listpack,兼顾内存和性能
  • hashtable:真正哈希表,O(1) 查找
  • intset:整数集合,适合小整数集合
  • skiplist:跳表,支持 O(logN) 查找、插入、删除和范围查询

3.3. ZSet 为什么用跳表,不用红黑树

跳表和红黑树的插入、查询、删除复杂度都是 O(logN),但 Redis 选择跳表:

  • 跳表实现更简单,代码可维护性高
  • 跳表不需要红黑树那样的旋转和重新平衡
  • 跳表天然支持范围查询,ZRANGE、ZREVRANGE 更方便
  • 跳表可以通过概率平衡,实现难度低
  • Redis 是单线程,简单稳定比极致复杂更重要

跳表不会像普通链表那样退化,因为层级通过随机函数生成,期望复杂度 O(logN)

4. 线程模型与网络 IO

4.1. Redis 为什么是单线程模型

Redis 的主要瓶颈通常不是 CPU,而是 内存 和 网络 IO。使用多线程不会带来太大收益,反而引入线程安全、锁竞争、上下文切换问题

单线程的好处:

  • 命令串行执行,天然避免并发安全问题
  • 不需要复杂锁机制
  • 实现简单,行为可预测
  • 配合 IO 多路复用,可以高效处理大量连接

Redis并不是完全单线程。它通过后台线程或子进程来处理一些耗时任务:

  • 持久化:通过fork()创建子进程进行RDB快照和AOF重写
  • 异步删除:使用UNLINK等命令,由后台线程负责回收内存
  • AOF刷盘:在默认的everysec策略下,fsync操作由后台线程执行;若设为always,则由主线程同步执行
  • 网络I/O(Redis 6.0+):使用多个I/O线程并行处理网络请求和协议解析,但命令执行仍是单线程

4.2. Redis 的 IO 多路复用是怎么回事

"IO 多路复用"就是用一个线程管理多个 socket,按需激活处理。

传统"一连接一线程"模式下,大量连接可能大部分时间不活跃,线程都在挂起,浪费资源。Redis 使用 Linux 的 epoll:

  • 内核维护红黑树管理所有 socket
  • 每个节点关联事件回调
  • 网卡收到数据后,内核判断属于哪个 socket,触发回调,唤醒用户线程
  • Redis 线程处理就绪的请求

Linux IO 多路复用三种实现:

  • select:最早,有文件描述符数量限制
  • poll:链表实现,没有数量限制,但仍需轮询
  • epoll:最先进,事件驱动,适合高并发

Redis 高并发不是因为多线程,而是因为单线程 + epoll + 内存操作 + 高效数据结构

Redis 的高效数据结构,指的是它为不同数据类型定制的底层编码:String 用 SDS,支持 O(1) 长度获取和二进制安全;Hash 用 dict + 渐进式 rehash,小数据量时用 listpack/ziplist 压缩存储;List 用 quicklist,兼顾内存和操作效率;Set 用 intset 或 dict;ZSet 用 listpack + skiplist,兼顾排序和范围查询;还有 rax、HyperLogLog、GEO 等专用结构。它们通过紧凑内存布局、按数据量自动切换编码、减少指针和内存碎片、提供 O(1)/O(log N) 操作,让 Redis 在单线程下也能以极低 CPU 和内存开销处理海量请求

5. 持久化机制

Redis 持久化主要有两种:RDB 和 AOF。Redis 4.0 后支持混合持久化

5.1. RDB

RDB 是内存快照,把某一时刻数据以二进制写入磁盘

触发方式:

  • 手动:SAVE、BGSAVE
  • 自动:
    • 配置 save m n:m 秒内发生 n 次修改触发
    • 从节点全量复制触发
    • 执行 SHUTDOWN 关闭 Redis 时触发

区别:

  • SAVE:阻塞主线程,期间无法处理写请求
  • BGSAVE:fork 子进程生成 RDB,父进程继续处理请求
  • 子进程写 RDB 期间,新写入数据不一定进入当前 RDB,需要下一轮持久化

优点:文件紧凑、恢复快、适合备份

缺点:可能丢数据,fork 有开销

5.2. AOF

AOF 记录写命令,重启时重放命令恢复数据

AOF 同步策略:

策略 说明 丢失风险
always 每条命令 fsync 后返回 几乎不丢,但性能差
everysec 先 write,每秒 fsync 最多丢 1 秒
no 只 write,由 OS 控制 fsync 丢失可能较多

5.3. AOF 重写机制

AOF 文件会越来越大,需要重写压缩,过程简述:

  1. 触发 BGREWRITEAOF 或自动重写
  2. fork 子进程,根据当前内存数据生成新 AOF
  3. 主进程继续处理命令,同时写入 AOF 重写缓冲区
  4. 子进程完成后,主进程把重写期间新命令追加到新 AOF
  5. 用新 AOF 替换旧 AOF

AOF 重写会阻塞吗?

fork 瞬间可能阻塞,之后子进程重写,主进程继续服务

但 fork 成本与内存页表有关,内存越大越慢

5.4. RDB 和 AOF 如何选择

  • 只做缓存:可以只开 RDB 或不开
  • 数据不能丢太多:AOF everysec + RDB
  • 恢复速度优先:RDB
  • 数据安全优先:AOF
  • 生产常见:混合持久化,RDB 快照 + AOF 增量

6. 过期、淘汰与内存管理

6.1. 如何设置 key 过期时间

复制代码
SET key value EX 60
SET key value PX 60000
EXPIRE key 60
PEXPIRE key 60000

EX 是秒,PX 是毫秒。也可以单独用 EXPIRE

6.2. Redis 的 key 过期删除策略

Redis 同时使用:

  • 惰性过期:访问 key 时才判断是否过期,过期则删除。省 CPU,但可能浪费内存
  • 定期过期:每隔 100ms 随机抽取一定数量 key 检查删除。CPU 和内存折中

expires 字典保存所有设置了过期时间的 key 及其过期时间

6.3. 大量 key 同时过期会怎样

如果大量 key 在同一时间过期,Redis 可能短暂卡顿,原因:

  • 定期采样删除时,如果过期 key 比例超过 25%,会持续删除,直到最大耗时 25ms
  • 对高并发场景,25ms 阻塞也可能造成抖动

解决方案:

  • 过期时间加随机值,打散过期点
  • 业务允许时,不必精确到毫秒
  • 监控过期 key 数量,避免集中过期

6.4. Redis 淘汰策略

当内存不足,继续写入会触发淘汰策略:

策略 说明
volatile-lru 从设置了过期时间的 key 中按 LRU 淘汰
allkeys-lru 从所有 key 中按 LRU 淘汰
volatile-lfu 从过期 key 中按 LFU 淘汰,4.0+
allkeys-lfu 从所有 key 中按 LFU 淘汰,4.0+
volatile-random 从过期 key 中随机淘汰
allkeys-random 从所有 key 中随机淘汰
volatile-ttl 从过期 key 中优先淘汰更早过期的
noeviction 默认,不淘汰,写入报错

LRU:最近最久未使用

LFU:最近使用频率最低

  • 默认 noeviction 能暴露问题,但很多缓存场景会用 allkeys-lru
  • 如果数据重要,不要用 allkeys-*
  • 应该有监控报警,内存接近上限就扩容
  • Redis 内存耗尽时,会触发淘汰;noeviction 下写入报错

7. 高可用:主从、哨兵、集群

7.1. 主从复制

作用:

  • 提高可用性,主节点挂了可以从节点读

  • 分担读压力,主写从读

    配置: slaveof master_ip master_port

    或配置文件 replicaof

流程:

  • 从节点启动后清空自身数据,全量复制主节点数据
  • 后续主节点写命令同步到从节点
  • 主节点可读写,从节点默认只读

优点:读扩展、数据备份

缺点:主节点故障需要手动或哨兵切换;异步复制可能丢数据

7.2. 哨兵 Sentinel

哨兵解决主从故障自动切换

功能:

  • 监控主从节点
  • 主观下线、客观下线
  • 选举 Leader 哨兵
  • 从从节点中选新主
  • 通知客户端新主地址
  • 继续监控

主节点宕机后:

  1. 单个哨兵认为主下线,是主观下线
  2. 多个哨兵确认,是客观下线
  3. 哨兵选举 Leader
  4. Leader 选择合适从节点提升为主
  5. 其他从节点指向新主
  6. 通知客户端

7.3. Redis Cluster 集群

集群用于分片存储,解决单机内存和性能上限

特点:

  • 数据分片,每个主节点负责一部分槽
  • 共有 16384 个哈希槽
  • 槽计算:CRC16(key) mod 16384
  • 至少 3 主 3 从,主从保证高可用
  • 支持 MOVED、ASK 重定向
  • 不支持 SELECT 多数据库,只能使用 db0
  • 异步复制,特定条件下可能丢写

最大节点数:作者建议不要超过 1000 个,不是硬限制

7.4. 一致性哈希

一致性哈希用于分布式缓存分片

原理:

  • 把哈希值空间组织成环
  • 节点和数据都映射到环上
  • 数据顺时针找到第一个节点
  • 增加虚拟节点解决数据倾斜

优点:扩缩容时只影响相邻数据,迁移量小

缺点:实现复杂,需要虚拟节点,仍有倾斜可能

Redis Cluster 没有用一致性哈希,而是用哈希槽,因为槽更易管理、迁移和重新分配

8. 事务、Pipeline 与消息队列

8.1. Redis 事务

相关命令:

  • MULTI:开启事务
  • EXEC:执行事务
  • DISCARD:取消事务
  • WATCH:乐观锁,监视 key

特点:

  • 命令入队,EXEC 时按顺序执行
  • 不支持回滚。运行时错误,其他命令仍可能继续执行
  • 不是 MySQL 那种强原子、隔离级别、回滚事务
  • 更像"命令打包串行执行"
  • WATCH 可实现乐观锁,若 key 被修改则 EXEC 失败

和 MySQL 区别:

维度 Redis MySQL
原子性 弱,不支持回滚 强,支持回滚
隔离性 单线程串行 多隔离级别
持久性 取决于持久化 取决于日志和配置
复杂度 简单 复杂

8.2. Pipeline

Pipeline 把多个命令合并到一个请求发送,减少 RTT

普通模式:

复制代码
发送命令 -> 排队 -> 执行 -> 返回
发送命令 -> 排队 -> 执行 -> 返回

Pipeline:

复制代码
发送多个命令 -> 排队 -> 执行 -> 一次性返回

注意:

  • Pipeline 命令 不是原子的
  • 只是节省网络往返
  • 命令太多可能阻塞服务器
  • 可用 cat cmd.txt | redis-cli --pipe

8.3. Redis 作为消息队列

三种方式:

  1. List:LPUSH/RPUSH 生产,BLPOP/BRPOP 阻塞消费
  2. Pub/Sub:发布订阅,但不持久化,消费者离线会丢消息
  3. Stream:Redis 5 引入,支持消费组、ACK、持久化,功能更完整

Redis Pub/Sub 是发布订阅模式,用 PUBLISH 发消息,SUBSCRIBE 订阅频道,PSUBSCRIBE 模式订阅。它的特点是实时推送,但不持久化、不存储、无 ACK,消费者离线就丢消息,投递语义是至多一次。所以它只适合实时通知、广播这类场景,不能当可靠消息队列用。可靠消息一般用 Redis Stream 或者 Kafka/RabbitMQ。Sentinel 内部就用 Pub/Sub 来互相通知

9. 缓存与分布式实战

9.1. 分布式锁

基本实现:

复制代码
SET lock_key unique_value NX PX 30000

释放锁要用 Lua 保证原子:

复制代码
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

要点:

  • value 必须唯一,防止误删别人的锁
  • 必须设置过期时间,防止死锁
  • 释放锁必须原子
  • 业务未完成可续期,看门狗机制
  • 主从切换可能丢锁,强一致场景考虑 Redlock 或 ZooKeeper
  • Redlock 有争议,面试可提"多数派加锁,但时钟漂移和网络延迟仍有挑战"

Redlock 是 Redis 作者提出的分布式锁算法:部署多个独立 Redis 节点,客户端在多数派节点上加锁成功才认为获取锁,以此提高可靠性。但它依赖各节点本地时钟判断锁过期,并假设网络延迟有界;时钟漂移、GC 停顿、网络抖动都可能导致锁提前失效,或客户端在锁已过期后仍误以为自己持有锁,从而破坏互斥。因此 Redlock 无法保证绝对安全,业界对其争议较大
ZooKeeper 和 etcd 都是分布式协调服务,核心是在分布式环境中提供强一致、高可用的元数据存储与协调能力。ZooKeeper 基于 ZAB 协议,通过 ZNode 树、临时顺序节点和 Watch 实现分布式锁、选主、服务发现和配置管理;etcd 基于 Raft 协议,提供键值存储、租约 Lease、Watch 和事务,是 Kubernetes 的核心数据存储。两者都依赖多数派共识,不依赖物理时钟来判断锁安全,因此在强一致要求的分布式锁、选主等场景中,比 Redis Redlock 更可靠。区别上,ZooKeeper 较老、Java 生态常用;etcd 更轻量、云原生生态更主流。

9.2. 缓存穿透、雪崩、击穿

问题 含义 解决方案
缓存穿透 查不存在的数据,请求打到 DB 缓存空值、布隆过滤器、参数校验
缓存雪崩 大量 key 同时过期或 Redis 宕机 随机过期、多级缓存、限流熔断、集群
缓存击穿 热点 key 过期,大量请求打到 DB 互斥锁、逻辑过期、永不过期、后台更新

9.3. 热 key 问题

某些 key 访问频率极高,可能打挂 Redis。集群下,热 key 仍在同一分片,其他分片帮不上忙

解决:

  • 扩大集群,增加热 key 所属分片的从节点
  • 应用层识别热 key,做二次哈希,拆成多个 key
  • 热 key 单独部署 Redis 集群
  • 使用本地缓存,减少 Redis 压力
  • 限流、降级、熔断

9.4. Redis 和 MySQL 双写一致性

双写一致性指修改数据库时,也要更新或删除缓存,否则缓存可能是脏数据

方案一:延时双删

  1. 先删除缓存
  2. 更新数据库
  3. 再次删除缓存

目的:第一次删除失败,第二次兜底

因为直接改缓存可能并发覆盖,不如删除缓存,后续读时从 DB 加载

方案二:删除缓存重试

  • 删除失败把 key 放入 MQ,反复重试
  • 可用阿里 canal 订阅 MySQL binlog,异步删除缓存

binlog 订阅是指通过 Canal、Debezium、Maxwell 等工具伪装成 MySQL 从库,向主库发送 dump 协议请求,实时接收并解析 binlog,从而捕获数据库的增删改操作。在缓存一致性场景中,应用更新数据库后,订阅程序监听到对应变更事件,再异步删除或更新缓存,避免业务代码耦合双写,实现最终一致;此外也常用于数据同步、审计、搜索索引更新等。

方案三:先更新 DB,再删缓存

这是常见 Cache Aside 模式

Cache Aside 是旁路缓存模式,应用先读缓存,未命中查数据库并回填;写时先更新数据库,再删除缓存。它简单常用,能保证最终一致,但并发下可能短暂脏读,可通过延迟双删、binlog 订阅、过期时间兜底

9.5. bigkey 问题

bigkey 指 value 占用空间过大,比如超长字符串、超大 Hash/Set/List

危害:

  • 读写慢,阻塞 Redis
  • 网络拥塞
  • 集群数据倾斜
  • 删除时可能阻塞

解决:

  • 拆分大 key 为多个小 key
  • 用 redis-cli --bigkeys 查找
  • 删除用 UNLINK,后台异步删除
  • 集合遍历用 HSCAN、SSCAN、ZSCAN

10. 运维、协议与高级命令

10.1. 测试连通性

复制代码
PING

返回 PONG 即连通

10.2. 常用管理命令

复制代码
DBSIZE                 # 当前数据库 key 数量
INFO                   # 服务器状态和统计
MONITOR                # 实时监听请求
SHUTDOWN               # 保存并关闭
CONFIG GET parameter   # 获取配置
CONFIG SET parameter value
DEBUG OBJECT key       # 查看 key 调试信息
DEBUG SEGFAULT         # 制造宕机,慎用
FLUSHDB                # 删除当前库,慎用
FLUSHALL               # 删除所有库,慎用

10.3. 为什么生产禁用 KEYS *

KEYS * 会遍历所有 key,数据量大时耗时极长,甚至阻塞 Redis,导致生产故障

替代:SCAN

复制代码
SCAN cursor [MATCH pattern] [COUNT count]

特点:

  • 渐进式遍历,每次 O(1)
  • 返回下一次游标
  • 游标为 0 表示结束
  • 可能重复或遗漏
  • 还有 HSCAN、SSCAN、ZSCAN

SCAN 是渐进式遍历,不保证快照一致性。遍历期间哈希表 rehash 或元素被修改,会导致同一元素重复返回,或被删除的元素不再返回。对于遍历期间一直存在的元素,SCAN 保证至少返回一次,但可能重复

10.4. Redis 网络协议

Redis 使用 RESP,Redis Serialization Protocol,应用层纯文本协议

客户端和服务器通过 RESP 通信。注意不是 RSP

10.5. 查找附近的人

使用 GEO:

复制代码
GEOADD key 经度 纬度 member ...
GEORADIUS key 经度 纬度 距离

底层基于 ZSet 和 Geohash。适合附近的人、打车、门店查询

11. 面试速查表

问题 一句话答案
Redis 是什么 高性能内存 KV 数据库
为什么快 内存、单线程、epoll、高效数据结构
五种类型 String、List、Hash、Set、ZSet
ZSet 为什么跳表 实现简单、范围查询方便、无需重平衡
单线程原因 瓶颈在内存/IO,不在 CPU,避免锁
6.0 多线程 网络 IO 和协议解析多线程,命令执行单线程
IO 多路复用 epoll 管理大量 socket,事件驱动
持久化 RDB、AOF、混合持久化
RDB 触发 save/bgsave、save m n、全量复制、shutdown
AOF 同步 always、everysec、no
过期删除 惰性 + 定期
大量 key 同时过期 随机过期时间打散
淘汰策略 LRU、LFU、random、ttl、noeviction
主从作用 读扩展、备份、故障恢复
哨兵作用 监控、选主、自动故障转移
集群分片 16384 哈希槽
集群选库 不支持,只能 db0
集群丢数据 异步复制,可能丢写
事务命令 MULTI、EXEC、DISCARD、WATCH
事务区别 不支持回滚,弱原子
Pipeline 减少 RTT,非原子
消息队列 List、Pub/Sub、Stream
分布式锁 SET NX PX + Lua 释放 + 续期
缓存穿透 缓存空值、布隆过滤器
缓存雪崩 随机过期、多级缓存、熔断
缓存击穿 互斥锁、逻辑过期
热 key 本地缓存、拆分、单独集群
双写一致 延时双删、删除重试、binlog
bigkey 拆分、UNLINK、SCAN 遍历
遍历 key SCAN,不用 KEYS *
附近的人 GEOADD、GEORADIUS
相关推荐
龙亘川1 小时前
铭记英烈守初心,数字强基促服务:亘川智城退役军人服务系统的实践与价值
java·数据库·人工智能
kv1102 小时前
Android studio国内开发有关
java·数据库·android studio
哭泣方源炼蛊2 小时前
正则表达式c++内容汇集
数据库·c++·mysql·正则表达式
余槐i3 小时前
EXPLAIN 显示走了索引查询仍慢:回表与选择性在 500 万行表上拉开 10 倍耗时
数据库·postgresql·性能优化·vacuum·explain
深度智能Ai3 小时前
IndexTTS‑2高清音质接口对接文档
数据库
香瓜子rd3 小时前
MySQL InnoDB 并发控制核心原理:事务、隔离级别、MVCC 与锁机制
数据库·后端
Elastic 中国社区官方博客4 小时前
Elasticsearch Serverless 如何通过 hollow shards 将索引节点关闭次数降低 30%
大数据·数据库·elasticsearch·搜索引擎·serverless·全文检索
ycvv4 小时前
手机启动失败后的数据提取评估:系统状态、加密条件与文件验收
服务器·数据库·智能手机
不恋水的雨4 小时前
gbase中union all导致末尾多出空格的坑
数据库·sql·mysql