个人学习笔记CACHE / REDIS

AUTHORED_MARKDOWN / 2026-08-26

Redis 学习笔记

记录 Hash、Listpack、Hashtable 等底层结构,以及购物车、缓存与常见面试场景中的选择依据。

.MD
字符
3,535
标题节点
20
预计阅读
8 分钟
内容状态
持续整理

redis学习:

1.Redis Hash底层是什么?

Redis Hash底层根据数据规模采用不同编码。

当Hash对象较小时(一般小于64或256)省内存,会采用listpack结构(类似于在内存里连续存储的链表数组),它将field和value连续存储,减少额外指针和对象开销。

当Hash数据量较大或者字段值较长时,会转换为hashtable结构(哈希表),

通过哈希定位field,提高查询效率。

这种设计体现了Redis空间和时间的平衡:

小数据优先节省内存,大数据优先保证查询性能。

这也是 Redis 设计思想:

用空间换时间,用结构适配场景,而不是所有数据都使用同一种实现。

Hash实际案例:购物车

这是面试非常喜欢问的。

购物车:

用户:

user:1001

商品:

商品id

数量

Redis:

cart:user:1001

商品id 数量

10001 2

10002 5

10003 1

添加商品:

HSET cart:user:1001 10001 2

增加数量:

HINCRBY cart:user:1001 10001 1

数量:

2+1=3

查询购物车:

HGETALL cart:user:1001

删除商品:

HDEL cart:user:1001 10001

这就是电商购物车典型设计。

Hash 常用命令总结

命令 作用

HSET 设置字段

HGET 获取字段

HMGET 获取多个字段

HGETALL 获取全部字段

HDEL 删除字段

HEXISTS 判断字段

HLEN 字段数量

HINCRBY 数字增加

HKEYS 获取所有字段名

HVALS 获取所有值

List:栈与队列
List = 栈(Stack)

什么是栈?

特点:

后进先出(在栈里全是左,即LPUSH,LPOP)

英文:

LIFO

Last In First Out

现实:

一摞盘子。

放:

盘子1

盘子2

盘子3

拿:

先拿盘子3。

Redis实现:

使用:

LPUSH + LPOP

例如:

入栈:

LPUSH stack A

LPUSH stack B

LPUSH stack C

现在:

C

B

A

出栈:

LPOP stack

得到:

C

符合:

后进先出。

List = 队列(Queue)

更重要。

队列:

特点:

先进先出(在队列里先向右插入RPUSH,在向左处理LPOP)

FIFO

First In First Out

现实:

排队买票:

张三

李四

王五

张三先处理。

Redis实现:

生产:

RPUSH queue task1

RPUSH queue task2

RPUSH queue task3

队列:

task1

task2

task3

消费:

LPOP queue

得到:

task1

剩余:

task2

task3

这就是最简单消息队列。

Redis List底层是什么?

回答:

Redis List底层采用quicklist结构。

quicklist是双向链表和listpack的结合,

每个节点内部使用listpack存储多个元素。

相比传统链表,它减少了指针带来的内存开销,

相比连续数组,它保留了快速插入删除能力。

Redis通过这种结构在性能和内存之间取得平衡。

实际项目案例:订单异步处理

假设:

用户下单。

传统:

用户请求

创建订单

发送短信

扣库存

生成物流

返回

问题:

后面步骤慢。

用户等待:

5秒。

改成 Redis List:

流程:

用户下单

订单服务

写入Redis List

立即返回

后台Worker消费

处理订单

Redis List vs Kafka/RabbitMQ

面试经常问:

为什么不用Redis做消息队列?

对比:

Redis List RabbitMQ Kafka

定位 简单队列 消息中间件 大数据流平台

吞吐 高 高 极高

消息持久化 弱 强 强

消息确认 弱 强 强

顺序保证 简单 支持 强

重试机制 需要自己实现 内置 支持

适合 简单异步任务 业务消息 日志/数据流

如果面试问:Redis如何实现消息队列?

Redis可以通过List结构实现简单消息队列。

生产者使用RPUSH将消息放入队列,

消费者使用LPOP获取消息。

为了避免消费者不断轮询导致CPU浪费,

Redis提供BLPOP阻塞读取,

