当前位置: 首页 > news >正文

Redis相关八股

Redis为什么快

1. 基于内存存储(In-Memory)

  • Redis 将所有数据存储在 内存 中,读写操作直接访问内存,避免了磁盘 I/O 的高延迟。
  • 内存访问速度比磁盘快几个数量级(纳秒 vs 毫秒)。

2. 单线程模型(Single-Threaded)

  • Redis 核心服务采用单线程处理所有客户端请求(从 6.0 开始,网络 I/O 和部分操作引入了多线程,但命令执行仍是单线程)。
  • 避免了多线程的上下文切换锁竞争开销。
  • 基于 I/O 多路复用(如 epoll、kqueue)实现高并发,一个线程可处理成千上万个连接。

3. 高效的数据结构

  • Redis 底层使用 C 语言实现,并针对每种数据类型优化了数据结构:
    • String:动态字符串(SDS)
    • List:双端链表或压缩列表(ziplist)
    • Hash:哈希表或压缩列表
    • Set:整数集合或哈希表
    • ZSet:跳跃表(Skip List)+ 哈希表
  • 这些结构在时间复杂度和内存使用上都做了极致优化。

4. 非阻塞 I/O 与事件驱动

  • 使用 Reactor 模式,通过事件循环处理连接、读写、定时任务等。
  • 所有操作都是非阻塞的,保证了高吞吐和低延迟。

5. 避免复杂操作

  • Redis 命令设计简单,大多数操作时间复杂度为 O(1) 或 O(log N)。
  • 不支持表连接(JOIN)等复杂查询,保持核心逻辑轻量。

总结内存 + 单线程 + 高效数据结构 + I/O 多路复用 = 极致性能

Redis的八种数据结构分别讲一下

Redis 不是只有“八种”数据结构,实际上它有 5 种基础数据结构,以及基于这些基础结构实现的 3 种高级数据结构,合起来常被说成“8 种”。

类型特点底层结构典型用途
String字符串/数字SDS缓存、计数
Hash字段-值映射ziplist / hashtable对象存储
List有序可重复ziplist / linkedlist消息队列
Set无序不重复intset / dict去重、集合运算
ZSet有序不重复skiplist + dict排行榜
Bitmap位操作String签到、统计
HyperLogLog基数估算-UV统计
Geospatial地理位置ZSet附近的人

店铺营业状态设置(day05)-CSDN博客

什么是布隆过滤器

布隆过滤器(Bloom Filter) 是一种基于概率的数据结构,用于高效判断一个元素是否可能存在于一个集合中
核心特点是:空间效率高、查询速度快,但存在一定的误判率(False Positive),且不支持删除操作(标准版本)

底层实现原理

布隆过滤器由两个核心组件构成:

1. 一个长度为 m 的位数组(Bit Array)

  • 初始时所有位都置为 0。

2. k 个独立的哈希函数

  • 每个哈希函数能将输入元素映射到位数组的一个位置(0 到 m-1)。

1. 添加元素

  • 对元素使用 k 个哈希函数,得到 k 个位置。
  • 将位数组中这 k 个位置都置为 1。

2. 查询元素

  • 同样计算出 k 个位置。
  • 检查这些位置是否全部为 1
    • 如果任意一位为 0 → 元素一定不存在
    • 如果全部为 1 → 元素可能存在(可能因哈希冲突导致误判)。

典型应用场景

  • ✅ 防止缓存穿透:在缓存前加布隆过滤器,过滤掉查询不存在 key 的请求。
  • ✅ 网页爬虫去重:快速判断 URL 是否已抓取。
  • ✅ 垃圾邮件过滤:判断邮件地址是否在黑名单中。
  • ✅ 数据库查询优化:如 HBase、Cassandra 用其跳过不含目标数据的文件。

Redis 中 set和zset区别是什么?

特性Set(集合)ZSet(有序集合,Sorted Set)
是否有序❌ 无序✅ 有序(按分数 score 排序)
元素是否唯一✅ 唯一(不允许重复)✅ 唯一(不允许重复)
存储结构哈希表(或整数集合)跳跃表(Skip List) + 哈希表
核心字段只有元素值元素值(member) + 分数(score)
时间复杂度(插入/删除/查询)O(1)O(log N)
内存占用较低较高(需存储 score 和维护跳跃表)

谈谈Redis的持久化机制RDB和AOF的区别及优缺点。

什么是RDB和AOF_rdb aof-CSDN博客

