Redis

168 阅读21分钟

Redis

直接看小林,硬看完

阿珊:Redis的持久化方式,它的事务,以及缓存击穿,缓存穿透,缓存雪崩,他们对应场景以及为什么这么使用

redis的使用场景

用缓存要注意哪些问题?(缓存与数据库的一致性问题、缓存雪崩、缓存穿透、缓存击穿) 14.redis大对象怎么存储?用什么类型存储?一开始没答上来,面试官引导我问redis有哪些数据类型,然后我答用string,面试官说如果想改其中一个字段,得把整个对象序列化反序列化?我反应过来要用hash,快速查找。

基础

1.说说什么是Redis?

2.Redis可以用来干什么?Redis除了缓存还能做什么+2

  • 分布式锁 : 通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。
  • 限流 :一般是通过 Redis + Lua 脚本的方式来实现限流。
  • 消息队列 :Redis 自带的 list 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。
  • 复杂业务场景 :通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 bitmap 统计活跃用户、通过 sorted set 维护排行榜。

3.Redis 有哪些数据结构?Redis的常用数据结构,+6

5 种基础数据结构 :String(字符串)、List(列表)、Hash(散列)、Set(集合)、Zset(有序集合)。

3 种特殊数据结构 :HyperLogLogs(基数统计)、Bitmap (位存储)、Geospatial (地理位置)。

redis中zset的底层数据结构是什么,为什么用这个

string类型的底层怎么实现的?

Redis 是基于 C 语言编写的,但 Redis 的 String 类型的底层实现并不是 C 语言中的字符串(即以空字符 \0 结尾的字符数组),而是自己编写了 SDS(Simple Dynamic String,简单动态字符串) 来作为底层实现。

SDS 共有五种实现方式,根据初始化的长度决定使用哪种类型

对于后四种实现都包含了下面这 4 个属性:

  • len :字符串的长度也就是已经使用的字节数
  • alloc:总共可用的字符空间大小,alloc-len 就是 SDS 剩余的空间大小
  • buf[] :实际存储字符串的数组
  • flags :低三位保存类型标志

4.Redis为什么快呢?Redis为啥快 redis性能好,为啥能性能好? +2

  • Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了;
  • Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。
  • Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,

5.能说一下I/O多路复用吗?

IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

线程模型

6.Redis为什么早期选择单线程? 为什么Redis6.0之前是单线程(√) +4

官方:CPU 并不是制约 Redis 性能表现的瓶颈所在,更多情况下是受到内存大小和网络I/O的限制,所以 Redis 核心网络模型使用单线程并没有什么问题,如果你想要使用服务的多核CPU,可以在一台服务器上启动多个节点或者采用分片集群的方式。

7.Redis6.0使用多线程是怎么回事?.redis线程?哪里用到多线程?+2

Redis6.0采用了多个 I/O 线程来处理网络请求,但是Redis执行命令还是单线程的。

这样做的⽬的是因为Redis的性能瓶颈在于网络IO而非CPU,使⽤多线程能提升IO读写的效率

redis的单线程怎么理解?Redis是单线程还是多线程?

Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。

Redis 程序并不是单线程的,Redis 在启动的时候,是会启动后台线程(BIO)的:

Redis 为「关闭文件、AOF 刷盘、释放内存」这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的。

后台线程相当于一个消费者,生产者把耗时任务丢到任务队列中,消费者(BIO)不停轮询这个队列,拿出任务就去执行对应的方法即可。

img

因此, Redis 6.0 版本之后,Redis 在启动的时候,默认情况下会额外创建 6 个线程这里的线程数不包括主线程):

  • Redis-server : Redis的主线程,主要负责执行命令;
  • bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;
  • io_thd_1、io_thd_2、io_thd_3:三个 I/O 线程,io-threads 默认是 4 ,所以会启动 3(4-1)个 I/O 多线程,用来分担 Redis 网络 I/O 的压力。

持久化

8.Redis持久化⽅式有哪些?有什么区别? +3

  • AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
  • 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;

