Redis常见面试题

1 说一下五种redis数据结构和之间的实现方式以及使用场景

string 简单字符串,通过int类型和SDS实现

list 顺序队列,元素可以重复

set 无序集合,元素不能重复

zset 有序集合,元素不能重复,按照一定顺序排序

hash key-value集合,适合存储对象

2. redis的可持久化机制

持久化机制是通过Redis的AOF日志和RDB快照实现的,AOF日志可以用于数据恢复,每次写操作后,都会在AOF新增一条记录,AOF会在合适的时机刷到磁盘中,AOF刷盘时机分三种,每次操作都写到硬盘、每秒写到硬盘一次、交给操作系统控制写回时机。当AOF日志越来越大时,数据恢复速度就变慢,需要重写AOF日志,会读取每一个键值对最新的指令。从而减小了AOF日志体积。重写的过程是由后台进程完成的,这样主进程还可以正常处理

RDB快照,记录了某一时刻Redis的全量数据。恢复数据会更快,AOF还得一条一条去执行命令。

生成快照时机不好把握,频率太高,容易造成不必要开销,频率太低,可能导致更多数据丢失。

Redis4.0采用AOF和RDB混合持久化,AOF文件中前半部分是RDB的全量数据,后半部分是AOF的增量数据。这样前半部分RDB快照恢复的很快,后面是重写AOF期间,主线程的命令,可以使数据更少丢失。

3. redis实现分布式锁的设计

用SET NX命令,可以实现加锁操作。当下一个请求来时,也用SETNX 命令,但是发现Key已经存在,加锁失败。 加锁成功的客户端,要及时释放锁。DEL命令删除key就相当于释放了锁。如果DEL命令因为一些原因没有释放锁,会导致死锁。这时候就要设置过期时间,确保一定能释放锁。如果锁没有指定是谁上的,还会出现不小心释放了别人的锁。可以在加锁时,设置一个只有自己知道的唯一标识。在释放锁时,判断下是不是自己上的锁。

4. redis 缓存雪崩、击穿、穿透?

redis缓存击穿,某一个热点数据过期。在redis没查询到数据,大量请求都到mysql。导致Mysql突然处理请求变多。导致宕机。

解决:不给热点key设置过期时间,或者检测如果热点数据即将过期,再重新设置过期时间

redis缓存穿透,在redis和mysql中都没有查询到记录。redis无法构建缓存记录。

解决:如果查询不存在的值,可以在redis里做一个缓存,专门缓存不存在的数据,查到就立马返回。不会请求到MySQL。利用布隆过滤器,在写入数据时,现在布隆过滤器中做标记,等请求来时,判断是否标记过。

redis缓存雪崩,大量热点key同时间过期。导致都去访问mysql。导致MySQL处理压力变大。导致宕机。或者redis宕机,请求没访问redis直接到数据库。

解决:给热点key设置不同的过期时间,防止同一时间多个热点key过期。构建Redis集群,保证Redis高可用。

5. 如果已经发生缓存雪崩,如果服务器也被搞崩溃了,我们怎么恢复网页。

启动服务熔断,重启服务器之后,先进行限流,等redis重新建立缓存之后,在解除限流。限流方式为令牌桶

6. redis本身是单线程嘛?

最开始redis3版本时用的是单线程,后来为了应对AOF和RDB时需要fork的子协程,还有大key删除会卡顿。支持了多协程。但是在读写操作上还是用单线程在处理。单线程保证了事务的原子性,不需要加锁操作保证互斥了。

7. redis分布式部署模式

主从模式:单机部署的redis如果出现宕机,影响很严重。我们可以利用多台redis建立一个主从模式,一般是一主二从一主备。主节点主要用来做写操作,然后将RDB快照传给从服务器,从服务器拿到RDB文件进行同步,读操作都在从节点。分摊了主服务器压力。

第一步,通过replicaof命令,建立主从。主服务器把全量数据同步给从服务器

第二步,从服务器清空所有数据然后载入RDB文件,同步期间发生的写操作,会存放到replication buffer里