如何保证 redis 和 mysql 数据缓存一致性问题?

1、对于【读数据】,选择旁路缓存策略,如果 cache 不命中,会从 db 加载数据到 cache。
读:1. 先读 Redis
2. 如果命中,返回数据
3. 如果未命中,查 MySQL,写入 Redis,再返回

写流程:1. 更新 MySQL
2. 删除 Redis 中对应的 key(不是更新!)

2、先删缓存,再更新 DB(不推荐)

1. 删除 Redis
2. 更新 MySQL

3、延迟双删

用于防止 “先删缓存,后更新 DB” 导致的并发问题。

public void updateOrder(Order order) {redis.delete("order:" + id);     // 第一次删除mysql.update(order);             // 更新数据库Thread.sleep(100);               // 延迟 100msredis.delete("order:" + id);     // 第二次删除
}
  • 高并发写场景,防止其他线程在更新 DB 期间读到旧缓存。

4、基于 MySQL  Binlog 的异步更新(如 Canal)

利用 MySQL 的 binlog 实现缓存自动更新。

MySQL → Binlog → Canal → 消费者 → 删除/更新 Redis

流程:业务更新 MySQL---->Canal 监听 binlog,捕获变更-->消费者删除对应 Redis key。

Redis如何实现高可用?

Redis 实现高可用(High Availability)的核心目标是:在部分节点故障时,系统仍能正常提供服务,避免单点故障。主要通过以下三种机制实现:

1. Redis 主从复制(Replication)

原理

  • 一个 主节点(Master) 接收写请求。
  • 多个 从节点(Slave/Replica) 异步复制主节点的数据。
  • 从节点可处理读请求,实现读写分离

2. Redis Sentinel(哨兵)

原理

  • Sentinel 是一个分布式监控系统,通常部署 3~5 个节点。
  • 监控主从节点的健康状态。
  • 当主节点宕机时,自动选举一个从节点升级为新主节点,并通知客户端。

3. Redis Cluster(集群)

原理

  • Redis 官方提供的分布式解决方案
  • 数据自动分片(Sharding) 到 16384 个哈希槽(hash slots),分布在多个节点上。
  • 每个节点负责一部分槽位。
  • 每个主节点可配置一个或多个从节点,实现高可用

高可用机制

  • 当某个主节点宕机:
    • 它的从节点会自动被选举为新主节点
    • 集群继续对外提供服务(仅该主节点负责的槽位短暂受影响)。
  • 客户端直接连接集群,通过 MOVED 或 ASK 重定向请求。
方案是否自动故障转移是否支持分片适用场景
主从复制❌ 否❌ 否基础备份、读写分离
Sentinel✅ 是❌ 否中小规模,高可用需求
Cluster✅ 是✅ 是大规模、高并发、分布式

Redis的持久化机制有哪两种?AOF和RDB同时开启时,重启会加载哪个文件?为什么?

Redis 提供了两种核心的持久化方式:

  1. RDB(Redis Database)

    • 原理:在指定时间间隔内,生成内存数据的快照(snapshot),保存为二进制文件(如 dump.rdb)。
    • 优点:文件小、恢复快、性能影响小。
    • 缺点:可能丢失最后一次快照之后的数据。
  2. AOF(Append-Only File)

    • 原理:记录每一条写操作命令,以文本形式追加到日志文件(appendonly.aof)。
    • 优点:数据安全性高(最多丢 1 秒数据),可读性强。
    • 缺点:文件大、恢复慢、影响写性能

Redis 在启动时,会根据持久化文件的存在情况决定加载策略:

情况加载顺序原因
仅开启 RDB加载 dump.rdb有快照就恢复
仅开启 AOF加载 appendonly.aof有日志就重放
✅ AOF 和 RDB 同时开启优先加载 AOF 文件AOF 数据更完整,更接近宕机前的状态

核心原因:

  • RDB 是定时快照,比如每 5 分钟保存一次,那么最后一次快照之后的 5 分钟数据会丢失
  • AOF 记录了每一笔写操作(默认每秒同步),最多只丢失 1 秒数据,数据完整性更高
  • 因此,Redis 选择优先使用数据更完整的 AOF 文件来恢复,确保数据不丢失。

用Redis做缓存时,缓存穿透、缓存击穿、缓存雪崩怎么解决?说具体方案,别只说概念。

缓存穿透、缓存击穿、缓存雪崩分别是什么-CSDN博客

Redis的哨兵模式和Cluster模式有什么区别?分别适合什么场景?

