分布式缓存(Redis)

Redis面试复习总结

2019-05-25  本文已影响0人  _Zy

该文章是建立在已经对Redis有初步了解和使用经验的情况下。
目的是梳理Redis的知识点,查漏补缺。
如果是新手,简易先学习一下什么是Redis以及如何使用。

Redis已经成为绝大多数互联网公司的核心缓存组件,更多关注的应该是如何用好Redis。

在这里推荐几本书,基本囊括了学习Redis的大部分知识:
Redis开发与运维
Redis设计与实现
Redis in Action(中文版叫 Redis实战)


Redis的优缺点

Redis的优点

1、速度快

Redis是基于key-value模型,类似于HashMap,同时,Redis的数据是存储在内存中的,充分利用了纯内存操作的的高性能和HashMap的查找时间优势。

2、丰富的数据类型

Redis支持的五种数据类型:string, list, set, sorted set, hash。
Redis单个Value支持的最大容量限制是1GB。因此可以由很多功能,例如:

3、丰富的特性

Redis提供了诸多特性,例如:

在 Redis5.0 新增了 Stream 功能,一个新的强大的支持多播和可持久化的消息队列,功能类似于kafka。

4、持久化存储

Redis支持持久化存储,解决万一Redis挂掉导致的数据丢失问题。
主要持久化方案分为:RDB 和 AOF

Redis的缺点

1、由于 Redis 是内存数据库,所以,单台机器存储的数据量,受限于机器本身的内存大小。虽然Redis自身也有内存回收策略,但还是需要提前预估内存使用和节约内存,如果内存增长过快,需要定期删除过期的Key。
另外,可以使用 Redis Cluster,Codis 等方案,构建Redis集群。

2、进行完整同步,由于需要生成RDB文件并且进行传输,这个时候会占用宿主机的CPU,并且会小号网络带宽。
在 Redis 2.8 版本之后,已经支持部分重同步的功能,但还是有需要完整重同步的情况,例如,新上线一台备机。

3、修改配置文件,进行重启,将硬盘中的持久化数据装载入内存耗时比较久,这个过程中 Redis 无法提供服务。


Redis 和 Memcached 的区别

面试问的比较多,但感觉这个问题很无脑,因为Memcached已经很少很少用到了,这个问题主要还是说 Redis 的优势。

个人感觉,与其花时间记区别,不如好好深入研究一下Redis的特性和内部原理。


Redis的线程模型

Redis内部使用文件事件处理器 file event handler
这个文件事件处理器是单线程的,所以,Redis 才叫做单线程的模型。
它采用 IO 多路复用机制,同时监听多个 socket ,根据 socket 上的事件来选择对应的事件处理器进行处理。

文件事件处理器的结构包含4部分:

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是IO 多路复用程序会监听多个 socket,将 socket 产生的事件放入一个等待队列中,事件分派器每次从等待队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

客户端与Redis的一次通信过程

客户端与Redis的一次通信过程:

这样,便完成了一次通信


为什么 Redis 单线程模型也能效率这么高

1、纯内存操作。
Redis为了达到最快的读写速度,将数据全部都读取到内存中,并通过异步的方式将数据持久化到磁盘,所以Redis具有快速 和 持久化 的特性。
如果不放在内存中,硬盘 I/O 将严重影响 Redis 性能

2、核心是基于非阻塞 IO 的多路复用机制

3、单线程避免了多线程的频繁上下文切换问题

4、Redis 全部使用Hash结构,根据Key查找Value的时间复杂度为O(1)。
还有一些特殊的数据结构,同时对数据存储进行了优化,例如:
压缩表:对端数据进行压缩存储
跳表:使用有序的数据结构加快读取速度。


Redis 的持久化方式

持久化方式

1、【全量】RDB持久化
是指在指定的时间间隔内,将内存中 数据集快照 写入磁盘。
实际操作过程是:fork一个子进程,先将数据集写入临时文件,写入成功后,再替换上一次RDB的持久化文件。用二进制压缩存储。

2、【增量】AOF持久化
以日志的形式记录服务器所处理的每一个 写,删除操作,查询操作不会记录,以文本方式记录,可以打开文件看到详细的操作记录。

RDB优缺点

优点

1、可以灵活设置备份频率和周期。

2、非常适合冷备份,对于灾难恢复,RDB是非常不错的选择。
因为我们可以非常轻松的将一个单独文件压缩,然后转移到其他存储介质上。

3、性能最大化。
对于Redis服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后由子进程完成持久化操作。也就是说,RDB对Redis对外提供的读写服务影响非常小,可以让Redis持续保持高性能。