消费者没有消息时进入等待状态,

有消息时立即唤醒。

不过Redis List缺少完整消息确认和持久化机制,

在可靠性要求高的场景通常使用Kafka或RabbitMQ。

Set和List区别(面试)

List Set

是否有序 有序 无序

是否重复 允许 不允许

访问方式 索引 成员

底层 quicklist intset/hash

应用 队列 去重集合

Redis Set有什么特点?

回答:

Redis Set是一种无序不可重复的数据结构。

它底层根据数据类型选择intset或者hashtable:

当元素都是整数且数量较小时使用intset节省内存,

否则使用hashtable保证查询效率。

Set除了提供增删查操作外,

还支持交集、并集、差集等集合运算,

因此常用于标签系统、共同好友、点赞去重、抽奖等场景。

Redis ZSet底层是什么?

回答:

Redis ZSet底层主要由hash table和skiplist组成。

hash table用于快速通过member找到score,

时间复杂度接近O(1)。

skiplist用于按照score排序,

支持范围查询和排名操作,

平均时间复杂度O(logN)。

两者结合,使ZSet既能快速查询元素,

又能高效实现排行榜功能。

Redis如何保证数据持久化?

回答:

Redis提供RDB和AOF两种持久化方式。

RDB通过定期生成内存快照保存数据,

优点是恢复快、文件小,

缺点是可能丢失最近一次快照之后的数据。

AOF通过记录每次写命令实现持久化,

数据安全性更高。

生产环境通常会结合使用,

RDB用于快速恢复和备份,

AOF用于降低数据丢失风险。

Redis缓存异常有哪些?如何解决?

可以回答:

Redis缓存主要有三个问题。

缓存穿透是查询不存在的数据,

导致请求绕过缓存访问数据库,

可以通过缓存空值或者布隆过滤器解决。

缓存击穿是热点数据过期时,

大量请求同时访问数据库,

可以通过互斥锁或者热点数据永不过期解决。

缓存雪崩是大量缓存同时失效,

导致数据库压力瞬间增加,

可以通过随机过期时间、缓存预热、多级缓存等方式解决。

穿透:

没有数据 → 查数据库

解决:

布隆过滤器 + 空值缓存

击穿:

一个热点key失效

解决:

互斥锁 + 永不过期

雪崩:

大量key一起失效

解决:

随机过期 + 预热 + 多级缓存

Redis如何实现分布式锁?

回答:

Redis实现分布式锁主要利用SET命令的NX和EX参数。

NX保证只有一个客户端能够成功创建锁,

EX设置过期时间防止服务异常导致死锁。

为了避免误删其他客户端的锁,

通常会给锁设置唯一value,

释放锁时通过Lua脚本判断value是否属于当前客户端。

生产环境通常使用Redisson等成熟框架实现。

AOF和replication buffer(复制缓冲区)的区别

非常重要:

AOF replication buffer

作用 持久化 同步Slave

保存位置 磁盘文件 内存

保存内容 写命令 写命令

生命周期 长期 临时

服务对象 自己恢复 从节点同步

Redis主从复制是什么?

回答:

Redis主从复制是一种数据同步机制。

主节点负责处理写请求,

从节点复制主节点数据并承担部分读请求。

第一次同步时采用全量复制,

通过生成RDB快照传输数据。

之后通过复制缓冲区进行增量复制,

同步新的写操作。

主从复制可以提高读性能和数据可靠性,

但主节点故障自动切换需要结合Sentinel实现。

Redis Sentinel(哨兵)是什么?

回答:

Redis Sentinel是Redis提供的高可用解决方案。

它主要负责监控Redis节点状态,

当Master发生故障时,

通过多个Sentinel节点投票确认故障,

选择合适的Slave提升为新的Master,

并通知客户端更新连接。

主从复制负责数据同步,

Sentinel负责故障检测和自动故障转移。

Redis Cluster(集群)为什么需要Hash Slot(哈希槽)?

回答:

Redis Cluster通过16384个Hash Slot实现数据分片。

客户端根据key计算slot,

然后根据slot所在节点发送请求。

相比直接key映射节点,

Hash Slot可以更方便地进行节点扩容和数据迁移,

因为只需要迁移部分slot,而不是重新分布全部数据。