哨兵模式(Sentinel)详解

1. 架构组成

  • 主从复制:一个 Master,多个 Replica。
  • Sentinel 集群:3~5 个 Sentinel 节点,监控 Master 和 Replica 的健康状态。

2. 工作流程

  • Sentinel 持续监控 Master。
  • 当 Master 宕机,Sentinel 集群通过投票选出一个 Replica 升级为新 Master。
  • 通知客户端更新连接地址。

3. 优点

  • ✅ 实现自动故障转移,避免单点故障。
  • ✅ 支持读写分离,提升读性能。
  • ✅ 架构相对简单,易于理解。

4. 缺点

  • ❌ 不支持数据分片,单节点存储上限受限。
  • ❌ 写操作集中在 Master,写性能无法扩展
  • ❌ 故障转移期间有短暂不可用(几秒)。

5. 适用场景

中小规模应用,如:

  • 数据量不大(< 10GB)
  • 对高可用有要求,但无需水平扩展
  • 读多写少的缓存系统

Cluster 模式(Cluster)详解

1. 架构组成

  • 多主多从:至少 6 个节点(3 主 3 从)。
  • 数据分片:16384 个哈希槽(hash slots),均匀分布在主节点上。
    • Key 通过 CRC16(key) % 16384 计算所属槽位。
  • 每个主节点负责一部分槽位,从节点复制主节点数据。

2. 工作流程

  • 客户端请求 Key,计算其槽位。
  • 如果节点负责该槽位,直接处理。
  • 否则返回 MOVED 重定向到正确节点。
  • 主节点宕机,其从节点自动升级为新主。

3. 优点

  • ✅ 真正的分布式架构,支持水平扩展。
  • ✅ 读写均可扩展,性能随节点增加而提升。
  • ✅ 高可用 + 自动故障转移
  • ✅ 官方原生支持,无需额外组件。

4. 缺点

  • ❌ 不支持跨 slot 的多键操作(如 MGET事务Lua 脚本)。
  • ❌ 运维复杂,需管理槽位、节点状态。
  • ❌ 客户端必须支持 Cluster 协议。

5. 适用场景

大规模、高并发、高可用系统,如:

  • 用户画像系统
  • 实时排行榜
  • 大型电商平台的购物车、库存缓存

Redis Cluster最多能有多少个节点?槽位怎么分配的?客户端怎么知道数据存在哪个节点?

问题回答
最多多少节点理论 1000,推荐 ≤1000,避免 Gossip 开销过大
槽位怎么分配16384 个槽,slot = CRC16(key) % 16384,主节点分片负责
客户端如何定位通过 MOVED / ASK 重定向,客户端缓存槽位映射,实现智能路由

理论上最多支持 1000 个节点,但实际推荐不超过 1000 个

槽位(Hash Slot)是怎么分配的?

Redis Cluster 将整个键空间划分为 16384 个哈希槽(hash slots),范围是 016383

1. 槽位分配原理

  • 每个 主节点(master) 负责一部分槽位。
  • 所有槽位必须被分配完,且每个槽位只能由一个主节点负责
  • 从节点(replica)不负责槽位,只复制主节点的数据。

2. Key 到槽位的映射

  • 对每个 key,通过以下公式计算其所属槽位:
    slot = CRC16(key) % 16384
  • CRC16 是一个标准的 16 位循环冗余校验算法,输出范围是 0~65535。
  • 取模 16384 后,得到 0~16383 的槽位号。

3. 槽位分配示例

假设 3 个主节点:

  • node1 负责槽位 0 ~ 5500
  • node2 负责槽位 5501 ~ 11000
  • node3 负责槽位 11001 ~ 16383

✅ 这样,数据就被均匀分散到多个节点上,实现水平分片(Sharding)

4. 为什么是 16384 个槽位?

  • 足够多:能支持几百个节点的均匀分布。
  • 足够小:每个节点只需维护 16384 bit(约 2KB)的位图来记录槽位归属,Gossip 消息不会太大。
  • 历史原因:CRC16 输出 65536,16384 是 2 的幂,便于计算。

客户端怎么知道数据存在哪个节点?

客户端通过 “重定向机制” 来定位数据,主要依赖以下两种响应:

1. MOVED 重定向(永久迁移)

  • 当客户端请求一个 key,但当前节点不负责该 key 的槽位时,会返回:
MOVED <slot> <node-ip:port>
  • 客户端收到后,应将该槽位映射缓存到本地,后续请求直接发往目标节点。

