Redis相关知识汇总

目录

一、数据类型

二、各数据类型容量

三、Redis持久化机制和优缺点

四、过期键的删除策略

五、回收策略

六、Redis集群策略

七、缓存穿透、缓存击穿、缓存雪崩分别是什么

八、Redis和Mysql如何保证数据一致性

九、Redis分布式锁底层是如何实现的

十、Redis主从复制原理


一、数据类型

String:字符串

Hash:哈希

List:列表

Set:集合

Sorted set:有序集合

二、各数据类型容量

String:512M

Hash:键值对个数最多为2^32 - 1

List:元素个数个数最多为2^32 - 1

Set:元素个数个数最多为2^32 - 1

Sorted set:元素个数个数最多为2^32 - 1

三、Redis持久化机制和优缺点

RDB(默认)和AOF

RDB:

按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期;记录Redis数据库的所有键值对,在某个时间点将数据写入一个临时文件持久化结束后,用这个临时文件替换上次持久化的文件达到数据恢复

优点:

1、只有一个文件 dump.rdb,方便持久化;

2、容灾性好,一个文件可以保存到安全的磁盘;

3、性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了Redis的高性能;

4、相对于数据集大时,比 AOF 的启动效率更高;

缺点:

1、数据安全性低;

2、RDB 是间隔一段时间进行持久化,如果在持久化时Redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候;

AOF:

是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。当两种方式同时开启时数据恢复Redis会优先选择AOF恢复;

优点:

1、数据安全,AOF持久化可以配置 appendfsync 属性,有always属性,每进行一次命令操作就记录到AOF文件中一次;

2、通过append模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题;

3、AOF机制的rewrite模式。AOF文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall);

缺点:

1、AOF文件比RDB文件大,且恢复速度慢;

2、数据集大的时候,比RDB启动效率低;

四、过期键的删除策略

定时删除:

在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作

惰性删除:

键过期了就过期了,不管。每次从dict字典中按key取值时,先检查此key是否已经过期,如果过期了就删除它,并返回nil,如果没过期,就返回键值

定期删除:

每隔一段时间,对expires字典进行检查,删除里面的过期键

Redis使用的是惰性删除策略和定期删除策略,两者配合使用

五、回收策略

maxmemory-policy,可以设置内存达到最大闲置后,采取什么策略来处理

noeviction:Redis默认策略,不回收数据,当内存不足以容纳新写入数据时,新增数据返回error
allkeys-lru:从数据集中,淘汰最近最少使用的数据
allkeys-random:从数据集中,随机移除某个key
volatile-lru:从已设置过期时间的数据集中,淘汰最近最少使用的数据
volatile-random:从已设置过期时间的数据集中,随机移除某个key
volatile-ttl:从已设置过期时间的数据集中,淘汰最早会过期的数据

六、Redis集群策略

        Redis提供了三种集群策略:

1. 主从模式:

这种模式⽐较简单,主库可以读写,并且会和从库进⾏数据同步,这种模式下,客户端 直接连主库或某个从库,但是但主库或从库宕机后,客户端需要⼿动修改IP,另外,这种模式也⽐ 较难进⾏扩容,整个集群所能存储的数据受到某台机器的内存容量,所以不可能⽀持特⼤数据量

2. 哨兵模式:

这种模式在主从的基础上新增了哨兵节点,但主库节点宕机后,哨兵会发现主库节点宕 机,然后在从库中选择⼀个库作为进的主库,另外哨兵也可以做集群,从⽽可以保证但某⼀个哨兵 节点宕机后,还有其他哨兵节点可以继续⼯作,这种模式可以⽐较好的保证Redis集群的⾼可⽤,但 是仍然不能很好的解决Redis的容量上限问题。

3. Cluster模式:

Cluster模式是⽤得⽐较多的模式,它⽀持多主多从,这种模式会按照key进⾏槽位的 分配,可以使得不同的key分散到不同的主节点上,利⽤这种模式可以使得整个集群⽀持更⼤的数据 Redis分布式锁底层是如何实现的? Redis主从复制的核⼼原理 Redis集群策略 39 容量,同时每个主节点可以拥有⾃⼰的多个从节点,如果该主节点宕机,会从它的从节点中选举⼀ 个新的主节点。

        对于这三种模式,如果Redis要存的数据量不⼤,可以选择哨兵模式,如果Redis要存的数据量⼤,并且 需要持续的扩容,那么选择Cluster模式

七、缓存穿透、缓存击穿、缓存雪崩分别是什么

        缓存中存放的⼤多都是热点数据,⽬的就是防⽌请求可以直接从缓存中获取到数据,⽽不⽤访问 Mysql。

1. 缓存雪崩:

如果缓存中某⼀时刻⼤批热点数据同时过期,那么就可能导致⼤量请求直接访问Mysql 了,解决办法就是在过期时间上增加⼀点随机值,另外如果搭建⼀个⾼可⽤的Redis集群也是防⽌缓 存雪崩的有效⼿段

2. 缓存击穿:

