redis面试题
-
- 1、redis的数据类型及应用场景?
- 2、incr的命令是原子性的么?
- 3、redis的操作是原子性的么?
- 4、hash类型存用户信息是怎么存的?
- 5、redis的value的长度限制?
- 6、 redis如何实现延时消息的?
- 7、单线程如何提高多核cpu的利用率?
- 8、redis为什么这么快?
- 9、redis和memecache的区别?
- 10、为什么用redis而不用map和guava做缓存?
- 11、什么是缓存雪崩、穿透、击穿?以及他们的解决办法?
- 12、布隆过滤器是什么?
- 13、缓存预热、降级、hot key、big key分别是什么意思?
- 14、redis的分布式锁是怎么实现的?
- 15、 redis的set和setnx怎么用的?
- 16、 redis是怎么设置过期时间和永久有效的?
- 17、Redis的常用命令包括但不限于:
- 18、redis锁和zk的锁的区别?
- 19、 redis锁的缺陷是什么?
- 20、 redis的秒杀业务结合实际怎么实现的?库存超卖的问题?
- 21、redis的过期删除策略(淘汰策略)?
- 22、redis的内存淘汰机制(内存优化)?
- 23、redis的持久化方式有哪几种及概念?
- 24、 如何选用持久化方式?
- 25、 redis的非阻塞IO问题?
- 26、redis支持的java客户端有哪些?
- 27、 jedis和redisson的区别?
- 28、 redis和redisson有什么关系?
- 29、简单介绍下redisson的原理?
- 30、 redisson实现分布式锁的原理?
- 31、redisson加锁的缺点?
- 32、怎么解决缓存和数据库数据的一致性?为什么不一致?
- 33、什么是RedLock?
- 34、redis常见的性能问题该如何解决?
- 35、redis支持事务么?
- 36、redis事务的三个阶段?
- 37、 redis事务的相关命令?
- 38、redis的事务支持隔离性么?
- 39、 redis的事务保证原子性么?支持回滚么?
- 40、redis的延时双删是怎么解决的?
- 41、redis如何保证缓存和数据库双写时数据的一致性?
- 42、如何解决redis的并发竞争key的问题?
- 43、分布式redis是前期做还是后期规模上来了再做?
- 44、1亿个key,10w个key固定前缀,怎么找出来?
- 45、Redis集群模式的工作原理是什么?
- 46、集群模式下,redis的key是如何寻址的(分布式寻址有哪些算法)
- 47、生产环境下redis是怎么部署的?
- 48、 redis哈希槽的概念?
- 49、redis集群会有写操作丢失么?
- 50、 redis集群之间是如何复制的?
- 51、 redis最大的节点个数是多少?
- 52、redis的端口号是多少?
- 53、主从复制是怎么实现的?
- 54、哨兵的选举流程是什么?
- 55、 raft算法是怎么实现的?(也是哨兵模式选举领头的实现方式)
- 55、 redis怎么解决库存超卖问题?
- 2、redis为什么要做分区?
- 2、 redis分区有什么缺点?
- 3、redis如何解决key冲突?
- 3、怎么提高缓存的命中率?
- 3、什么情况下会导致redis阻塞?
- 3、redis怎么实现高可用的(集群方案以及相关的问题)?
- 4、集群架构模式有哪几种?(单机单节点、主从、哨兵)
- 4、哨兵模式是怎么实现的,简单介绍一下(实现高可用的)?
- 4、keepalived的怎么实现的?
- 4、 redis集群方案什么情况下会导致集群不可用?
1、redis的数据类型及应用场景?
redis的数据类型都是针对value来说的
- String:适合最简单的k-v存储,做简单的键值对缓存、共享session、限速、Incr的自增命令;
- List: 有序列表,存储一些列表型的数据结构,类似粉丝列表、文章评论列表之类的数据,简单的消息队列;
- Hash:包含键值对的无序散列表,redis的hash类型并没有在value单独存key的概念,每个字段名和字段值都是直接存在哈希结构中,他是结构化的数据,比如一个对象,存放用户信息,比如实现购物车;
例如:Hset (user:John)key (username john phone 12345)value
HGETALL>检索 HDEL>删除 - Set:无序集合(不可重复),交集并集差集的操作,比如交集就是把两个粉丝列表整合一个交集;
- Sorted set:跳表实现,有序集合,有个权重参数score,按照score排序,做排行榜;
应用场景:
计数器:对String数据类型进行自增自减操作,incr自增命令来实现的;
缓存:将热点数据存放到内存中,设置内存的最大使用量及淘汰策略保证缓存的命中率;
消息队列:发布订阅功能,list是一个双向链表,可以通过lpush和rpop写入和读取消息,不过最好使用Kafka,RabbitMq等消息中间件;
分布式锁:使用setnx命令实现分布式锁;
2、incr的命令是原子性的么?
是原子性的,多个线程执行incr命令时,redis会确保操作的原子性,INCR命令主要用于原子递增一个Key对应Value的值。
3、redis的操作是原子性的么?
Redis的操作是原子性的。原子性是数据库事务中的一个特性,指的是事务中的所有操作要么全部完成,要么全部不完成,不会结束在中间某个环节。对于Redis而言,命令的原子性指的是一个操作不可分割,操作要么执行,要么不执行。Redis的操作之所以是原子性的,是因为Redis是单线程的。在Redis中,执行get、set等API都是一个一个的任务,这些任务都会由Redis的线程去负责执行,任务要么执行成功,要么失败。因此,Redis的单个命令操作是原子性的。
4、hash类型存用户信息是怎么存的?
比如一个对象,存放用户信息,比如实现购物车;
Hset (user:John)key (username john phone 12345)value
5、redis的value的长度限制?
字符串类型的值能储存512m;
6、 redis如何实现延时消息的?
用sorted set (有序集合)实现延时消息,首先创建一个有序集合作为延时消息的存储容器,每条延时消息添加到这个有序集合里,并且设置其分数值为当前时间+延时时间。
7、单线程如何提高多核cpu的利用率?
- 使用多个redis实例,每个实例在单独的核心上运行,每个核心可以处理不同的任务,从而提高整个系统的处理能力;
- 使用事件驱动模型,通过不断监听来处理I/O操作,提高运行效率;
8、redis为什么这么快?
为什么用redis做缓存?
- 完全基于内存,绝大部分请求是纯粹的内存操作,非常迅速数据存在内存中,类似于Hashmap,Hashmap的优势就是查找和操作的时间复杂度都是O(1);
- 数据结构简单,对数据的操作也简单,Redis中会有专门的数据结构来对此进行优化;
- 采用单线程,避免为了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗cpu,不用去考虑各种锁的问题,不存在加锁或者释放锁的操作,没有因为可能出现死锁而导致的性能消耗;(为什么会使单线程的?)
- 使用多路I/O复用,非阻塞I/O;
- 使用底层的模型不同,他们底层实现方式以及客户端之间通信的协议不一样,Redis直接自己构建了VM机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
9、redis和memecache的区别?
Redis和Memcache作为两种常见的内存数据存储系统,各有其特点和适用场景。以下是它们之间的主要区别:
存储方式和数据持久性:
- Memcache将数据全部存储在内存中,一旦断电,数据将会丢失,且其数据大小不能超过内存大小。
- Redis则部分数据存储在硬盘上,这保证了数据的持久性,即使在服务器重启或故障后,数据也不会丢失。
数据支持类型:
- Memcache主要支持简单的key-value存储,不支持枚举、持久化和复制等功能。
- Redis支持的数据类型则更为丰富,包括list、set、sorted set、hash等众多数据结构,并提供了持久化和复制等功能。
使用底层模型:
- 新版本的Redis直接构建了VM机制,这有助于减少系统调用和移动数据的开销,从而提高性能。
- Memcache则没有这样的底层模型优化。
运行环境:
- Redis目前官方只支持在Linux上运行,这有助于更好地优化其在该系统的性能。
- Memcache则可以在多种操作系统上运行。
10、为什么用redis而不用map和guava做缓存?
Redis、Map和Guava都可以作为缓存解决方案,但它们各自具有不同的特点和适用场景。以下是为什么在某些情况下会选择Redis而不是Map和Guava作为缓存的主要原因:
分布式缓存 vs 本地缓存:
- Redis是一个分布式缓存,可以部署在网络中的多台服务器上,并被多个应用共享访问。这使得Redis在需要跨多个服务器或应用共享数据的场景中非常有用。
- Map和Guava则是本地缓存,通常存储在应用的内存中,只能被运行在同一台机器上的应用访问。因此,它们更适合单机环境或单进程内的缓存需求。
数据持久化与可靠性:
- Redis支持数据持久化,可以将内存中的数据定期保存到磁盘上,确保数据在服务器重启后不会丢失。同时,Redis还支持主从复制和哨兵等机制,提供高可用性和容错能力。
- Map和Guava缓存则不具备这样的数据持久化和可靠性特性,一旦应用重启或进程终止,缓存数据就会丢失。
扩展性与容量:
- Redis支持集群模式,可以方便地扩展缓存容量和负载均衡,满足大规模和高并发的需求。
- Map和Guava缓存的容量受限于单个进程的内存大小,因此在处理大规模数据时可能会遇到性能瓶颈。
数据类型与操作丰富性:
- Redis支持多种数据类型,如字符串、哈希、列表、集合等,并提供了丰富的操作命令,可以满足各种复杂的缓存需求。
- Map通常只支持键值对存储,而Guava虽然提供了一些缓存策略和功能,但相比于Redis来说操作和功能相对有限。
社区支持与生态:
- Redis作为一个开源项目,拥有庞大的用户群体和活跃的社区支持,这使得Redis在问题解决、功能更新和性能优化等方面具有优势。
- 虽然Map和Guava也有广泛的使用和社区支持,但它们在缓存领域的专业性和活跃度可能不及Redis。
11、什么是缓存雪崩、穿透、击穿?以及他们的解决办法?
雪崩:是指缓存在同一时间大面积失效,所以后面的请求都会落到数据库上,造成数据库崩了
解决办法:
- 给过期时间设置一个随机值;
穿透:是指缓存和数据库中都没有的数据,导致所有请求都落到数据库上了,造成短时间内数据库承受大量的请求崩掉;
解决办法:
- 接口层增加校验,比如用户鉴权,id做基础校验,id<=0就行拦截;
- 布隆过滤器;
击穿:是指缓存中没有,但是数据库中有的数据,用于并发用户特别多,导致请求直接到达数据库,引起数据可压力瞬间增大,导致数据库崩了。
解决办法:
- 设置热点数据永不过期;
- 加互斥锁;
12、布隆过滤器是什么?
它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
13、缓存预热、降级、hot key、big key分别是什么意思?
缓存预热、降级、hot key、big key是缓存技术中常见的几个概念,以下是对它们的解释:
缓存预热:
- 定义:在应用程序启动或缓存失效之后,主动将热点数据加载到缓存中的策略。
- 目的:通过预先加载热点数据,提高缓存的命中率,减少对后端数据源(如数据库)的访问,降低系统的负载。同时,它也有助于保持应用程序的性能稳定,防止请求对后端数据源产生突然的压力,从而优化用户体验。
缓存降级:
- 定义:最终目的是保证核心服务可用,当缓存失效或缓存服务器挂掉时,不去访问数据库,而是直接返回默认数据或访问服务的内存数据。
- 目的:确保在缓存失效或服务器故障的情况下,系统仍然能够提供一定的服务,尽管可能不是最佳的服务。但需要注意的是,降级通常是有损的操作,应尽量减少降级对业务的影响。
Hot key:
- 定义:热点key,通常指那些被频繁访问的缓存数据。
- 问题:预估热点key往往有偏差,总会有意想不到的地方成为热点,或者突发的状况导致某些key成为热点。
- 解决方案:客户端收集、代理层收集、redis监控命令、网络抓包分析等方法都可以用于识别和处理hot key。
Big key:
- 定义:大key是指那些大小超过一定阈值的缓存key。例如,单个String类型的Key大小达到20KB并且OPS高,或者集合类型的Key总大小达到1MB等。
- 影响:大key可能导致客户端超时阻塞、阻塞工作线程,以及内存分布不均等问题,进而影响到整个缓存系统的性能和稳定性。
- 解决手段:针对历史key未使用的情况,可以删除不再使用的缓存数据以释放资源。此外,合理的缓存设计和维护策略也是防止大key问题的重要手段。
14、redis的分布式锁是怎么实现的?
Redis的分布式锁实现主要依赖于其提供的SETNX(set if not exist)命令,该命令会在指定的key不存在时,将key的值设为给定的value。如果key已经存在,则SETNX不做任何操作。基于这个特性,Redis的分布式锁的实现大致如下:
- 获取锁:客户端尝试使用SETNX命令获取锁。如果SETNX命令返回1,表示客户端成功获取到锁,可以进行后续操作。如果返回0,则表示锁已经被其他客户端持有,此时客户端可以选择等待或者进行其他操作。
- 设置锁的过期时间:在获取到锁之后,客户端需要为锁设置一个合理的过期时间,以防止因客户端崩溃或网络问题导致的锁无法释放,从而造成死锁。这可以通过Redis的EXPIRE命令实现。
- 释放锁:当客户端完成操作后,需要显式地释放锁。这通常是通过删除对应的key来实现的,即使用DEL命令。
然而,这种简单的实现方式存在一些问题,比如锁的过期时间设置不当可能导致锁提前释放,或者在释放锁时可能因网络问题导致释放失败。为了解决这些问题,Redis的分布式锁实现通常会引入一些额外的机制,如:
- 使用Lua脚本确保原子性:为了避免在获取锁和设置过期时间之间出现其他客户端获取锁的情况,可以使用Redis的Lu