🌰 示例:

  • 客户端向 node1 发送 GET user:1001
  • node1 计算 CRC16("user:1001") % 16384 = 12000
  • 发现 12000 不归自己管,返回:MOVED 12000 192.168.1.3:6379
  • 客户端缓存 slot 12000 → node3,下次直接请求 node3

2. ASK 重定向(临时迁移)

  • 在 集群重新分片(resharding) 过程中,某个槽位正在从 nodeA 迁移到 nodeB
  • 如果 key 还在 nodeA,但槽位已部分迁移到 nodeBnodeA 会返回:
ASK <slot> <target-node-ip:port>
  • 客户端需先向目标节点发送 ASKING 命令,再发送请求。

⚠️ ASK 是临时的,不影响客户端本地的槽位映射缓存。

3. 客户端行为(智能客户端)

  • 现代 Redis 客户端(如 Jedis、Lettuce、redis-py-cluster)都是 “智能客户端”
  • 它们会:
    1. 维护一个 本地槽位映射表(slot → node)。
    2. 收到 MOVED 时更新映射。
    3. 自动重定向请求,对应用透明。

Redis的过期键删除策略是什么?

Redis 的过期键删除策略采用了 两种机制结合的方式:惰性删除(Lazy Deletion) + 定期删除(Active Expire),目的是在内存占用CPU 消耗之间取得平衡。

 惰性删除(Lazy Deletion)

  • 只有在访问某个 key 时,才检查它是否已过期
  • 如果过期,则删除该 key,并返回 nil
  • 如果未过期,则正常返回值。

定期删除(Active Expire / Active Expire)

  • Redis 会周期性地随机抽取一部分设置了过期时间的 key,检查并删除其中已过期的 key。
  • 该任务由定时任务serverCron)执行,默认每秒运行 10 次(每 100ms 一次)。

具体流程(Redis 7.0+)

  1. 从设置了过期时间的 key 字典中,随机抽取 20 个 keyACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)。
  2. 检查这些 key 是否过期,删除过期的。
  3. 如果超过 25% 的抽样 key 过期,则重复步骤 1,继续清理。
  4. 每次运行时间不超过 25ms,避免阻塞主线程。

过期删除策略和内存淘汰策略有什么区别?

  • 内存淘汰策略是在内存满了的时候,redis 会触发内存淘汰策略,来淘汰一些不必要的内存资源,出空间,来保存新的内容
  • 过期键删除策略是将已过期的键值对进行删除,Redis 采用的删除策略是惰性删除+定期删除。

为什么对于过期键不立即删除?

在过期 key 比较多的情况下,删除过期 key 可能会占用相当一部分 CPU 时间,在内存不紧张但 CPU 时间紧张的情况下,将 CPU 时间用于删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。所以,定时删除策略对 CPU 不友好。

介绍一下Redis 内存淘汰策略

Redis 提供了 8 种淘汰策略,分为 三类:基于 LRU、LFU、TTL 和随机。

 第一类:针对所有 key(allkeys)

策略说明
allkeys-lru所有 key 中淘汰最近最少使用(Least Recently Used)的。
allkeys-lfu所有 key 中淘汰最不经常使用(Least Frequently Used)的。(Redis 4.0+)
allkeys-random所有 key 中随机淘汰

第二类:仅针对设置了过期时间的 key(volatile)

策略说明
volatile-lru设置了 TTL 的 key 中淘汰最近最少使用的。
volatile-lfu设置了 TTL 的 key 中淘汰最不经常使用的。
volatile-random设置了 TTL 的 key 中随机淘汰
volatile-ttl淘汰剩余生存时间(TTL)最短的 key。

第三类:不淘汰

noeviction默认策略。达到内存上限后,新写入操作返回错误(如 SET 返回 OOM)。只允许读操作。

LRU和LFU工作原理对比

1. LRU(最近最少使用)
  • 维护一个“访问时间线”:每次访问某个 key,就把它移到“最近使用”位置。
  • 淘汰时:选择最久未被访问的 key。
  • 类比:像翻书,最近翻过的页在最上面,很久没翻的在最下面。

🌰 示例:

  • 访问顺序:A → B → C → A
  • 当前顺序:[A, C, B](A 最近用过)
  • 淘汰时:淘汰 B(最久未访问)
