Redis
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集群 主从复制: ...