2-3-4-1-Redis基础概念
1、Redis知识点全体系梳理(基础→高阶,原理→应用)
Redis是高性能分布式键值存储系统,定位为“缓存+分布式数据结构服务器”,核心价值是解决高并发下的数据访问效率与复杂业务场景的数据存储需求。以下从基础认知、核心原理、高级特性、应用场景、面试高频问题五大维度,构建“原理-实现-应用”的闭环知识体系。
一、基础认知:Redis是什么?
1. 核心定位
- 缓存:解决数据库瓶颈,提升读性能(90%以上的请求命中缓存);
- 分布式数据结构服务器:支持String、Hash、List、Set、Sorted Set等数据结构,用于计数器、排行榜、分布式Session等场景;
- 轻量级消息队列:通过Pub/Sub或Streams实现异步通信。
2. 基础特性
| 特性 | 说明 |
|---|---|
| 单线程模型 | 所有请求由一个线程处理(避免上下文切换),IO用epoll多路复用(支持10万+ QPS); |
| 键值对存储 | 键是字符串,值支持多种数据结构; |
| 过期机制 | 支持key过期(基于TTL),用于缓存失效; |
| 持久化 | RDB(快照)+ AOF(日志),保障数据安全性; |
| 高可用 | 主从复制+哨兵(Sentinel)+ Redis Cluster(集群),解决单点故障; |
二、核心原理:Redis为什么这么快?
1. 单线程模型的底层逻辑
Redis的单线程并非“真的只有一个线程”,而是请求处理线程是单线程,其他线程负责IO、持久化等后台任务。其快的原因:
- 避免上下文切换:单线程处理请求,无需切换线程;
- IO多路复用:用epoll模型监听多个客户端连接,一次性处理多个请求;
- 高效数据结构:底层用C实现,针对不同数据结构优化(如String用SDS,Hash用压缩列表)。
2. 数据结构的底层实现(面试必问)
Redis的数据结构不仅是“存储工具”,更是解决复杂问题的关键。需掌握底层实现与应用场景的对应关系:
| 数据结构 | 底层实现 | 核心特性 | 应用场景 |
|---|---|---|---|
| String | SDS(Simple Dynamic String) | 可变长度字符串,支持预分配(减少扩容次数),存储二进制数据(如图片) | 缓存(用户信息JSON)、计数器(点赞数)、分布式锁(setnx) |
| Hash | 压缩列表(ziplist)→ 哈希表(hashtable) | 压缩列表:小数据(≤512键值对,≤64字节/值),节省内存;哈希表:大数据,O(1)查询 | 对象属性存储(用户资料:name、age)、购物车(商品ID→数量) |
| List | 快速列表(quicklist) | 双向链表+压缩列表(分段存储),兼顾插入效率和内存占用 | 消息队列(FIFO)、最新动态(朋友圈前10条,ltrim维护) |
| Set | 整数集合(intset)→ 哈希表(hashtable) | 整数集合:小整数(≤512个),节省内存;哈希表:大数据,支持交集/并集运算 | 去重集合(标签)、共同好友(sinter) |
| Sorted Set | 跳表(skiplist)+ 哈希表 | 跳表:支持O(logN)范围查询,有序;哈希表:快速查找元素分数 | 排行榜(游戏积分)、时间线排序(微博热搜,按时间戳排序) |
面试追问:为什么Sorted Set用跳表而不用红黑树?
- 查询效率:跳表和红黑树的查询时间复杂度都是O(logN),但跳表的范围查询更高效(如zrange 0 -1);
- 实现复杂度:跳表无需旋转节点,实现简单;红黑树需要维护平衡,代码复杂;
- 内存占用:跳表的内存占用略高于红黑树,但Redis追求“简单高效”,跳表更符合需求。
3. 持久化机制:数据安全与性能的平衡
Redis的持久化解决“宕机数据丢失”问题,核心是RDB(快照)与AOF(日志)的组合。
(1)RDB(Redis Database Snapshot)
- 原理:定期将内存数据快照写入磁盘(默认每5分钟一次);
- 触发方式:
- 手动:
save(同步,阻塞主线程)、bgsave(异步,fork子进程); - 自动:配置文件设置
save 900 1(900秒内至少1次写操作则触发);
- 手动:
- 优点:文件小(二进制压缩)、恢复快(直接加载快照);
- 缺点:会丢失最后一次快照后的所有数据(如宕机时未生成快照)。
(2)AOF(Append Only File)
- 原理:记录所有写操作命令(如set、incr),以文本形式追加到文件;
- 同步策略:
appendfsync always:每次写操作都同步(数据安全,性能差);appendfsync everysec:每秒同步(默认,兼顾安全与性能);appendfsync no:由操作系统同步(性能好,数据可能丢失);
- 优化:AOF重写(自动压缩日志,去除重复命令,如多次incr合并为set);
- 优点:数据完整性高(最多丢失1秒数据);
- 缺点:文件大(日志冗余)、恢复慢(需重放所有命令)。
(3)混合持久化(Redis 4.0+)
- 原理:将RDB快照与AOF日志结合(RDB存全量数据,AOF存增量命令);
- 优势:兼顾RDB的快速恢复与AOF的数据完整性,是生产环境推荐方案。
4. 主从复制:读扩展与数据备份
Redis的主从复制解决“读多写少”场景的读性能问题,同时作为数据备份。
(1)复制流程
- 全量复制:从节点首次连接主节点,主节点生成RDB快照发送给从节点;
- 增量复制:全量复制后,主节点将增量命令发送给从节点(通过
repl_buffffer)。
(2)主从延迟问题(面试高频)
- 原因:
- 主节点写操作耗时(如大key写);
- 从节点处理命令慢(配置低);
- 网络延迟(主从节点不在同一机房);
- 解决方案:
- 优化主节点写操作(减少大key写);
- 从节点用更高配置的机器;
- 关闭主节点的持久化(由从节点负责持久化,避免主节点写RDB影响性能)。
5. 高可用:哨兵(Sentinel)与集群(Redis Cluster)
(1)哨兵(Sentinel)
- 功能:监控主从节点状态,自动切换主节点(failover);
- 原理:哨兵集群(至少3个节点)通过投票决定主节点是否故障,若故障则提升从节点为主节点;
- 缺点:主节点切换期间会有短暂不可用(秒级)。
(2)Redis Cluster(官方分片方案)
- 分片原理:将数据分布在16384个槽位(slot)上,每个节点负责一部分槽位;
- 故障转移:节点故障时,从节点自动接管槽位,实现高可用;
- 优点:横向扩展(支持大规模数据),高可用;
- 缺点:客户端需要支持槽位重定向(如
MOVED错误)。
三、高级特性:解决复杂业务场景
1. 分布式锁:跨进程的互斥机制
Redis的分布式锁解决“多进程并发访问共享资源”的问题,核心是“原子性获取锁”与“可靠释放锁”。
(1)正确实现方式
-
获取锁:用
set命令的NX(不存在才设置)+PX(过期时间)参数:set lock_key unique_value NX PX 30000 # unique_value是客户端唯一标识(如UUID) -
释放锁:用Lua脚本保证原子性(判断value是否为当前客户端,是则删除):
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
(2)进阶:Redisson的看门狗机制
- 问题:若业务执行时间超过锁的过期时间,会导致锁提前释放,引发并发问题;
- 解决方案:Redisson的
RLock实现自动续期(看门狗线程每10秒检查锁,若业务未执行完则延长过期时间)。
(3)高可用:RedLock算法(争议中)
- 问题:单Redis节点故障会导致锁失效;
- 原理:向多个Redis节点(如5个)同时申请锁,若获得多数节点(≥3)的锁,则认为锁获取成功;
- 争议:时钟漂移可能导致锁失效,生产环境建议用ZooKeeper或Etcd替代(更可靠,但性能略低)。
2. 事务与乐观锁:解决并发冲突
Redis的事务(MULTI/EXEC)是弱一致性事务(仅保证命令原子执行,不保证数据一致性),而WATCH机制可实现乐观锁,解决“并发修改冲突”。
(1)流程
WATCH key:监视某个key,若在执行MULTI前该key被修改,则事务失败;- 循环:监视key → 开启事务 → 修改数据 → 执行事务 → 若失败则重试。
(2)应用场景
- 抢红包:监视红包剩余金额,若被修改则重试;
- 库存扣减:监视库存数量,避免超卖。
3. Streams:持久化消息队列
Redis 5.0引入的Streams是“持久化的发布订阅”,解决了传统Pub/Sub“消息易丢失”“无消费者组管理”的问题,适用于分布式消息队列场景。
(1)核心概念
- Stream:有序的消息队列(类似Kafka的Topic),每个消息有唯一ID(
时间戳-序列号); - 消费者组(Consumer Group):多个消费者共同消费一个Stream,实现负载均衡;
- 消息确认(ACK):消费者处理完消息后需确认,避免重复消费。
(2)应用场景
- 订单状态变更通知:生产者发送订单状态,消费者组处理通知;
- 日志收集:多个服务发送日志,消费者组统一处理。
4. 内存优化:解决内存浪费与碎片
Redis的内存优化不仅是“设置maxmemory”,更要深入内存淘汰策略、碎片整理、数据结构优化。
(1)内存淘汰策略
Redis的maxmemory-policy有8种策略,核心差异在于“淘汰哪些key”:
| 策略 | 描述 |
|---|---|
| volatile-lru | 淘汰有过期时间的key中,最近最少使用的 |
| allkeys-lfu | 淘汰所有key中,最不经常使用的(Redis 4.0+,基于计数衰减) |
| volatile-ttl | 淘汰有过期时间的key中,剩余寿命最短的 |
| noeviction | 不淘汰,返回错误(默认策略,适合数据不能丢失的场景) |
(2)内存碎片优化
Redis的内存碎片是由于频繁修改数据结构导致的(如List的扩容/缩容),碎片率(mem_fragmentation_ratio)= used_memory_rss/ used_memory(>1.5表示碎片严重)。
(3)解决方案
- 主动碎片整理:Redis 4.0+支持
MEMORY PURGE(清理碎片,需重启或后台线程); - 配置优化:
activedefrag yes(开启自动碎片整理,适合内存紧张的场景); - 数据结构优化:避免频繁修改大key(如拆分List为大List+小List)。
四、应用场景:Redis的最佳实践
1. 缓存(最常用)
- 实现:将数据库数据缓存到Redis,过期时间设置为10-30分钟;
- 优化:
- 热点key设置永不过期,后台异步更新;
- 用布隆过滤器过滤不存在的key,避免缓存穿透。
2. 计数器(如点赞数、访问量)
-
实现:用String的
incr命令(原子性递增),避免并发问题:incr like_count:article_123 # 文章123的点赞数加1
3. 排行榜(如游戏积分、销量)
-
实现:用Sorted Set的
zadd(添加元素)+zrevrange(倒序取前N名):zadd rank 1000 user_1 # 用户1积分1000 zadd rank 900 user_2 zrevrange rank 0 9 withscores # 取前10名
4. 分布式Session(如Spring Session)
-
实现:将Session存储在Redis中,解决集群环境下Session共享问题:
# Spring Boot配置 spring: session: store-type: redis timeout: 1800 # Session过期时间(秒)
5. 限流(如接口防刷)
-
实现:用Sorted Set记录请求时间戳,超过阈值则拒绝:
public boolean limitRequest(String ip) { long now = System.currentTimeMillis(); long window = 1000; // 1秒窗口 long maxRequests = 100; // 每秒最多100次 // 移除窗口外的请求 redis.zremrangeByScore(ip, 0, now - window); // 统计窗口内的请求数 long count = redis.zcard(ip); if (count < maxRequests) { redis.zadd(ip, now, now); redis.expire(ip, window / 1000); // 设置过期时间 return true; } return false; }
五、面试高频问题总结
- Redis的线程模型是什么?为什么单线程还快?
- 单线程处理请求,IO用epoll多路复用,避免上下文切换,高效数据结构减少处理时间。
- RDB和AOF的区别?生产环境怎么用?
- RDB是快照,恢复快但可能丢数据;AOF是日志,数据完整但恢复慢。生产环境用混合持久化。
- 缓存穿透的解决方案?
- 布隆过滤器或空值缓存。
- 分布式锁的可靠性?
- 用set命令的NX+PX参数,保证原子性;用Redisson的看门狗机制自动续期;避免单节点,用RedLock(但有争议)。
- 主从延迟怎么解决?
- 优化主节点写操作,从节点用高配置,关闭主节点持久化(由从节点负责)。
- Redis Cluster的分片原理?
- 将数据分布在16384个槽位上,每个节点负责一部分槽位。
- Redis的内存碎片怎么优化?
- 开启自动碎片整理(
activedefrag yes),手动清理(MEMORY PURGE),优化数据结构避免频繁修改大key。
- 开启自动碎片整理(
六、工程实践建议
- 选型:缓存用Redis,消息队列用Kafka/RocketMQ(Redis Stream适合轻量级场景);
- 高可用:生产环境用Redis Cluster(官方分片方案)+ Sentinel(监控);
- 规范:key命名用“业务前缀:模块:唯一标识”(如
user:info:123),避免乱码; - 监控:用Prometheus+Grafana监控Redis的内存、CPU、QPS,及时预警;
- 安全:生产环境必须开启TLS和ACL,禁止公网暴露Redis端口。
七、总结
Redis的知识体系可归纳为:基础特性→核心原理(单线程、持久化、主从复制)→高级特性(分布式锁、事务、Streams)→应用场景(缓存、计数器、排行榜)。面试中需结合场景讲原理(如“为什么用Sorted Set做排行榜?”),工程中需关注可靠性与性能(如分布式锁的自动续期、缓存穿透的防护)。若有具体场景(如秒杀系统中的Redis应用),可进一步针对性深入。
本文来自博客园,作者:哈罗·沃德,转载请注明原文链接:https://www.cnblogs.com/panhua/p/19210248
浙公网安备 33010602011771号