2. LFU(最不经常使用)
  • 为每个 key 维护一个“访问计数器”:每访问一次,计数 +1。
  • 淘汰时:选择访问次数最少的 key。
  • 高级实现:计数器会随时间衰减,避免“历史热门”长期霸占缓存。

🌰 示例:

  • 访问记录:A(5次), B(2次), C(8次)
  • 淘汰时:淘汰 B(访问最少)

LRU和LFU有什么区别?

算法全称中文含义核心思想
LRULeast Recently Used最近最少使用看“时间”:优先淘汰最久没被访问的
LFULeast Frequently Used最不经常使用看“频率”:优先淘汰访问次数最少的
对比维度LRULFU
判断依据最后一次访问时间历史访问频率
对突发流量的反应⚠️ 敏感
(新 key 会排到前面,旧热点可能被淘汰)
✅ 不敏感
(需要多次访问才能成为“热点”)
缓存污染问题❌ 存在
(一次性大量扫描数据会挤掉热点)
✅ 较好解决
(单次访问不会大幅提升计数)
内存开销较小
(只需维护访问顺序)
较大
(每个 key 要存一个计数器)
实现复杂度简单
(可用双向链表 + 哈希表)
复杂
(需计数器 + 衰减机制)
适合场景访问模式局部性强
(如会话缓存、页面缓存)
访问模式稳定
(如商品详情、配置缓存)

Redis 6.0的多线程和单线程相比,性能提升多少?

Redis 6.0 引入的多线程是一个重大架构升级,但它并非将整个 Redis 变成多线程,而是在网络 I/O 层面引入多线程,核心命令执行仍为单线程。

redis 6.0 多线程的本质:多线程只用于网络 I/O

  • 主线程:仍负责接收连接、解析命令、执行命令、返回结果。
  • IO 线程:只负责并行地读取客户端请求数据写回响应数据

🔑 命令执行(Command Execution)依然是单线程的,保证了数据一致性和无锁设计。

在高并发、网络 I/O 密集的场景下,性能可提升 3~4 倍

为什么能提升这么多?

根本原因:网络 I/O 成为瓶颈

  • 在单线程模型下,处理大量小请求时,网络读写(socket read/write)占用了大量 CPU 时间。
  • 尤其在 10G 网卡、高并发(10万+ QPS)场景下,单线程无法充分利用多核 CPU。
  • 多线程 I/O 将这部分工作并行化,释放了主线程压力

Redis 6.0多线程为什么只处理网络IO不处理命令执行?

Redis 6.0 引入多线程时,只将网络 I/O 部分多线程化,而命令执行仍然保留在单线程中

根本原因:保持 Redis 的“简单性”和“无锁设计”

原因说明
✅ 保持无锁设计避免锁竞争,保证高性能和简单性
✅ 解决真实瓶颈网络 I/O 是瓶颈,命令执行不是
✅ 保证数据一致性单线程天然支持原子性、事务、Lua 脚本
✅ 避免复杂性多线程执行会引入竞态、死锁等问题
✅ 兼容生态不破坏现有客户端和模块假设

Redis的主从复制是同步还是异步?网络中断后重连,会全量同步还是增量同步?怎么判断?

问题回答
主从复制是同步还是异步?✅ 异步复制,主节点不等待从节点确认
网络中断后重连?⚖️ 取决于偏移量是否在 backlog 中
- 在:增量同步
- 不在:全量同步
如何判断?🔍 看日志
Partial resynchronization → 增量
Full resync → 全量

Redis 主从复制本质上是异步的

  1. 主节点(Master) 在接收到写命令后:
    • 先执行该命令(如 SET key value)。
    • 然后将该命令追加到复制积压缓冲区(replication backlog)
    • 立即返回结果给客户端不等待从节点确认
  2. 从节点(Replica) 通过 PSYNC 命令持续拉取主节点的写命令,并在本地重放。

网络中断后重连,会全量同步还是增量同步?

取决于 从节点的偏移量(offset)是否还在主节点的复制积压缓冲区中

两种情况:

情况同步方式说明
✅ 增量同步(Partial Resynchronization)从节点断开时间短,其复制偏移量仍在主节点的 backlog 中主节点只发送缺失的部分命令
❌ 全量同步(Full Resynchronization)从节点断开时间长,偏移量已从 backlog 中移除主节点生成 RDB 快照并传输,从节点清空数据重新加载

怎么判断是全量还是增量同步?

1. 通过日志判断(最直接)

查看 Redis 日志:

  • 增量同步日志

Replica asks for synchronization
Partial resynchronization request from replica accepted.
  • 全量同步日志