4、恢复更快。
相比于AOF而言,RDB恢复速度更快,更适合数据恢复,特别是在数据量非常大的情况。

缺点

1、无法保证高可用性。如果系统在下一次持久化之前宕机,那么这个过程中的数据将丢失。
(所以实际场景下,需要 RDB 和 AOF 一起使用)

2、RDB是通过子进程写出来完成持久化的,如果数据集很大,可能会导致整个服务器停止较长时间,几百毫秒,甚至1秒钟。
(所以,RDB建议在业务低谷进行,例如凌晨)

AOF优缺点

优点

1、该机制可以带来高可用性,即更高的数据安全性。Redis提供了 3 种AOF同步策略。即秒同步、每修改同步,和不同步。

2、该机制对日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机,也不会破坏日志文件中已经存在的内容。

3、如果日志过大,redis可以自动启动 rewrite机制
即使出现后台重写操作,也不会影响客户顿的读写。因为在 rewrite log 的时候,会对其中的指令进行压缩,创建一份需要恢复数据的最小日子出来。再创建新日志文件的时候,老的日志文件照常写入。
当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。
(即将切换磁盘时,redis在写入老磁盘文件的同时,也会新建一个文件用于记录此期间执行的命令。以保证在rewrite有更高的数据安全性)

4、AOF包含一个格式清晰,易于理解的日志文件,用于记录所有的 修改操作。事实上,我们也可以通过AOF文件完成数据重建。

缺点

1、对于相同数量的数据集而言,AOF文件比RDB文件要大,恢复速度也更慢。

2、根据同步策略的不同,AOF在运行效率上要慢于RDB。
秒同步效率是比较高的,不同步的效率和RDB一样。

3、AOF数据恢复会更脆弱。容易出Bug。


如何选择

1、不要仅仅使用RDB,这样数据丢失的风险很大。

2、不要仅仅使用 AOF,因为这样有两个问题。
第一、AOF的数据冷备份没有RDB的冷备份恢复速度快。
第二、RDB每次直接生成数据快照更加健壮,避免AOF这种复杂机制的Bug。

3、Redis支持同时开启两种持久化模式,我们可以综合使用两种方式,是希望达到安全的持久化方式。
a)AOF用来保证数据不丢失,作为数据恢复的第一选择。
b)RDB用来做不同程度的数据冷备,在AOF文件丢失或损坏的情况下,用RDB来快速恢复。
c)同时使用AOF和RDB,那么在Redis重启的时候,会使用AOF来重建数据,因为AOF中的数据更加完整。

在 Redis4.0 版本开始,允许使用 RDB-AOF 混合持久化方式。
可以参考:Redis4.0之RDB-AOF混合持久化

Redis持久化知识点总结(更适合面试)

1、bgsave做镜像全量持久化,AOF做增量持久化。
因为 bgsave 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF配合使用。
在 Redis 实例重启时,会使用 bgsave 持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。

2、如果突然机器掉电会怎样?
取决于 AOF 日志 sync 属性的配置。如果不要求性能,在每条写指令时都 sync 一下磁盘,就不会丢失数据,达到最高的数据安全性。
但是在高性能的要求下,每次 sync 是不现实的,一般使用定时 sync ,比如1秒一次,这样最多只丢失1秒的数据。

3、bgsave的原理是什么?
两个词汇 fork 和 cow。
fork:是指 Redis 通过创建子进程来进行 bgsave 操作
cow:是指 copy on write ,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
bgsave 操作后,会产生 RDB 快照文件。

实际案例

实际场景下:主 AOF,从 RDB+AOF

Q:为什么不建议在 主 Redis 上开启 RDB 呢?
A:因为会带来一定时间的阻塞,特别是数据量大的时候。


Redis数据过期策略

Redis的过期策略,就是指当 Redis 中缓存的 key 过期了, Redis如何处理。
提供了 3 种过期策略:
1、被动删除:当读/写 一个已经过期的 key 时,会触发惰性删除策略,直接删除这个过期的 key。
2、定期删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已经过期的 key。
3、主动删除:当前已用内存,超过设定的 maxmemory 限制时,触发主动清理策略,即内存淘汰策略(下面讲到)。


Redis数据淘汰策略

如何配置

可以通过配置 redis.conf 中的 maxmemory 来开启内存淘汰功能。

Redis 也支持动态配置,无需重启:

config set maxmemory 100000
config set maxmemory-policy noeviction // no-eviction 表示没有使用限制

内存淘汰策略

