Redis是什么?
Redis是一个基于内存的、单线程驱动的、可持久化的数据结构服务器。
Redis在微服务中的常见使用场景:
- 缓存:加速数据查询,扛住读流量。
- 分布式锁:用Redission 解决超卖、重复执行。
- 排行榜/计数器:Sorted Set做实时排名,String做原子计数。
- 轻量消息队列:List当简单队列,Stream当可靠消费队列。
- 特征存储:AI场景下存向量、用户画像标签。
Redis为什么快?
- 完全基于内存:没有磁盘IO瓶颈,读写都在纳秒级。
- 单线程执行命令:
- 在Redis 6.0前,所有命令都在主线程串行执行,没有上下文切换、锁竞争等问题。瓶颈本身不在CPU,而在网络IO。
- 在Redis 6.0后,引入多线程优化读写网络IO,但还是用单线程来执行命令。
- IO多路复用:一种同步非阻塞的IO模型,允许单线程通过一个系统调用,同时监控多个文件描述符,当其中某些描述符就绪,内核会返回就绪列表,应用程序再逐个处理,而不会阻塞在某个未就绪的连接上。(好比一个柜员同时监控多位客户的状态,哪位客户准备好了,柜员就去处理。虽然是一个柜员,但柜员一直在工作)
Redis的数据结构
String
- 数据结构:SDS(Simple Dynamic String)
- SDS优点:二进制安全,O(1)获取长度、预分配空间减少内存重分配、惰性释放、杜绝缓冲区溢出。
- 使用场景:缓存对象、计数器、分布式锁等。
List
- 数据结构:双向链表,有序、可重复。支持左右压入弹出。
- 使用场景:消息队列、最新列表、时间线。
Hash
- 数据结构:键值对集合
- 使用场景:存储用户属性、购物车。
Set
- 数据结构:无序、不可重复的集合。
- 使用场景:标签系统、共同好友、抽奖去重。
Sorted Set
- 数据结构:有序集合,每个成员关联一个score,按score排序,成员唯一。
- 使用场景:排行榜、延迟队列、带权重的实时队列。
Bitmaps
- 数据结构:操作位数组。
- 使用场景:签到、用户画像。
HyperLogLog
- 数据结构:概率算法
- 使用场景:基数统计。
Redis的数据过期策略
- 惰性删除:数据被访问时,检查是否需要清理。
- 定期删除:定时执行,随机抽取部分key检查是否需要清理。
Redis的数据淘汰策略
当内存满时,通过淘汰策略释放内存:
- noeviction:拒绝写入。
- allkeys-lru:所有key中,淘汰最近最少使用的。
- volatile-lru:设置了过期的key中,淘汰最近最少使用的。
- allkeys-lfu:所有key中,淘汰最不经常使用的。
- volatile-lfu:设置了过期的key中,淘汰最不经常使用的。
- volatile-ttl:设置了过期的key中,淘汰最接近过期时间的。
- allkeys-random:所有key中,随机淘汰。
- volatile-random:设置了过期的key中,随机淘汰。
Redis的数据持久化方式
- RDB(Redis Database Backup):定时快照,二进制紧凑,恢复快,但可能丢失最后一次快照之后的数据。
- 刷盘方式:fork子线程,将内存快照写入操作系统的页缓存,然后显式调用fsync()进行刷盘,同步到磁盘上。
- AOF(Append Only File):顺序追加记录每个写命令,可通过重放AOF命令来恢复数据。
- always:每条命令立即刷盘,由主线程执行。
- everysec:每秒刷一次,由后台线程执行。
- no:不主动刷盘,由OS决定。
- 混合持久化:只在AOF重写时发生,子线程将当前内存数据用RDB形式写入AOF的文件开头,后续文件采用AOF追加写。
┌────────────────────┐
│ RDB 二进制数据 │ ← 全量快照(重启时快速加载)
├────────────────────┤
│ 增量 AOF 文本 │ ← 快照时刻之后的写命令
└────────────────────┘Redis&数据库常见问题
缓存雪崩
- 定义:某一时刻,大量缓存同时失效或不可用,导致大量请求直接打到数据库,使数据库压力骤增甚至崩溃。
- 原因:大量缓存设置了相同的过期时间、缓存服务器宕机
- 解决方式:
- 缓存过期时间增加随机值:对设置的缓存过期时间增加一定的随机值,避免大量缓存同时失效。
- 多级缓存:增加本地缓存,本地缓存没有时再查询分布式缓存。
- 限流降级:在缓存失效时,限制对后端系统的请求速率,并提供可降级能力。
缓存穿透
- 定义:查询一个缓存中不存在的数据,导致每次请求都查询数据库,使数据库压力变大。
- 原因:用户请求的数据在缓存和数据库都不存在。
- 解决方式:
- 缓存空结果:对于查询结果为空的数据,也进行缓存,设置一个较短的过期时间。
- 布隆过滤器:在缓存前增加布隆过滤器,快速判断请求是否可能存在,从而减少对数据库的压力。
- 参数校验:对请求参数进行校验,过滤无效请求。
缓存击穿
- 定义:某个热点数据在缓存过期的瞬间,大量请求访问该数据,导致请求直接打到数据库。
- 原因:热点数据过期时,大量请求并发访问。
- 解决方式:
- 热点数据永不过期:对于热点数据设置为永不过期,通过后台异步更新缓存。
- 提前更新缓存:在缓存即将过期时,提前触发缓存更新,确保缓存中的数据始终有效。
- 互斥锁:在缓存失效时,通过加分布式锁的方式,只允许一个请求区加载数据并更新缓存。
Redis集群
主从复制:
- 特点:读写分离
- 数据分片:无
- 故障转移:无
- 适用场景:少量读扩展
哨兵模式:
- 特点:监控节点状态、故障通知、自动故障转移。
- 数据分片:无
- 故障转移:有,当主节点故障时,哨兵会从 从节点 中选举新的主节点。
- 适用场景:中小规模、高可用
集群模式:
- 特点:水平扩展、自动分片、无中心架构。
- 数据分片:有,默认16384个Slot,每个主节点负责一部分Slot。
- 故障转移:有,当主节点故障时,自动从 从节点 选举新的主节点。
- 适用场景:大规模分布式应用
Redis事务
Redis 事务提供了一种一次性、顺序性、排他性地执行多个命令的机制。它通过三个核心命令实现:
MULTI:开启事务。EXEC:执行事务队列中的所有命令。DISCARD:取消事务。WATCH:乐观锁,监视一个或多个键,如果这些键在事务执行前被改动,则事务中断。
本质:命令的批处理 + 执行期间的隔离保证,但不会回滚。基本上被lua脚本替代。