Replica asks for synchronization
Full resync from master, sending 123456789 bytes of bulk data

为什么Redis单线程还能这么快?遇到CPU密集型命令(如KEYS)会有什么问题?怎么处理?

问题回答
单线程为何快?内存操作 + I/O 多路复用 + 无锁 + 高效数据结构
CPU 密集型命令问题?阻塞主线程,导致服务不可用
如何处理?1. 禁用 KEYS
2. 用 SCAN 替代
3. 开启慢日志
4. 多线程 I/O(仅提升网络)
5. 从节点执行

单线程为何快?

1. 基于内存操作

  • Redis 数据存储在 内存 中,读写速度是纳秒级。
  • 相比之下,数据库操作磁盘是毫秒级,相差百万倍。
  • 内存操作几乎不成为瓶颈。

📊 示例:一次 GET key 就是一次哈希表查找,O(1) 时间复杂度。

2. 采用 I/O 多路复用(I/O Multiplexing)

  • Redis 使用 epoll(Linux)、kqueue(BSD)等机制,一个线程可监听成千上万个客户端连接。
  • 不需要为每个连接创建线程,避免了线程切换和锁竞争开销。

3. 纯 C 语言实现,高效数据结构

  • Redis 用 C 编写,贴近硬件,性能极高。
  • 内置如 跳表(zset)压缩列表(ziplist)哈希表 等优化数据结构,查询效率高。

4. 避免多线程开销

  • 多线程的代价:
    • 线程创建/销毁开销
    • 上下文切换(context switch)
    • 锁竞争(lock contention)
  • Redis 单线程天然无锁,避免了这些开销。

遇到 CPU 密集型命令(如 KEYS)会有什么问题?

虽然 Redis 快,但某些命令会阻塞主线程,导致整个服务不可用。

典型问题命令:

命令问题
KEYS *扫描所有 key,O(N) 时间,大数据量时卡住几秒甚至更久
SMEMBERS big_set获取大集合所有元素,耗 CPU 和带宽
HGETALL huge_hash类似,可能返回 GB 级数据

后果:

  • 主线程阻塞:期间无法处理其他请求。
  • 超时:客户端请求超时(如 read timeout)。
  • 雪崩:大量请求堆积,系统崩溃。

怎么处理这类问题?

