共计 2594 个字符,预计需要花费 7 分钟才能阅读完成。
Redis 介绍
Redis 是一个应用 C 语言开发的数据库,Redis 数据存储在内存中,所以读写速度十分快。
利用场景
- 数据(热点)⾼并发的读写
- 海量数据的读写
- 对扩展性要求⾼的数据
分布式缓存和本地缓存的区别
分布式缓存
本地缓存
缓存一致性
较好
较弱,每个实例都有本人的缓存
堆内存占用
不占用
占用,影响垃圾回收
速度
较慢,因为须要网络传输和序列化
较快
应用场景
要求数据一致性,访问量大的场景
对数据一致性没有特地高的要求,且拜访次数多的场景
本地缓存的实现:
- 应用特定数据结构,比方 ConcurrentHashMap
- 使⽤开源的缓存框架 Ehcache,Ehcache 封装了对于内存操作的性能
- Guava Cache 是 Google 开源的⼯具集,提供了缓存的边界操作⼯具、
Redis 和 Memcache 的区别
Redis
Memcache
存储形式
长久化
断电失落
反对数据类型不同
String,hash,list,set,zset
只反对 key-value
速度
快
慢
缓存解决流程
常见数据结构
- String(字符串)
最大容量为 512M
- list(列表)
list 是字符串列表,依照插⼊程序排序。元素能够在列表的头部(右边)或者尾部(左边)进⾏增加。最大容量为 2^32-1 个。能够做音讯队列。
- hash(哈希)
Redis hash 是⼀个键值对(key-value)汇合。Redis hash 是⼀个 String 类型的 field 和 value 的映射表,hash 特地适宜⽤于存储对象。最大容量为 2^32-1 个。
- set(汇合)
Redis 的 set 是 String 类型的⽆序汇合。最大容量为 2^32-1 个。
- zset(sorted set:有序汇合)
Redis zset 和 set ⼀样也是 String 类型元素的汇合,且 不容许反复的成员。不同的 zset 是每个元素都会关联⼀个 double 类型的分数。zset 通过这个分数来为汇合中所有元素进⾏从⼩到⼤的排序。zset 的成员是唯⼀的,但分数(score)却能够反复。最大容量为 2^32-1 个。适宜做排行榜。
zset 底层实现
跳表,这篇文章对跳表进行了具体的解说:
www.jianshu.com/p/dc252b5ef…
过期删除策略
常见的删除策略:
- 定时删除:设置过期工夫的同时,创立一个 timer,过期工夫一到就被动删除
- 惰性删除:放任不管,每次获取时,才判断是否过期,过期就删除,属于被动删除
- 定期删除:每隔一段时间就对数据库进行一次删除过期键的操作
Redis 采纳惰性删除 + 定期删除的形式治理键。既减小 cpu 压力的同时,也保障了数据的准确性。
内存淘汰机制
因为可能产生,既没有被惰性删除也没有被定期删除,但内存很快满了的状况呈现,所以须要肯定的内存淘汰机制。有 6 中淘汰策略:
- no-eviction:不会持续服务 写申请 , 读申请 能够持续进行。这样能够保障不会失落数据,然而会让线上的业务不能继续进行。这是默认的淘汰策略。
- volatile-lru:尝试 淘汰设置了过期工夫 的 key,起码应用的 key 优先被淘汰。没有设置过期工夫的 key 不会被淘汰,这样能够保障须要长久化的数据不会忽然失落。(这个是应用最多的)
- volatile-ttl:跟下面一样,除了淘汰的策略不是 LRU,而是 key 的残余寿命 ttl 的值,ttl 越小越优先被淘汰, 即 淘汰将要过期的数据。
- volatile-random:从已设置过期工夫的数据集(server.db[i].expires)中 随机 抉择数据淘汰。
- allkeys-lru:区别于 volatile-lru,这个策略要淘汰的 key 对象是整体的 key 汇合,而不只是过期的 key 汇合。这意味着没有设置过期工夫的 key 也会被淘汰。
- allkeys-random:从整体的 key 汇合(server.db[i].dict)中任意抉择数据淘汰。
长久化机制
- RDB:将 Redis 在内存中的数据库记录定时 dump 到磁盘上的 RDB 长久化。
- AOF:将 Redis 的操作日志以追加的形式写入文件。
RDB
RDB 长久化是指在指定的工夫距离内将内存中的数据集快照写⼊磁盘,实际操作过程是 fork ⼀个⼦过程,先将数据集写⼊长期⽂件,写⼊胜利后,再替换之前的⽂件,⽤⼆进制压缩存储。
长处:
- RDB 是紧凑的⼆进制⽂件,⽐较适宜备份,全量复制等场景
- RDB 复原数据远快于 AOF
毛病:
- 无奈实现实时或者秒级长久化
- 新老版本无奈兼容 RDB
AOF
AOF 长久化以⽇志的模式记录服务器所解决的每⼀个写、删除操作,查问操作不会记录,以⽂本的⽅式记录,能够关上⽂件看到具体的操作记录。
长处:
- 更好地爱护数据不失落
- append-only 模式写入性能比拟高
- 适宜做灾难性的误删除紧急复原
毛病:
- 对于同一份文件,AOF 文件要比 RDB 快照大
- 会对 QPS 有所影响
- 数据库复原慢,不适宜做冷备
缓存穿透
查问缓存中没有,数据库也没有的数据会导致缓存穿透。
解决办法:
- 布隆过滤
将所有查问的参数都存储到一个 bitmap 中,查问之前先去 bitmap 外面验证,如果存在就进行底层缓存的数据查问;如果不存在就进行拦挡。
能够用于实现数据字典,进行数据的判重,汇合求交加。
- 缓存空对象
间接缓存一个空对象,然而会有两个问题:
- 缓存将存储更多的键值对,可能会受到歹意攻打,至于内存空间的节约;能够通过设置过期工夫来管制。
- DB 与缓存数据不统一,能够通过异步音讯来进行数据更新的告诉。
缓存雪崩
一段时间内,大量的缓存生效,导致数据库压力忽然增大,导致缓存雪崩。
解决办法:
- 扩散生效工夫
- DB 拜访限度,进行限流
- 多级缓存设计
缓存击穿
缓存中没有,然而数据库中油的数据,这时因为并发用户多,就会造成数据库压力霎时增大。
解决办法:
- 设置热点数据永不过期
- 加互斥锁,使写数据的只有一个线程执行:
缓存更新策略
先更新数据库,再更新缓存
- 会导致线程平安问题
两个线程一起更新数据,就会造成脏数据的问题。
- 更新缓存的复杂度绝对较高
因为个别存入缓存的数据都要通过一系列的计算。
先删除缓存,再更新数据库
可能会导致数据不统一的问题,比方,刚删掉缓存,另一个线程马上读取申请,缓存还是旧的。
解决办法只能是写数据胜利后,再更新一次缓存。
先更新数据库,再删除缓存
可能会造成短暂的数据不统一,在更新数据库胜利后和删除缓存之前,会有肯定的数据不统一景象,不过能够承受。
参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/693720…