第三步,主服务器发送新写的操作给从服务器。后续都通过命令传播传递写命令。

如果因为网络问题,主从连接断开,重连上时,会发生增量复制,只会把网络断开时候的写操作命令同步给从服务器。 从服务器先发送自己读的位置,主服务器找到后,会将中间的写操作命令发送。如果没找到,会把全量数据发送给从服务器。

8.redis哨兵模式

哨兵模式实现主节点挂掉后,(监控,选主,通知)操作。

哨兵每隔一秒ping所有主从节点,如果主节点没有在规定时间内响应哨兵的ping命令,哨兵就会标记为主观下线,然后会通知所有哨兵,哨兵们根据自己到主节点的网络状况来投票。如果有半数以上的哨兵投赞成票。此时会被哨兵标记为客观下线。

然后就会开始选主操作,在所有从节点里,挑选一个从节点,作为主节点。规则是:去掉网络状况不好的节点和离线节点。剩下的从节点根据优先级、复制进度、版本号大小来选出一个新节点。

哨兵通知其他节点修改复制目标,将新主节点的IP和信息,通过消息发布订阅机制通知给客户端,继续监视下线主节点,当再次上线时,将其作为新主节点的从节点。

9. redis为什么单线程会快?

redis数据都存储在内存中,内存的速度比磁盘高很多。

redis单线程避免了上下文切换,和多线程竞争。

redis数据结构简单,都是专门设计的,这些数据结构查询查找时间复杂度大部分都是 o1,性能高

redis采用多路复用 ,监听多个socket连接客户端,这样可以使用一个线程连接来处理多个请求。

10. string底层有了解吗?

string不光可以放字符串类型、整型、浮点型、二进制数据等都可以放入。底层是SDS动态字符串,会根据数据大小选择合适的类型,当数据量小于

11. redis数据怎么设置过期时间,原理是什么,让你来设计过期机制你会怎么设计?

redis可以设置字段的过期时间 expire key n 设置几秒后过期,pexpire key n 设置几毫秒后过期。还可以在添加键值对时设置时间,set key px n。

原理是,当对字段加过期时间后,会将这个字段加入到一个过期字典中。里面存放的都是设置了过期时间的键。每次查询一个键值对时,会先判断是否在过期字典中,如果在再判断和系统时间大小,如果小于说明过期了。

Redis的过期机制是,采取惰性删除和定期删除的方式。惰性删除是当访问到这个key过期了,就会从过期字典中移除,定期删除,每隔10s从过期字典中抽20个key,判断是否过期,如果过期数大于总数的25%,就继续抽20个,直到低于25%。

12.redis内存淘汰策略

redis内存超过最大内存时,会触发redis内存淘汰。

大体分为两种,一种不进行内存淘汰,一种进行内存淘汰,进行内存淘汰的里面又可以分为只在设置了过期时间的数据中淘汰,在全局数据进行淘汰。在过期时间的数据中随机淘汰,淘汰最早的,LRU,LFU。在全局数据中,随机淘汰,全局LRU,全局LFU淘汰。

LRU最近最少使用。LFU最近最不常用。Redis中实现LRU没有采用链表的方式,链表查找速度慢,而是在结构体中添加了最后一次访问时间,删除时按照最后一次访问时间来删除。

Redis中实现LFU是在结构体中加了访问频次字段,通过频次和最后一次访问时间的值来判断淘汰哪个数据。

13. redis的hash类型?怎么实现扩容

hash底层是由哈希表实现的,复杂度o1。在定值查找中非常迅速。 hash结构体定义了两个哈希表,交替使用,当触发rehash操作时,给哈希表2分配空间,一般时hash1的二倍,然后将1迁到2中,1释放,2改成1。并新建一个空白hash表,方便下次使用。

渐进式扩容,每次操作完数据后,还会将hash1中当前的key-value迁移到hash2中。随着请求次数越来越多,最终实现迁移操作。

rehash触发条件:

哈希冲突比较严重,节点数/哈希表大小 >=5强制rehash

>=1并且不进行AOF RDB快照时。

14. bitmap的应用场景有哪些