方案 1:禁用危险命令(推荐

redis.conf 中重命名或禁用:

rename-command KEYS ""
rename-command FLUSHDB ""
rename-command FLUSHALL ""

方案 2:使用替代命令

危险命令安全替代
KEYS *SCAN 0 MATCH user:* COUNT 100
SMEMBERSSSCAN
HGETALLHSCAN
# 安全分页扫描
SCAN 0 MATCH session:* COUNT 100
# 返回新的游标,下次继续

🔑 SCAN 是 O(1) 每次调用,适合在生产环境使用。

 方案 3:Redis 6.0+ 的多线程 I/O

Redis 6.0 引入了多线程 I/O,但命令执行仍是单线程

  • 多线程负责:网络读写(socket read/write)。
  • 主线程负责:命令解析和执行。

效果:提升网络吞吐,但不能解决 KEYS 这类命令的阻塞问题

方案 4:监控与告警

  • 监控 slowlog
    SLOWLOG GET 5
  • 设置慢查询阈值:
    config
    slowlog-log-slower-than 10000  # 超过 10ms 记录
  • 告警:发现 KEYSFLUSHALL 等命令立即报警。

方案 5:隔离部署

  • 将管理类、分析类请求放到独立的从节点执行。
  • 主节点只处理核心业务流量

什么是 BigKey?

Redis大key问题指的是某个key对应的value值所占的内存空间比较大,,导致Redis的性能下降、内存不足、数据不均衡以及主从同步延迟等问题。

BigKey 并没有一个绝对的标准,但通常从两个维度衡量:

  1. Key 对应的 Value 体积过大:例如,一个 String 类型的 Value 超过 10 KB,或者一个 Hash、List、Set 等集合类型的元素数量超过 5000(这个阈值可根据实际情况调整)。

  2. Key 本身占用内存过大:虽然不常见,但如果一个 Key 的 Value 是包含了数百万个元素的集合,它就是一个 BigKey。

Redis的BigKey有什么危害?

  • 阻塞主线程(最严重): Redis是单线程处理命令的。删除或读取一个BigKey(如包含数百万个元素的Hash/List)会消耗大量CPU时间,导致其他命令被阻塞,造成服务延迟甚至超时。
  • 内存占用过高 创建或读取BigKey时,需要一次性申请或传输大量内存,可能引发内存碎片或网络带宽打满。
  • 主从同步延迟: BigKey的同步会占用大量网络带宽和从节点处理时间,导致主从数据不一致时间变长。
  • 集群模式下槽位倾斜: 在Redis Cluster中,BigKey会导致其所在节点的内存和负载远高于其他节点,破坏负载均衡。

怎么检测和删除BigKey?

  • 使用官方 redis-cli --bigkeys 命令 Redis自带的命令,通过扫描(SCAN)方式统计不同数据类型中元素数量最多的Key,适合离线或低峰期使用。
  • 使用 MEMORY USAGE 命令:对于已知的、怀疑是 BigKey 的 Key,可以直接查询其精确的内存占用(字节数)。

删除BigKey时会阻塞服务吗?

直接使用 DEL 命令删除一个 BigKey(例如,一个包含百万元素的 Hash),Redis 需要同步释放大量内存,这个过程会长时间占用主线程,导致服务阻塞。

UNLINK 命令: 不会阻塞(或阻塞极短)UNLINK 只将Key标记为待删除并创建后台任务,立即返回。内存释放由后台线程完成,对主线程影响极小。

UNLINK:异步删除。它先将 Key 从 keyspace 中移除,真正的内存释放操作在后台线程中执行。

Redis大key如何解决?

解决 Redis 大 Key 问题是一个系统工程,需要从预防、监控、治理三个层面入手。

预防

  1. 数据分片(Sharding):

    • 按范围分片: 将一个大的集合拆分成多个小的Key。例如,将一个包含百万用户信息的Hash user:all:info 拆分为 user:0-9999:infouser:10000-19999:info 等。
    • 按哈希分片: 对ID进行哈希取模,如 user:profile:{id%100},将数据分散到100个Key中。
    • 时间维度分片: 如日志类数据,按天/小时存储,log:20251023log:20251024
  2. 选择合适的数据结构:

    • 避免使用一个String存储超大JSON或序列化对象,考虑是否可拆解。
    • 如果List过长且只关心最新N条,使用 LPUSH + LTRIM 限制长度。
    • 考虑用Sorted Set替代List实现排行榜,利用其范围查询能力。
  3. 设置合理的过期时间(TTL):为可能膨胀的Key设置TTL,防止无限增长。

  4. 业务逻辑优化:评估是否真的需要在Redis中存储如此大的数据。有时数据库或文件系统更合适。

已存在BigKey的治理

  1. 安全删除:必须使用 UNLINK 命令 替代 DELUNLINK 异步释放内存,避免阻塞主线程。

  2. 分批处理:

    • List: 使用 LPOP / RPOP 或 LTRIM 分批弹出或截断。
    • Hash: 使用 HSCAN 遍历,配合 HDEL 分批删除字段。
    • Set/ZSet: 使用 SSCAN / ZSCAN 配合 SREM / ZREM 分批删除成员。
  3. 迁移或归档:将不常访问的BigKey数据迁移到成本更低的存储(如数据库、对象存储),Redis中只保留热点数据。

监控与发现

  • 定期执行 redis-cli --bigkeys 进行扫描。
  • 配置慢查询告警,分析长时间运行的命令。
  • 集成监控系统,对内存突增、延迟升高进行预警。

什么是热key?

热Key(Hot Key) 是指在短时间内被极高频次访问的Redis Key。

核心特征

  • 高QPS: 该Key的读/写请求量在极短时间内暴增,可能达到每秒数万甚至数十万次。
  • 集中访问: 访问集中在单个或少数几个Key上。
  • 突发性: 通常由特定事件触发,具有突发性。

常见场景

  1. 突发热点事件: 某明星官宣、突发新闻,导致相关资讯的缓存Key被疯狂访问。
  2. 热门商品: 电商大促时,秒杀或爆款商品的商品详情、库存信息Key被大量用户请求。
  3. 热门文章/视频: 平台上的爆款内容,其内容缓存、点赞数、评论数等Key访问量激增。
  4. 公共配置: 全局开关、活动配置等被所有服务实例频繁读取的Key。

危害

  1. 单机过载(最严重): Redis通常是主从或集群部署。一个热Key会集中在某一台Redis实例上,导致该实例的CPU、内存带宽或网络带宽被打满,响应变慢甚至崩溃,而其他实例却很空闲。
  2. 请求倾斜: 在集群模式下,热Key所在的分片(shard)负载远高于其他分片,破坏负载均衡。
  3. 缓存击穿风险: 如果热Key恰好在此时过期或被删除,大量请求会直接穿透到数据库,造成数据库压力剧增,甚至宕机。
  4. 响应延迟: 单实例处理不过来,导致所有访问该实例的请求延迟升高。

如何解决热key问题?

  1. 本地缓存(Local Cache):

    • 在应用服务本地(如使用CaffeineGuava Cache)缓存热Key的数据。
    • 大部分请求在本地缓存命中,极大减少对Redis的访问压力。
    • 需注意本地缓存的一致性问题(如设置较短TTL或通过消息队列更新)。
  2. Redis集群优化:

    • Key分片: 将一个热Key拆分成多个子Key(如 hotkey:1hotkey:2),访问时随机选择一个,分散压力。
    • 副本读取: 利用Redis主从架构,将读请求分散到多个从节点(Slave),写请求仍走主节点。
  3. 限流与降级:

    • 在服务层对访问热Key的请求进行限流,防止打垮下游。
    • 在极端情况下,可返回默认值或降级页面,保证系统可用性。
  4. 提前发现与预案:

    • 建立热Key探测机制(如监控、采样分析),提前发现潜在热Key。
    • 对已知的热Key(如大促商品)提前做好预案(如预热、本地缓存)。

用Redis存储1000万条用户会话数据,选什么数据结构?内存占用大概多少?怎么优化内存?

推荐使用 String 结构,以 session:<session_id> 为 key,序列化后的会话数据为 value

SET session:abc123 "{\"user_id":1001,"login_time":1730000000,"ip":"192.168.1.100"}"
EXPIRE session:abc123 3600  # 1小时过期
数据结构是否合适原因
✅ String✔️ 推荐简单、直接、内存紧凑,适合存储整条会话数据
❌ Hash⚠️ 不推荐虽然可存字段,但每个 field 都有额外开销,小数据更耗内存

