Redis
数据类型
String字符串:因为C语言字符串的限制(没有扩容机制,获取长度速度太慢,特殊字符无法处理)
List链表:双向链表
Hash哈希表:拉链法
Set集合:1.普通集合(利用Hash) 2.整数集合(数组实现,所以添加扩容,删除缩容,查找二分)
ZSet有序集合:跳表
跳表:
构建:随机n/2作为一级索引,n/4作为二级索引
插入:1/2概率无索引,1/4概率为一级索引,1/8概率为二级索引
利用redis实现微博热搜TopK
1. Hash哈希表,键存储热搜标题,值存储热度,排序,选取TopK,复杂度O(nlogn)
2. Zset,复杂度O(k)
缓存穿透
查询大量不存在的数据
解决方案:
- 空结果缓存
- 布隆过滤器
缓存击穿
热点请求的key过期了,并发请求压垮数据库
解决方案:
- 互斥锁(强一致性、性能差)
- 逻辑过期(高可用、性能优、不能保证数据绝对一致)
缓存雪崩
同一时段大量缓存key同时失效或者Redis宕机,导致大量请求到达数据库
解决方案:
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性(哨兵模式、集群模式)
- 给缓存业务添加降级限流策略(nginx, gateway)
- 给业务添加多级缓存
注:降级限流策略可以作为缓存穿透、缓存击穿、缓存雪崩的保底策略。
双写一致性
当修改了数据库的数据,同时更新缓存数据,缓存数据和数据库的数据要保持一致
延迟双删
删除缓存 -> 操作数据库 -> 延时删除缓存
无法强一致性
为什么要延迟?
数据库是主从模式,等待数据同步到从节点
分布式锁
强一致性,性能低
缓存的数据一般是读多写少
添加共享锁(读)与排他锁(写)
异步通知
异步通知保证数据的最终一致性
写入数据库 -> 发布MQ消息 -> 监听MQ消息 -> 更新缓存
持久化
RDB: Redis数据备份文件
原理:
开启子进程,子进程共享主进程内存数据(页表),将数据写入RDB文件
copy-on-write解决脏写:
- 当主进程执行读操作,访问共享内存
- 当主进程执行写操作,拷贝一份数据,执行写操作
AOF: 记录每一个写命令,默认关闭
Always:
同步刷盘,性能影响大,可靠性高
everysec:
每秒刷盘,性能适中,可能丢1s数据
no:
操作系统自动控制,性能最好,可能丢大量的数据
通过设置bgrewriteaof可以重写AOF,只保留最后一次写操作
数据过期策略
惰性删除:需要key的时候检查,如果过期就删除。CPU友好,内存不友好
定期删除:每隔一段时间检查,删除过期的key
Redis过期策略是这两种方法配合使用
数据淘汰策略
noeviction:不淘汰任何key,满了不允许写入
volatile-ttl:对设置了TTL的key,淘汰剩余TTL最小的key
allkeys-random: 对全体的key进行随机淘汰
volatile-random:对设置了TTL的key,随机进行淘汰
allkeys-lru:对全体key,基于LRU算法进行淘汰
volatile-lru:对设置了TTL的key,基于LRU算法进行淘汰
allkeys-lfu:对全体key,基于LFU算法进行淘汰
volatile-lfu:对设置了TTL的key,基于LFU算法进行淘汰
选择方法:
0. 优先使用allkeys-lru
1. 数据访问频率差别不大,没有明显的冷热数据,allkeys-random
2. 置顶需求,置顶数据不设置过期时间,volatile-lru
3. 短时高频访问,allkeys-lfu、volatile-lfu
分布式锁
setnx
主从复制
主从全量同步:
主从增量同步:
哨兵模式
- 监控
- 自动故障恢复:选一个slave提升为master
- 服务发现来源
分片集群
略