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(哈希)

Re­dis hash 是⼀个键值对(key-value)集合。Re­dis hash 是⼀个 String 类型的 field 和 value 的映射表,hash 特别适合⽤于存储对象。最大容量为 2^32-1 个。

  • set(集合)

Re­dis 的 set 是 String 类型的⽆序集合。最大容量为 2^32-1 个。

  • zset(sorted set:有序集合)

Re­dis zset 和 set ⼀样也是 String 类型元素的集合,且 不允许重复的成员。不同的 zset 是每个元素都会关联⼀个 dou­ble 类型的分数。zset 通过这个分数来为集合中所有元素进⾏从⼩到⼤的排序。zset 的成员是唯⼀的,但分数(score)却可以重复。最大容量为 2^32-1 个。适合做排行榜。

zset底层实现

跳表,这篇文章对跳表进行了详细的讲解:

www.jianshu.com/p/dc252b5ef…

过期删除策略

常见的删除策略:

  • 定时删除:设置过期时间的同时,创建一个timer,过期时间一到就主动删除
  • 惰性删除:放任不管,每次获取时,才判断是否过期,过期就删除,属于被动删除
  • 定期删除:每隔一段时间就对数据库进行一次删除过期键的操作

Re­dis 采用惰性删除 + 定期删除的方式管理键。既减小 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 ⼀个⼦进程,先将数据集写⼊临时⽂件,写⼊成功后,再替换之前的⽂件,⽤⼆进制压缩存储。

优点:

  1. RDB 是紧凑的⼆进制⽂件,⽐较适合备份,全量复制等场景
  2. RDB 恢复数据远快于 AOF

缺点:

  1. 无法实现实时或者秒级持久化
  2. 新老版本无法兼容RDB

AOF

AOF 持久化以⽇志的形式记录服务器所处理的每⼀个写、删除操作,查询操作不会记录,以⽂本的⽅式记录,可以打开⽂件看到详细的操作记录。

优点:

  1. 更好地保护数据不丢失
  2. append-only模式写入性能比较高
  3. 适合做灾难性的误删除紧急恢复

缺点:

  1. 对于同一份文件,AOF文件要比RDB快照大
  2. 会对QPS有所影响
  3. 数据库恢复慢,不适合做冷备

缓存穿透

查询缓存中没有,数据库也没有的数据会导致缓存穿透。

解决方法:

  • 布隆过滤

将所有查询的参数都存储到一个 bitmap 中,查询之前先去 bitmap 里面验证,如果存在就进行底层缓存的数据查询;如果不存在就进行拦截。

可以用于实现数据字典,进行数据的判重,集合求交集。

  • 缓存空对象

直接缓存一个空对象,但是会有两个问题:

  1. 缓存将存储更多的键值对,可能会遭到恶意攻击,至于内存空间的浪费;可以通过设置过期时间来控制。
  2. DB与缓存数据不一致,可以通过异步消息来进行数据更新的通知。

缓存雪崩

一段时间内,大量的缓存失效,导致数据库压力突然增大,导致缓存雪崩。

解决方法:

  • 分散失效时间
  • DB访问限制,进行限流
  • 多级缓存设计

缓存击穿

缓存中没有,但是数据库中油的数据,这时由于并发用户多,就会造成数据库压力瞬间增大。

解决方法:

  1. 设置热点数据永不过期
  2. 加互斥锁,使写数据的只有一个线程执行:

缓存更新策略

先更新数据库,再更新缓存

  • 会导致线程安全问题

两个线程一起更新数据,就会造成脏数据的问题。

  • 更新缓存的复杂度相对较高

因为一般存入缓存的数据都要经过一系列的计算。

先删除缓存,再更新数据库

可能会导致数据不一致的问题,比如,刚删掉缓存,另一个线程马上读取请求,缓存还是旧的。

解决方法只能是写数据成功后,再更新一次缓存。

先更新数据库,再删除缓存

可能会造成短暂的数据不一致,在更新数据库成功后和删除缓存之前,会有一定的数据不一致现象,不过可以接受。

参考:《2020最新Java基础精讲视频教程和学习路线!》
链接:https://juejin.cn/post/693720...


Java攻城师
451 声望390 粉丝

本人太过于丰富,无法简介