原则:数据结构越简单,内存占用越小,性能越高。

用Redis做排行榜,怎么实现实时更新和分页查询?ZSet的score更新会影响性能吗?

????

Spring Boot02(数据库、Redis)---java八股-CSDN博客

Spring Boot02(数据库、Redis)02---java八股-CSDN博客

http://www.dtcms.com/a/519832.html

相关文章:

  • zookeeper数据迁移
  • Java 大视界 -- Java 大数据机器学习模型在智能客服多轮对话系统中的优化策略
  • 怎么上网做网站dede网站模板怎么改
  • 网站关键词查询怎么用腾讯云主机建设网站
  • WGJ技术解析与应用:构建下一代智能数据处理引擎
  • js基础:05、对象(创建对象、属性名及属性值、基本数据及引用数据类型、对象字面量)
  • 苍穹外卖是如何从0搭建一个标准的 Maven 多模块项目​​的?
  • 网站建设竞品调研上海注册公司免费地址
  • 宣传网站制作方案网站架构演变过程
  • K8S 二进制集群搭建(一主两从)
  • 每日一个C语言知识:C typedef
  • 交叉编译FFmpeg:从x264到RK3588部署实战
  • LeetCode算法日记 - Day 82: 环形子数组的最大和
  • Leetcode 36
  • 深入理解epoll:为什么推荐使用epoll_create1而不是epoll_create?
  • 公司被其它人拿来做网站营销渠道的概念
  • 在 Linux 下使用 I2C(Inter-Integrated Circuit)进行用户态编程 — 教程与实战
  • 替代HT1621B液晶驱动显示模块芯片程序演示
  • C++和OpenGL实现3D游戏编程【连载26】——添加TransformComponent组件(设置子物体的位移、旋转、缩放)
  • 常规条形光源在工业视觉检测上的应用
  • Zotero插件安装
  • Llama Factory、Unsloth与Hugging Face三大微调平台深度对比分析
  • 电脑卡在 “正在准备 Windows”?5 步解决:从等待到重装
  • 优惠券网站要怎么做的佛山禅城网站建设
  • 基于深度学习计算s21参数,在射频中的应用
  • 微服务day01——拆分作业参考
  • YOLO11训练后的模型无法正常推理解决办法
  • 网站模版 优帮云深圳网络安全公司排名
  • navicat过期了,怎么操作mysql。用DBeaver
  • LangGraph工作流与智能体核心模式总结