9.RDB 和 AOF 各自有什么优缺点?

  • RDB 文件存储的内容是经过压缩的二进制数据, 保存着某个时间点的数据集,文件很小,适合做数据的备份,灾难恢复。AOF 文件存储的是每一次写命令,类似于 MySQL 的 binlog 日志,通常会必 RDB 文件大很多。
  • 使用 RDB 文件恢复数据,直接解析还原数据即可,不需要一条一条地执行命令,速度非常快。而 AOF 则需要依次执行每个写命令,速度非常慢。也就是说,与 AOF 相比,恢复大数据集的时候,RDB 速度更快。
  • RDB 的数据安全性不如 AOF,没有办法实时或者秒级持久化数据。生成 RDB 文件的过程是比较繁重的, 虽然 BGSAVE 子进程写入 RDB 文件的工作不会阻塞主线程,但会对机器的 CPU 资源和内存资源产生影响,严重的情况下甚至会直接把 Redis 服务干宕机。AOF 支持秒级数据丢失(取决 fsync 策略,如果是 everysec,最多丢失 1 秒的数据),仅仅是追加命令到 AOF 文件,操作轻量。
  • RDB 文件是以特定的二进制格式保存的,并且在 Redis 版本演进中有多个版本的 RDB,所以存在老版本的 Redis 服务不兼容新版本的 RDB 格式的问题。
  • AOF 以一种易于理解和解析的格式包含所有操作的日志。你可以轻松地导出 AOF 文件进行分析,你也可以直接操作 AOF 文件来解决一些问题。比如,如果执行FLUSHALL命令意外地刷新了所有内容后,只要 AOF 文件没有被重写,删除最新命令并重启即可恢复之前的状态。

10.RDB和AOF如何选择?

11.Redis的数据恢复?

12.Redis 4.0 的混合持久化了解吗?

由于 RDB 和 AOF 各有优势,于是,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化

混合持久化工作在 AOF 日志重写过程,当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,

然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据

AOF是如何实现的?

Redis 在执行完一条写操作命令后,就会把该命令以追加的方式写入到一个文件里,然后 Redis 重启时,会读取该文件记录的命令,然后逐一执行命令的方式来进行数据恢复。

AOF 重写了解吗?

当 AOF 变得太大时,Redis 能够在后台自动重写 AOF 产生一个新的 AOF 文件,这个新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样,但体积更小。

在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。

RDB

RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据,而 AOF 文件记录的是命令操作的日志,而不是实际的数据。

RDB 创建快照时会阻塞主线程吗?

  • save : 同步保存操作,会阻塞 Redis 主线程;
  • bgsave : fork 出一个子进程,子进程执行,不会阻塞 Redis 主线程,默认选项。

高可用/集群

redis集群模式

1)主从复制

将一台Redis服务器,同步数据到多台从Redis服务器上,也就是一主多从。 读写分离,主服务器进行读写操作,从服务器只读。 发生写操作以后,自动同步给从服务器。

主从复制是异步进行的。主服务器在收到新的写命令后,会发送给从服务器。但是主服务器不会等从服务器执行完命令后再把结果返回客户端,而是主服务自己执行完就直接返回结果了。无法保证强一致性。

哨兵模式 +2

主从模式中如果主服务器挂了,那么就无法执行服务器的写操作,也无法给从节点进行数据同步了。 如果要恢复必须人工介入,选择一个从节点切换为主节点,并且让其他从节点指向新主节点,同时还要通知上游连接Redis的客户端 更新主节点的IP地址。

Redis2.8以后哨兵机制,实现主从故障转移。他会检测主节点是否存活,如果主节点挂了,会选举一个新的主节点,并且通知从节点和客户端。 监控、选主、通知。

监控 哨兵会每隔1秒给所有主从节点发PING,主从节点收到后会返回一个响应命令。 如果没有在规定时间内相应那么会被标记为 主观下线。 「规定的时间」是配置项 down-after-milliseconds 参数设定的,单位是毫秒。

对主节点还有客观下线。 设置两个状态,因为主节点可能并没有故障,可能只是因为主节点的系统压力比较大或者网络发生拥塞,导致主节点没有在规定时间内响应PING。 为了减少误判,哨兵集群(至少3台)会通过多个哨兵一起判断,避免单个哨兵因为自身网络不好导致的误判主节点下线。 多个哨兵网络同时不稳定的概率较低,误判率降低。

如何判定客观下线呢? 当一个哨兵判断主节点为「主观下线」后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应。

当这个哨兵的赞同票超过quorum后,这个节点会被标记为 客观下线。 (quorum一般设为哨兵个数的二分之一加1)

