Redis面试题汇总

说一下你在项目中的redis的应用场景?

  1. 5大value类型:
  2. String数据类型
  3. List 数据类型
  4. Hash数据类型(散列类型)
  5. set数据类型(无序集合)
  6. Sorted Set数据类型 (zset、有序集合)。
  7. 基本上就是缓存~!
  8. 为的是服务无状态,延申思考,看你的项目有哪些数据结构或对象,在单机里需要单机锁,在多机需要分布式锁,抽出来放入redis中;
  9. 无锁化

redis是单线程还是多线程?

  1. 无论什么版本,工作线程就是一个

  2. 6.x高版本出现了IO多线程

  3. 使用上来说,没有变化

image-20220308100321375

  1. [去学一下系统IO课],你要真正的理解面向IO模型编程的时候,有内核的事,从内核把数据搬运到程序里这是第一步,然后,搬运回来的数据做的计算式第二步,netty

  2. 单线程,满足redis的串行原子,只不过IO多线程后,把输入/输出放到更多的线程里去并行,好处如下:

  3. 执行时间缩短,更快;

  4. 更好的压榨系统及硬件的资源(网卡能够高效的使用);
    客户端被读取的顺序不能被保障
    哪个顺序时可以被保障的:在一个连接里,socket里

redis存在线程安全的问题吗?为什么?

  1. 重复2中的单线程串行
  2. redis可以保障内部串行
  3. 外界使用的时候要保障,业务上要自行保障顺序~!

redis是二进制安全的么

是,redis是使用的二进制字节流传输而不是字符流。

遇到过缓存穿透吗?详细描述一下。

https://www.cnblogs.com/xichji/p/11286443.html

缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

有很多种方法可以有效地解决缓存穿透问题最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

遇到过缓存击穿吗?详细描述一下。

https://www.cnblogs.com/xichji/p/11286443.html

缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

image-20220321134510366

使用互斥锁(mutex key)

业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,并加到期时间,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

如何避免缓存雪崩?

以上问题,核心就是避免DB无效/重复请求,结合图去理解
涉及一些架构思想上的提升

缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

Redis是怎么删除过期key的?缓存如何回收的?

三种过期策略

定时删除

  1. 含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。
  2. 优点:保证内存被尽快释放。
  3. 缺点:
  4. 若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key。
  5. 定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重。
  6. 所以没人用。

惰性删除

  1. 含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
  2. 优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)。
  3. 缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)。

定期删除

  1. 含义:每隔一段时间执行一次删除过期key操作。
  2. 优点:
  3. 通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理”定时删除”的缺点。
  4. 定期删除过期key–处理”惰性删除”的缺点。
  5. 缺点:
  6. 在内存友好方面,不如”定时删除”。
  7. 在CPU时间友好方面,不如”惰性删除”。
  8. 难点:合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)。

redis采用的过期策略

惰性删除+定期删除

  1. 惰性删除流程:
  2. 在进行get或setnx等操作时,先检查key是否过期,
  3. 若过期,删除key,然后执行相应操作;
  4. 若没过期,直接执行相应操作。
  5. 定期删除流程(简单而言,对指定个数个库的每一个库随机删除小于等于指定个数个过期key)
  6. 遍历每个数据库(就是redis.conf中配置的”database”数量,默认为16)

    1. 检查当前库中的指定个数个key(默认是每个库检查20个key,注意相当于该循环执行20次,循环体时下边的描述)
      1. 如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历
      2. 随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key
      3. 判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。
  7. 后台在轮询,分段分批的删除哪些过期的key

  8. 请求的时候判断时候已经过期了
    尽量的把内存无用空间回收回来~!
  9. 设置了过期时间,获取缓存内数据不会刷新过期时间。

缓存是如何淘汰的,内存满了怎么处理。

  1. 查看调整内存管理算法
  2. LFU:最不经常使用淘汰算法(Least Frequently Used)。LFU是淘汰一段时间内,使用次数最少的页面。
  3. LRU:最近最少使用淘汰算法(Least Recently Used)。LRU是淘汰最长时间没有被使用的页面。
  4. ARC:自适应缓存替换算法,在IBM Almaden研究中心开发,这个缓存算法同时跟踪记录LFU和LRU,以及驱逐缓存条目,来获得可用缓存的最佳使用。
  5. FIFO:先进先出算法。FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
  6. random:随机删除。

  7. 调整key过期时间。

  8. 设置maxmemory redis可使用内存一般是1G-10G。太大不利于持久化数据迁移。
  9. 增大机器内存。
  10. 淘汰机制里有不允许淘汰
  11. LRU/LFU/random/TTL
  12. 设置过过期的key的集合中