和缓存雪崩类似,缓存雪崩是⼤批热点数据失效,⽽缓存击穿是指某⼀个热点key突然失 效,也导致了⼤量请求直接访问Mysql数据库,这就是缓存击穿,解决⽅案就是考虑这个热点key不 设过期时间

3. 缓存穿透:

假如某⼀时刻访问redis的⼤量key都在redis中不存在(⽐如⿊客故意伪造⼀些乱七⼋糟 的key),那么也会给数据造成压⼒,这就是缓存穿透,解决⽅案是使⽤布隆过滤器,它的作⽤就是 如果它认为⼀个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加⼀层布隆过滤器来 拦截不存在的key

面试回答: 

缓存雪崩:就是存储在缓存里面的大量数据,在同一个时刻全部过期, 原本缓存组件抗住的大部分流量全部请求到了数据库。 导致数据库压力增加造成数据库服务器崩溃的现象。

导致缓存雪崩的主要原因,我认为有两个:

缓存中间件宕机,当然可以对缓存中间件做高可用集群来避免。

缓存中大部分 key 都设置了相同的过期时间,导致同一时刻这些 key 都过期了。 对于这样的情况,可以在失效时间上增加一个 1 到 5 分钟的随机值。

缓存穿透问题:表示是短时间内有大量的不存在的 key 请求到应用里面,而这些 不存在的 key 在缓存里面又找不到,从而全部穿透到了数据库,造成数据库压力。

我认为这个场景的核心问题是针对缓存的一种攻击行为,因为在正常的业务里面, 即便是出现了这样的情况,由于缓存的不断预热,影响不会很大。

而攻击行为就需要具备时间是的持续性,而只有 key 确实在数据库里面也不存在 的情况下,才能达到这个目的,所以,我认为有两个方法可以解决:

1、把无效的 key 也保存到 Redis 里面,并且设置一个特殊的值,比如“null”,这样 的话下次再来访问,就不会去查数据库了。 但是如果攻击者不断用随机的不存在的 key 来访问,也还是会存在问题。

2、可以用布隆过滤器来实现,在系统启动的时候把目标数据全部缓存到布隆过滤器里 面,当攻击者用不存在的 key 来请求的时候,先到布隆过滤器里面查询,如果不 存在,那意味着这个 key 在数据库里面也不存在。

布隆过滤器还有一个好处,就是它采用了 bitmap 来进行数据存储,占用的内存 空间很少。不过,在我看来,您提出来的这个问题,有点过于放大了它带来的影响。

首先,在一个成熟的系统里面,对于比较重要的热点数据,必然会有一个专门缓 存系统来维护,同时它的过期时间的维护必然和其他业务的 key 会有一定的差别。 而且非常重要的场景,我们还会设计多级缓存系统。

其次,即便是触发了缓存雪崩,数据库本身的容灾能力也并没有那么脆弱,数据 库的主从、双主、读写分离这些策略都能够很好的缓解并发流量。

最后,数据库本身也有最大连接数的限制,超过限制的请求会被拒绝,再结合熔 断机制,也能够很好的保护数据库系统,最多就是造成部分用户体验不好。

另外,在程序设计上,为了避免缓存未命中导致大量请求穿透到数据库的问题, 还可以在访问数据库这个环节加锁。虽然影响了性能,但是对系统是安全的。

八、Redis和Mysql如何保证数据一致性

1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不⼀致

2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种⽅案能解决1 ⽅案的问题,但是在⾼并发下性能较低,⽽且仍然会出现数据不⼀致的问题,⽐如线程1删除了 Redis缓存数据,正在更新Mysql,此时另外⼀个查询再查询,那么就会把Mysql中⽼数据⼜查到 Redis中

3. 延时双删,步骤是:先删除Redis缓存数据,再更新Mysql,延迟⼏百毫秒再删除Redis缓存数据, 这样就算在更新Mysql时,有其他线程读了Mysql,把⽼数据读到了Redis中,那么也会被删除掉, 从⽽把数据保持⼀致

面试回答:

一般情况下,Redis 用来实现应用和数据库之间读操作的缓存层,主要目的是减少数据库 IO,还可以提升数据的 IO 性能。

当应用程序需要去读取某个数据的时候,首先会先尝试去 Redis 里面加载,如果命中就直接返回。如果没有命中,就从数据库查询,查询到数据后再把这个数据 缓存到 Redis 里面。

在这样一个架构中,会出现一个问题,就是一份数据,同时保存在数据库和 Redis 里面,当数据发生变化的时候,需要同时更新 Redis 和 Mysql,由于更新是有先 后顺序的,并且它不像 Mysql 中的多表事务操作,可以满足 ACID 特性。所以就会出现数据一致性问题。

在这种情况下,能够选择的方法只有几种。

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

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

如果先更新数据库,再更新缓存,如果缓存更新失败,就会导致数据库和 Redis 中的数据不一致。

如果是先删除缓存,再更新数据库,理想情况是应用下次访问 Redis 的时候,发 现 Redis 里面的数据是空的,就从数据库加载保存到 Redis 里面,那么数据是 一致的。但是在极端情况下,由于删除 Redis 和更新数据库这两个操作并不是原 子的,所以这个过程如果有其他线程来访问,还是会存在数据不一致问题。