选主

由哪个哨兵进行主从故障转移呢? 会在哨兵集群中选一个leader来执行。

哪个哨兵节点判断主节点为主观下线,那么他就是候选者。 候选者会向其他哨兵发送命令,表明希望成为leader,每一个哨兵只能投一票。每个候选者都会先投自己一票。

候选者满足两个条件就可以成为leader: 1)拿到半数以上的票 2)票数>= quorum

通知

1.在旧主节点的所有从节点中选出一个做为新主节点。 2.让旧主节点的其他所有从节点,修改为复制新主节点 3.让新主节点的ip和信息,通过发布订阅模式,通知给客户端 4.继续监视旧主节点,当这个旧主节点上线的时候,将他设置为新主节点的从节点。

哨兵集群是如何组成的 哨兵节点是通过Redis的发布订阅模式相互发现的。

切片集群模式

一个库的数据一台服务无法缓存的时候,就需要切片集群,将数据分布在不同的服务器上。

Redis cluster 采用哈希槽 Hash Slot,来处理数据和节点之间的映射关系。 一个切片集群有16384个哈希槽。

每个键值都会根据他的key被映射到一个哈希槽中。

集群脑裂

13.主从复制了解吗? 14.Redis主从有几种常见的拓扑结构? 15.Redis的主从复制原理了解吗? 16.说说主从数据同步的方式? 17.主从复制存在哪些问题呢? 18.Redis Sentinel(哨兵)了解吗? 19.Redis Sentinel(哨兵)实现原理知道吗? 20.领导者Sentinel节点选举了解吗? 21.新的主节点是怎样被挑选出来的? 22.Redis 集群了解吗? 23.集群中数据如何分区? 24.能说说Redis集群的原理吗? 25.说说集群的伸缩?

Redis 过期删除与内存淘汰

redis的过期策略

Redis 使用的过期删除策略是「惰性删除+定期删除」这两种策略配和使用。

惰性删除策略的做法是,不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。

定期删除策略的做法是,每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。

缓存设计

26.什么是缓存击穿、缓存穿透、缓存雪崩? 如何预防 +7

Redis缓存雪崩、穿透怎么应对处理?

深入问了怎么通过加锁的方式预防缓存击穿(× 真不会)

缓存雪崩怎么解决?加随机时间怎么保证不在同一时间失效?还有什么解决办法

如何避免缓存雪崩?

为了保证缓存中的数据和数据库中的数据一致,会给Redis设置过期时间。 当大量缓存在同一时间失效时,如果有大量用户请求,就会去直接访问数据库,数据库压力骤增,可能会系统崩溃,这就是缓存雪崩。

解决方案 1) 将缓存的失效时间随机打散 在原有的失效时间基础上增加一个随机值(比如1到10分钟),这样就避免了重复。 2)设置缓存不过期 通过后台服务来更新缓存数据,避免缓存失效。

缓存击穿

如果缓存中的某个热点数据过期了,此时有大量请求访问此热点数据,那么就会直接去访问数据库,导致系统崩溃。 缓存击穿和雪崩类似,雪崩是多个数据失效,击穿是一个数据失效。

解决方案: 1)互斥锁方案 (Redis 中使用 setNX 方法设置一个状态位,表示这是一种锁定状态) 同一时间只能有一个业务线程请求缓存。这样就不会很多请求并发导致崩溃了。 2)不给热点数据设置过期时间 后台异步更新缓存,或者在过期之前提前通知后台线程更新缓存。

缓存穿透

用户访问的数据,不在缓存中 也不在数据库中。 当有大量这样的请求时,先去访问缓存,发现没有后就去访问数据库,数据库也没法处理。

一般是业务误操作删掉了数据,或者黑客故意访问不存在的数据。

解决方案: 1)非法请求限制 在API层面,判断请求参数是否合理,是否有非法值和字段,直接返回错误。 2)设置空值或者默认值 针对查询的数据在缓存中设置一个空值或者默认值,这样就能在缓存中查到,不必访问数据库。 3)使用布隆过滤器 快速判断数据是否存在,避免通过数据库来判断是否存在 写入数据库数据的时候,使用布隆过滤器做个标记,请求来的时候,如果判断缓存失效,可以查询过滤器数据是否存在。这样大量的请求只会访问缓存和布隆过滤器,保护了数据库。