当Redis内存占用达到限制时,就会触发数据淘汰策略。Redis提供了 6 种数据淘汰策略:

volatile-lru: 从设置过期时间的数据集中,选择最近最少使用的淘汰。
volatile-ttl: 从设置过期时间的数据集中,选择即将要过期的数据淘汰。
volatile-random: 从设置过期时间的数据集中,随机选择数据淘汰。
allkeys-lru: 从数据集中,挑选最近最少使用的淘汰。
allkeys-random: 从数据集中,随机选择数据淘汰。
no-envicition: 禁止驱逐数据

Redis确定驱逐某个键值对后,会删除这个数据,并将数据变更消息发布到本地(AOF持久化)和从机(主从链接)

LRU淘汰机制

Redis的 LRU 并不是严格的LRU实现,只是一个近似的LRU实现。

淘汰机制:在数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
所以,redis并不是保证取得所有数据集中最少使用(LRU)的键值对,而只是随机挑选的几个中,最少使用的

TTL淘汰机制

redis 数据集数据结构中保存了键值对过期时间表,即 redisDb.expires。

淘汰机制:和 LRU 数据淘汰机制类似,TTL淘汰机制是,从过期时间的表中随机挑选几个键值对,取出其中 ttl 最大的键值对淘汰。

所以和LRU类似,redis并不是保证取得的数据是所有过期时间表中最快过期的,而是从随机取得的数据集中选择最快过期的

如何选择淘汰策略

每个淘汰策略都有不同的适用场景:

allkeys-lru:
如果我们的应用对缓存的访问符合幂律分布,也就是存在相对热点的数据,或者我们不太清楚我们的应用缓存访问分布状况,那么建议选择 allkes-lru 策略。

allkeys-random:
如果我们的应用对于缓存 key 的访问概率相等,那么可以使用这个策略

volatile-ttl:
这种策略使得我们可以向 Redis 提示哪些 key 更适合被驱逐

volatile-lru,volatile-ttl
适合我们将一个 Redis 实例既应用于缓存 又应用于持久化存储的时候,然而我们可以使用两个 Redis 实例来达到相同效果。

Redis 将 key 设置过期将消耗更对内存,因此建议使用 allkeys-lru 策略从而更有效的使用内存


Redis有哪些数据结构

初级:

中级,可以加上下面几个:

高级,比如玩过 Redis Module,可以加上下面几个数据结构:

另外,Redis5.0 新增加了 Stream 功能,一个新的强大的支持多播的可持久化消息队列,提供类似 Kafka 的功能。


Redis的使用场景

Redis可用的场景非常之多:


Redis支持的客户端有哪些

Redis 官方推荐使用 Redisson 或 Jedis
Spring-boot 2.x 内置使用 Lettuce

1、Redisson

Redisson ,是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

2、Jedis

Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支持。
Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,Jedis 功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等 Redis 特性。
Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

3、Lettuce

Lettuc e是一个可伸缩线程安全的 Redis 客户端。多个线程可以共享同一个 RedisConnection 。它利用优秀 Netty NIO 框架来高效地管理多个连接。


如何用Redis实现分布式锁

1、使用 SET key value EX NX 命令。
在设置ex的同时,可以设置过期时间。(在往期文章里有讲到)

2、Redlock 方案。
SET指令的方案,适用于单机Redis节点场景下。对于多 Redis 节点场景下,会存在分布式锁丢失问题。
所以 Redis 作者 Antriez 基于分布式环境下提出了一种更高级的分布式锁实现方式:Redlock。

具体方案可以参考文末链接,这里就不细讲了



(如果有什么错误或者建议,欢迎留言指出)
(本文内容是对各个知识点的转载整理,用于个人技术沉淀,以及大家学习交流用)


参考资料:
芋道源码
Redis设计与实现——RDB
Redis设计与实现——AOF
Redis实战——内存淘汰机制
深入剖析 redis 数据淘汰策略
Redis 事务锁CAS实现以及深入误区
Redis内存优化
为什么Redis单线程却能支撑高并发

Redis的使用场景相关:
聊聊 Redis 的使用场景
Redis 应用场景及实例
Redis 常见的应用场景解析

Redis分布式锁相关
Redis分布式锁的正确实现方式(Java版)
Redlock:redis分布式锁最牛逼的实现
Redisson 实现Redis 分布式锁的N种姿势

Redis高可用
Redis Sentnel 实现高可用
Redis Cluster教程

Redis面试题
Redis面试题
史上最全 Redis 面试题及答案
天下无难试之 Redis 面试题刁难大全

上一篇下一篇

猜你喜欢

热点阅读