所以,如果需要在极端情况下仍然保证 Redis 和 Mysql 的数据一致性,就只能采用最终一致性方案。

1、基于 RocketMQ 的可靠性消息通信,来实现最终一致性

2、直接通过 Canal 组件,监控 Mysql 中 binlog 的日志,把更新后的数据同 步到 Redis 里面

3、使用分布式锁,在更新数据之前,使用Redis的分布式锁来确保同一时间只有一个进程或线程可以访问和修改数据。这可以防止并发操作导致的数据不一致问题

九、Redis分布式锁底层是如何实现的

1. ⾸先利⽤setnx来保证:如果key不存在才能获取到锁,如果key存在,则获取不到锁

2. 然后还要利⽤lua脚本来保证多个redis操作的原⼦性

3. 同时还要考虑到锁过期,所以需要额外的⼀个看⻔狗定时任务来监听锁是否需要续约

4. 同时还要考虑到redis节点挂掉后的情况,所以需要采⽤红锁的⽅式来同时向N/2+1个节点申请锁, 都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到

 代码实现方式:

1、利用 Redis 提供的 SET key value NX PX milliseconds 指令,这个指令是设置一个 key-value,如果 key 已经存在,则返回 0,否则返回 1,我们基于这个返回值来 判断锁的占用情况从而实现分布式锁。

2、基于 Redission 客户端来实现分布式锁,Redisson 提供了分布式锁的封装方 法,我们只需要调用 api 中的 lock()和 unlock()方法。它帮我们封装锁实现的细 节和复杂度

redisson 所有指令都通过 lua 脚本执行并支持 lua 脚本原子性执行

redisson 中有一个 watchdog 的概念,翻译过来就是看门狗,它会在你获取锁 之后,每隔 10 秒帮你把 key 的超时时间设为 30s,就算一直持有锁也不会出现 key 过期了。“看门狗”的逻辑保证了没有死锁发生。

十、Redis主从复制原理

        Redis主从复制有两种方式,全量复制和增量复制。

        通过执⾏slaveof命令或设置slaveof选项,让⼀个服务器去复制另⼀个服务器的数据。主数据库可以进 ⾏读写操作,当写操作导致数据变化时会⾃动将数据同步给从数据库。⽽从数据库⼀般是只读的,并接受主数据库同步过来的数据。⼀个主数据库可以拥有多个从数据库,⽽⼀个从数据库只能拥有⼀个主数 据库。

全量复制:

1. 主节点通过bgsave命令fork⼦进程进⾏RDB持久化,该过程是⾮常消耗CPU、内存(⻚表复制)、硬 盘IO的

2. 主节点通过⽹络将RDB⽂件发送给从节点,对主从节点的带宽都会带来很⼤的消耗

3. 从节点清空⽼数据、载⼊新RDB⽂件的过程是阻塞的,⽆法响应客户端的命令;如果从节点执⾏ bgrewriteaof,也会带来额外的消耗

增量复制:

1. 复制偏移量:执⾏复制的双⽅,主从节点,分别会维护⼀个复制偏移量offset

2. 复制积压缓冲区:主节点内部维护了⼀个固定⻓度的、先进先出(FIFO)队列 作为复制积压缓冲区, 当主从节点offset的差距过⼤超过缓冲区⻓度时,将⽆法执⾏部分复制,只能执⾏全量复制。

3. 服务器运⾏ID(runid):每个Redis节点,都有其运⾏ID,运⾏ID由节点在启动时⾃动⽣成,主节点会 将⾃⼰的运⾏ID发送给从节点,从节点会将主节点的运⾏ID存起来。 从节点Redis断开重连的时 候,就是根据运⾏ID来判断同步的进度:

如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续 尝试使⽤部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);

如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不 是当前的主节点,只能进⾏全量复制。

相关推荐

  1. Redis相关知识汇总

    2024-04-10 14:16:03       15 阅读
  2. redis攻防知识汇总

    2024-04-10 14:16:03       9 阅读
  3. Redis相关知识

    2024-04-10 14:16:03       37 阅读
  4. redis 相关知识

    2024-04-10 14:16:03       14 阅读
  5. Redis知识汇总表格总结

    2024-04-10 14:16:03       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-10 14:16:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-10 14:16:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-10 14:16:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-10 14:16:03       20 阅读

热门阅读

  1. vue qrcode生成二维码

    2024-04-10 14:16:03       21 阅读
  2. C++虚继承

    2024-04-10 14:16:03       13 阅读
  3. 游戏盾如何防护支付平台免受DDOS攻击

    2024-04-10 14:16:03       15 阅读
  4. 【Spring学习笔记】1. Hello Spring

    2024-04-10 14:16:03       12 阅读
  5. 富格林:可信技巧规避虚假风险

    2024-04-10 14:16:03       16 阅读
  6. Python中的抽象基类(ABC)

    2024-04-10 14:16:03       19 阅读
  7. adb remount

    2024-04-10 14:16:03       15 阅读