bitmap适用于二值情况。比如签到统计,男女这种只有两种结果的情况。 占用的内存更小

15.如果保证数据库和缓存一致性

无非四种方式:

先更新数据库再更新缓存:如果第一步成功,第二步失败,会导致查询时还是旧纪录。

先更新缓存再更新数据库:如果第一步成功,第二步失败,导致查询时是正确的,但是当缓存过期后,查询出来的又是之前的数据。

解决并发问题。当两个客户端都要操作记录,假设都成功。由于并发操作,可能出现数据库值是A的,但是redis值是B的情况。因此,将更新缓存变为删除缓存。

先删除缓存再更新数据库:读写并发问题下,两步都成功。A删缓存成功了,B读缓存没读到,去Mysql读了旧数据,A更新了Mysql数据,B将旧数据设成了缓存值。造成不一致

先更新数据库再删除缓存:读写并发问题下,两步都成功。A先读取数据库,B更新了数据库,B删除了缓存,A设置了缓存。导致又不一致。

但是这种情况基本不会出现,A正常先读取redis,但是恰好失效时才会读取Mysql。B更新数据库并且删除缓存 时间大于A读取数据库并设置缓存时间短是不太可能的。

但是如果第一步成功,第二步失败都会造成不一致情况:

第二步失败就要重试,可以放到消息队列中。或者拿到mysql的binlog操作日志,然后根据操作日志来删除对应的缓存。订阅binlog操作日志。

延迟双删是为了解决,在读写分离情况下,先删除缓存,再更新数据库可能导致缓存的值是旧值情况。所以要在更新数据库后,再次删除缓存。

16.大key是什么,有什么影响,如何排查解决?

大key指的当前这个键对应的值很大,当string值大于10k。或Hash、set、zset、list类型个数超过5000个。

  1. 大key首先影响redis的写操作时间,由于Redis读写是单线程的,大的key会延长写操作时间,导致阻塞。
  2. 其次在Redis读取数据时,大key同时也会对网络传输造成一定影响。
  3. 删除数据,使用del删除大key,会阻塞工作线程,del是在主线程进行处理。这样就没办法处理后续命令
  4. 在写入一个大key时,会记录写操作到AOF日志中,如果此时AOF刷盘参数是always。就会立马开始写入磁盘,由于always是同步操作,因为大key存在导致数据同步到磁盘过程非常耗时。
  5. 在AOF日志写满时,会触发重写操作,主线程会fork一份数据副本,fork操作是在主线程中的,如果大key,势必会阻塞主线程。影响后续命令处理

排查:

使用命令redis-cli --bigkeys 查找大key,是按类型查找的,并且只返回每个类型最大的。

使用命令scan扫描数据库,然后用TYPE命令获取返回的每一个key的类型。

使用第三方工具RdbTools查找大key 用来解析RDB文件,找到其中的大key

解决:

慢慢删除,一次处理一点点。

使用unlink代替del命令。unlink是异步操作。不会阻塞主线程

相关推荐
vip1024p6 分钟前
第二篇:MySQL安装与配置(基于小皮面板(phpstudy))
数据库·mysql·adb
limts6 分钟前
Oracle中补全时间的处理
数据库·oracle
woshilys10 分钟前
sql server 从库创建的用户名登录后访问提示数据库无权限
数据库·sqlserver
CodeJourney.2 小时前
EndNote与Word关联:科研写作的高效助力
数据库·人工智能·算法·架构
trigger3332 小时前
MongoDB 简介
数据库·mongodb
许心月2 小时前
MongoDB#常用语句
数据库·mongodb
Jason95103 小时前
使用大语言模型(Deepseek)构建一个基于 SQL 数据的问答系统
数据库·sql·问答系统·大语言模型·deepseek
苍老流年3 小时前
Redis底层数据结构
数据结构·数据库·redis
三天不学习3 小时前
Redis面试宝典【刷题系列】
数据库·redis·面试
HaoHao_0103 小时前
如何将MySQL数据库迁移至阿里云
服务器·数据库·阿里云·云计算·云服务器·迁移