如何进行缓存预热?

  1. 提前把数据塞入redis,()(你知道那些是热数据吗?肯定不知道,会造成上线很多数据没有缓存命中)
  2. 开发逻辑上也要规避差集(你没缓存的),会造成击穿,穿透,雪崩,实施456中的锁方案
  3. 一劳永逸,未来也不怕了

数据库与缓存不一致如何解决?

  1. 恶心点的,我们可以使用分布式事务来解决,(意义不大),顶多读多,写稀有情况下
  2. redis是缓存,更倾向于稍微的有时差
  3. 还是减少DB的操作
  4. 真的要落地,咱就canal binlog吧
  5. https://www.cnblogs.com/msxj/articles/11476878.html

简述一下主从不一致的问题?

  1. redis的确默认是弱一致性,异步的同步
  2. 锁不能用主从(单实例/分片集群/redlock)==>redisson
  3. 在配置中提供了必须有多少个Client连接能同步,你可以配置同步因子,趋向于强制一性
  4. wait 2 0 小心
  5. 34点就有点违背redis的初衷了

描述一下redis持久化原理?

由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

二者的区别

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

img

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

img

二者优缺点

RDB优点:

  1. 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  2. 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
  3. 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
  4. 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB缺点:

  1. 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
  2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

AOF优点:

  1. 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
  2. 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
  3. 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
  4. AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。

AOF缺点:

  1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
  2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

常用配置

RDB持久化配置

Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:

save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。

save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。

save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF持久化配置

在Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always #每次有数据修改发生时都会写入AOF文件。

appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。

appendfsync no #从不同步。高效但是数据不会被持久化。

Redis有哪些持久化方式?

  1. RDB快照/副本,AOF日志;主从同步也算持久化;
  2. 高版本:开启AOF,AOF是可以通过执行日志得到全部内存数据的方式,但是追求性能:
  3. 体积变大,重复无效指令 重写,后台用线程把内存的kv生成指令写个新的aof
  4. 4.x 新增更有性能模式:AOF中包含RDB全量,增加记录新的写操作。

Redis也打不住了,万级流量会打到DB上,该怎么处理?

  1. 见缓存穿透,击穿,雪崩解决方法。

redis中的事务三条指令式什么,第三条指令到达后执行失败了,怎么处理

image-20220309143413191

redis实现分布式锁的指令

  1. 为什么使用setnx?

1,好东西,原子(不存在的情况下完成创建)
2,如果要做分布式锁,就要用set k v nx ex (不存在,过期时间,避免死锁)

  1. 分布式锁实现,理论:

nx

仅当key不存在时,set才会生效。

xx

仅当key存在时,set才会生效。

redis集群

单机,单节点,单实例有哪些的问题?

  1. 单点故障。
  2. 容量有限。
  3. 压力。

微服务拆分的四个原则

  1. AKF拆分原则
  2. 前后端分离
  3. 无状态服务
  4. Restful通信风格

X:全量镜像 (主备:读写分离,主写备读 ),只能解决单点故障的问题,,但无法解决其他两种问题。

img

Y:单台有10G数据,但redis只有4G。按业务逻辑,功能拆分数据到多台redis上。
例:订单,用户信息,等。

img

按义业务拆分后,数据又变大了,怎么办?

Z:基于一个优先级逻辑按编号拆分。

img

如果解决一个问题,必然进入新的问题。

数据一致性:写的时候阻塞,直到所有节点数据全部一致,强一致性,成本极高。
网络,丢包,导致超时,导致不可用,会破坏可用性。

容量问题如何解决:

1. 业务拆分

img

2.hash+取模

弊端:取值的数必须固定

%3 %4

影响分布式下的扩展性

redis集群默认使用的是这种,不过他自动

img

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

3. random

消息队列:一个往redis里扔lpush,一个从redis取rpop,消费的模式。

img

4.一致性哈希算法(更适合作为缓存使用)

img

映射算法:hash,crc16,crc32,fnv,md5

没有取模,使用的是哈希环

0开始到2的32次方,有无数个虚拟的点。

准备一个算法,按照物理机的节点数分片。

新增一个节点,不影响节点以后的数据。

优点:加节点,可以分担其他节点的压力,不会造成全局洗牌。

缺点:新增节点会造成一小部分数据不能命中。

  1. 问题:会出现击穿,压力到了数据库
  2. 方案:没的话,去取离我最近的2个物理节点

数据倾斜
可以通过设备地址拼接10个数字,使两个节点平均分配再20个节点中

版权声明:除特殊说明,博客文章均为Mark原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。VIP内容严禁转载! | 广告招租请留言
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