27.什么是布隆过滤器?布隆过滤器如何快速判断?+2

布隆过滤器,它是一个连续的数据结构,每个存储位存储都是一个bit,即0或者1, 来标识数据是否存在。

存储数据的时时候,使用K个不同的哈希函数将这个变量映射为bit列表的的K个点,把它们置为1。

布隆过滤器

我们判断缓存key是否存在,同样,K个哈希函数,映射到bit列表上的K个点,判断是不是1:

  • 如果全不是1,那么key不存在;
  • 如果都是1,也只是表示key可能存在。

布隆过滤器也有一些缺点:

  1. 它在判断元素是否在集合中时是有一定错误几率,因为哈希算法有一定的碰撞的概率。
  2. 不支持删除元素。

28.如何保证缓存和数据库数据的⼀致性?+3

怎么保证redis和mysql和数据库一致?

你如何保障本地缓存和redis实现数据一致性

29.如何保证本地缓存和分布式缓存的一致?

30.怎么处理热key?

31.缓存预热怎么做呢?

32.热点key重建?问题?解决?

33.无底洞问题吗?如何解决?

Redis运维

34.Redis报内存不足怎么处理?

35.Redis的过期数据回收策略有哪些?

36.Redis有哪些内存溢出控制/内存淘汰策略?

37.Redis阻塞?怎么解决?

38.大key问题了解吗?

39.Redis常见性能问题和解决方案?

Redis应用

40.使用Redis 如何实现异步队列?

41.Redis 如何实现延时队列?

42.Redis 支持事务吗?

43.Redis和Lua脚本的使用了解吗?

44.Redis的管道了解吗?

45.Redis实现分布式锁了解吗? +3

底层结构

46.说说Redis底层数据结构?

47.Redis 的 SDS 和 C 中字符串相比有什么优势?

48.字典是如何实现的?Rehash 了解吗?

49.跳跃表是如何实现的?原理?

50.压缩列表了解吗?

51.快速列表 quicklist 了解吗?

其他问题 52.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?

redis数据结构

redis线程模型

redis持久化

集群

Redis 过期删除与内存淘汰

Redis 缓存设计

_什么情况会使用Redis __ 分布式唯一ID **** 分布式锁 _ 缓存 ___使用Redis遇到的问题

25.redis中如何设置缓存过期时间

  1. 分布式锁因为删锁而产生的问题
  2. redis lua脚本写一个???原理,怎么实现的?分布式锁(怎么实现的)?常用命令?数据结构?过期删除策略?内存策略?如果要你实现一个lru,你去怎么实现?redis 常用命令?
  3. Redis两种持久化的比较

Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化。Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

RDB是定期将数据写入磁盘,当redis出现故障时,有一部分内存数据肯定会丢失。而AOF是以日志的方式追加,数据丢失会少很多。对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大,数据恢复慢一些。

  1. 不要仅仅使用 RDB,因为那样会导致你丢失很多数据
  1. 也不要仅仅使用 AOF,因为那样有两个问题,第一,你通过 AOF 做冷备,没有 RDB 做冷备,来的恢复速度更快; 第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug。
  2. redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。

最开始的版本对命令的解析处理、网络io是单线程,新版本将网络io改为多线程处理,提高了性能,介绍了单线程下的高QPS原因,不使用多线程的原因、epoll在redis中的应用;

,虚拟内存和物理内存

MySQL和Redis都存数据

Redis为什么能实现分布式锁

为什么会用redis?

什么样的数据需要存到redis里面?

如果按照你的方案,会不会出现数据不一致问题? 该怎么解决呢?

Redis分布式锁的底层原理是什么?

Redis集群方案应该怎么做?都有哪些方案? 2、如何实现集群中的session共享存储? 3、memcached与redis的区别? 4、有使用过哪些阿里的开源中间件?相关的中间件有做个性能比较吗? 5、服务器雪崩的场景,一般是由什么引起的?如何来设计应对 6、谈谈springboot,springcloud、dubbo的设计原理和应用场景 7、Docker与JVM的区别? 8、高并发的解决方案有哪些,重点谈谈方案的优先级步骤?

项目中哪些业务场景使用到了redis?项目中提了基于session的共享问题?你是怎么解决的?

4)

5)Redis分布式锁怎么实现的?

24.redis大key的弊端?

redis介绍一下