导图社区 缓存
重点讲缓存相关,会逐渐补全各种常见缓存技术。缓存是指可以进行高速数据交换的存储器,它先于内存与CPU交换数据,因此速率很快。
编辑于2021-06-21 16:56:02缓存
MongoDB
Redis
功能介绍
数据类型
Redis的发布订阅
Redis的五大数据类型
string(字符串)
String(字符串) string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。 string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。 string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M
hash(哈希,类似java里的Map)
Hash(哈希) Redis hash 是一个键值对集合。 Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 类似Java里面的Map
list(列表)
List(列表) Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。 它的底层实际是个链表
set(集合)
Set(集合) Redis的Set是string类型的无序集合。它是通过HashTable实现实现的,
zset(sorted set:有序集合)
zset(sorted set:有序集合) Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个double类型的分数。 redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
bitmaps
HyperLogLog
GEO
pipeline
功能
bitmap
hyperLogLog
geospatial
pub/sub
pipeline
lua脚本
事务
淘汰策略
定期删除+惰性删除 定期删除:默认没100ms检查删除过期的key,但不是全量检查,而是随机抽取 惰性删除:在获取某个key时,检查该key是否过期,过期则删除 存在的问题:如果定期删除一直没有命中已经过期的key,并且也没有获取该key,那么该key长期占用内存 解决办法:redis内置多种淘汰策略
持久化
RDB(Redis DataBase)
触发机制
手动触发
save
阻塞redis服务器,直到持久化完成
bgsave
fork一个子进程,由子进程完成持久化
自动触发
满足save n m条件 就会自动触发,即m秒内数据集发生n次改变
debug reload
流程说明
1、执行bgsave命令,没有子进程在执行,才会创建成功
2、父进程执行fork操作创建子子进程,fork过程会阻塞,通过info stats命令查看最佳一个fork耗时
3、父进程fork完后,bgsave命令返回background saving started信息,并不在阻塞父进程,响应其他命令
4、子进程创建RDB文件,生成临时快照文件,替换原来的文件
5、进程发送信号给父进程表示完成,父进程更新统计信息
AOF(Append Only File)
开启配置:appendonly yes;默认不开启 Aof保存的是appendonly.aof文件
流程
1、所有写入命令会追加到aof_buf缓冲区中
2、AOF缓冲区根据对应的策略向硬盘做同步操作
3、AOF超过配置最大值,会进行重写
4、redis重启时,会加载AOF文件进行数据恢复
重写机制
为了防止文件过大
手动触发
bgrewriteaof
自动触发
auto-aof-rewrite-min-size和auto-aof-rewrite-percentage
流程
1、执行AOF重写请求
2、父进程执行fork创建子进程
3、父进程fork完后继续响应其他命令
4、子进程根据内存快照,按照命令合并规则写入到新的AOF文件
5、新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,父进程把AOF重写缓冲区的数据写入到新的AOF文件,使用新AOF文件替换老文件,完成AOF重写
重启加载
流程
1、AOF持久化开启且存在AOF文件时,优先加载AOF文件
2、AOF关闭或者AOF文件不存在时,加载RDB文件
3、加载AOF/RDB文件成功后,redis启动成功
4、AOF/RDB文件存在错误时,redis启动失败并打印错误信息
集群
Sentinel哨兵
主从同步
master选举
4.0/5.0新特性
其他
应用场景
redis可以做什么
缓存
排行榜系统
计数器应用
社交网络
消息队列系统
redis不可以做什么
存储大数据成本高
冷数据放redis浪费资源
面试
Redis为什么这么快?
(一)纯内存操作 (二)单线程操作,避免了频繁的上下文切换 (三)采用了非阻塞I/O多路复用机制
基础理论
类型
本地缓存
本地缓存就是在进程的内存中进行缓存,比如我们的 JVM 堆中,可以用 LRUMap 来实现,也可以使用 Ehcache 这样的工具来实现。 优势:本地缓存相对于分布式缓存,没有远程交互的时间和性能损耗,速度相对更快
分布式缓存
分布式系统中,将缓存单独提成一个独立的集群,业务服务通过远程调用的方式进行读写操作。
对比
本地缓存相对分布式缓存没有远程交互的损耗,速度较快,但是本地缓存依赖于当前服务所在进程,对本地缓存的内存是个很大的挑战,同时也将缓存与业务耦合在一起。 分布式缓存则是抽象成独立的集群,易于扩展,且扩展对于业务服务透明,但多了远程交互。
多级缓存
实际业务当中一般是 本地缓存和分布式缓存相结合使用,优先本地,分布式缓存次之
缓存问题
缓存不一致
概念
缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据! 解决思路: 1、直接写个缓存刷新页面,上线时手工操作下; 2、数据量不大,可以在项目启动的时候自动进行加载; 3、定时刷新缓存;
缓存更新
失效更新
有些数据依赖于远程服务,但是远程服务又无法及时更新,则可以采用失效更新 也有一种可能是该数据对于实时性要求不高时,也可采用失效更新
主动更新
部分数据需要随业务数据的变动而实时更新,此时就需要在业务服务更新DB以后来更新缓存,当缓存更新失败时需要业务服务回滚DB更新
定时分批更新
有些数据无需实时获取,此时可以采用定时任务的方式分批更新
缓存降级
常见问题
建议 不管是数据库查询,还是redis查询,尽量校验key的有效值,如范围等,不要相信任何一个客户端的调用参数
缓存雪崩
缓存挂掉,或者大面积缓存失效,短时间内,大量请求均穿透到DB,DB高负载导致系统异常 解决方案 1、设置缓存key失效时间是加上随机值,避免批量缓存在同一个时间段大面积失效 2、部分非常热的数据可以设置为永不过期,然后通过定时任务的方式去剔除已失效的数据 3、快速失败熔断,减少DB的压力 4、尽量加固redis集群以保证提供更可靠的服务
缓存击穿
缓存击穿的特点在于某个或者某几个非常热的key失效,导致瞬间大量请求到达了DB,造成DB卡死等 解决方案 1、缓存中没有,去DB拿数据时添加互斥锁
对比
缓存击穿 关注的是 非常热的某个key在瞬间失效 雪崩则关注的是大面积key失效,导致请求聚集到DB,也就是说非热点key是可以容忍在短时间失效的
缓存穿透
问题:缓存穿透是指缓存和DB中都没有对应的值,而请求不断的被发起,此时会穿透到数据库,造成数据库卡死等 解决方案 1、对查询做校验,比如用户的code值范围是0到100,此时就可以针对code做范围校验,超过范围直接返回 2、对于不存在的对象在缓存中保存空对象,注意有效时间不要太长 3、BloomFilter 4、当缓存和DB都没有拿到时,添加本地缓存
淘汰策略
FIFO
依据写入时间,淘汰最早写入数据
LRU
依据被访问时间,剔除最久访问的记录
LFU
依据使用的频次,剔除最少访问次数的记录