Redis面试系列-01

2022年7月17日
大约 13 分钟

Redis面试系列-01

1. 什么是 Redis?

redis是一个高性能的key-value数据库,它是完全开源免费的,而且redis是一个NOSQL类型数据库,是为了解决高并发、高扩展,大数据存储等一系列的问题而产生的数据库解决方案,是一个非关系型的数据库。但是,它也是不能替代关系型数据库,只能作为特定环境下的扩充。

redis是一个以key-value存储的数据库结构型服务器,它支持的数据结构类型包括:字符串(String)、链表(lists)、哈希表(hash)、集合(set)、有序集合(Zset)等。为了保证读取的效率,redis把数据对象都存储在内存当中,它可以支持周期性的把更新的数据写入磁盘文件中。而且它还提供了交集和并集,以及一些不同方式排序的操作。

2. 为什么 Redis 需把数据放到内存中?

若不将数据读到内存中,磁盘I/O速度会严重影响Redis的性能。

Redis具有快速和数据持久化的特征。

Redis为了提高读写时的速度将数据读到内存中,并通过异步的方式将数据写入磁盘。

注:若设置最大使用内存,则数据已有记录数达到内存限值后不能继续插入新值。

为什么内存读取比磁盘读取数据速度快?

1)内存是电器元件,利用高低电平存储数据,而磁盘是机械元件,电气原件速度超快,而磁盘由于在每个磁盘块切换时磁头会消耗很多时间,说白了就是IO时间长,两者性能没发比较。

2)磁盘的数据进行操作时也是读取到内存中交由CPU进行处理操作,因此直接放在内存中的数据,读取速度肯定快很多。

3. Redis 支持那些数据类型?

String字符串

命令: set key value

string类型是二进制安全的,它可以包含任何数据,如图片或序列化对象等。

string类型是Redis最基本的数据类型,一个键最大能存储512MB。

Hash(哈希)

命令: hmset name key1 value1 key2 value2

Redis hash是一个键值(key=>value)对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

List(列表)

Redis列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)

命令: lpush name value

key对应list的头部添加字符串元素

命令: rpush name value

key对应list的尾部添加字符串元素

命令: lrem name index

key对应list中删除count个和value相同的元素

命令: llen name

返回key对应list的长度

Set(集合)

命令: sadd name value

Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

zset(sorted set:有序集合)

命令: zadd name score value

Redis zset和set一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

4. 什么是 Redis 持久化?Redis 有哪几种持久化方式?

Redis持久化是指把内存的数据写到磁盘中去,防止服务因宕机导致内存数据丢失。

Redis提供了两种持久化方式:RDB(默认)和AOF。

RDB是Redis DataBase缩写,功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数。

AOF是Append-only file缩写,每当执行服务器(定时)任务或者函数时flushAppendOnlyFile函数都会被调用,这个函数执行以下两个工作。

AOF写入与保存

WRITE:根据条件,将aof_buf中的缓存写入到AOF文件

SAVE:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中。

5. 什么是缓存穿透?如何避免?

缓存穿透是指一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。

一些恶意的请求会故意查询不存在的key,导致请求量大,造成后端系统压力大,这就是做缓存穿透。

如何避免?

1)对查询结果为空的情况也进行缓存,缓存时间设置短一点或key对应的数据insert后清理缓存。

2)对一定不存在的key进行过滤,可以把所有可能存在的key放到一个大的Bitmap中,查询时通过bitmap过滤。

6. 什么是缓存雪崩?何如避免?

缓存雪崩是指当缓存服务器重启或大量缓存集中在某一个时间段内失效,这样在失效时,会给后端系统带来很大压力,导致系统崩溃。

如何避免?

1)在缓存失效后,使用加锁或队列的方式来控制读数据库写缓存的线程数量。如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2)实现二级缓存方式,A1为原始缓存,A2为拷贝缓存,A1失效时,切换访问A2,A1缓存失效时间设置为短期,A2设置为长期。

3)不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

7. 为什么要用 Redis 而不用 Map、Guava 做缓存?

缓存可以划分为本地缓存和分布式缓存。

以Java为例,使用自带Map或者Guava类实现的是本地缓存,主要特点是轻量以及快速,它们的生命周期会随着JVM的销毁而结束,且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。

使用Redis或Memcached等被称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,具有一致性,但是需要保持Redis或Memcached服务的高可用。

8. Redis 是单线程的吗?为什么这么快?

Redis是单线程的,至于为什么这么快主要是因如下几方面:

1)Redis是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快。

2)Redis使用的是非阻塞IO、IO多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。

3)Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。

4)Redis避免了多线程的锁的消耗。

5)Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。

需要注意的是:

1)Redis 4.0开始引入多线程的概念,比如 Redis通过多线程方式在后台删除对象、以及通过Redis模块实现的阻塞命令等;

2)Redis 6.0的发布提到多线程IO,Theaded IO指的是在网络IO处理方面增加了多线程,如网络数据的读写和协议解析等,需要注意的是,执行命令的核心模块还是单线程的。

9. Redis 过期键都有哪些删除策略?

Redis是key-value数据库,可以设置Redis中缓存key的过期时间。

Redis的过期策略是指当Redis中缓存的key过期,Redis是如何处理。

常见的删除策略有以下三种:

定时删除

在设置key的过期时间的同时,创建一个定时器,让定时器到过期时间就立即执行对key的删除操作。

需要注意的是这种策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。

惰性删除

只有当访问一个key时,才会判断这个key是否已过期,若果过期急就删除,反之没有过期,就返回该key。

需要注意的是这种策略可以最大化地节省CPU资源,但是对内存非常不友好。甚至极端情况可能出现大量的过期key,因没有再次被访问从而不会被清除,占用大量内存。

定期删除

每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于要删除哪些数据库的哪些过期键,则由算法决定。

每隔一定的时间,程序会扫描一定数量的数据库的expires字典中一定数量的key并删除其中已过期的key。至于要删除哪些数据库的哪些过期key,则由算法决定。

需要注意的是这种策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

expires字典保存所有设置过期key的过期时间数据。 key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。 键空间是指该Redis集群中保存的所有键。

其中定时删除和定期删除为主动删除策略,惰性删除为被动删除策略,Redis中同时使用了惰性删除和定期删除两种删除策略。

10. Redis 官方为什么不提供 Windows 版本?

Redis官方不提供Window 版本主要是因为目前Linux版本已经相当稳定,而且用户量很大。

如果开发windows版本Redis还需要考虑兼容性等问题。

11. Redis 各数据类型最大容量是多少?

String类型:一个String类型的value最大可以存储512M。

List类型:元素个数最多为2^32-1个,即4294967295个。

Set类型:元素个数最多为2^32-1个,即4294967295个。

Hash类型:键值对个数最多为2^32-1个,即4294967295个。

Sorted set类型:同Set类型,元素个数最多为2^32-1个,即4294967295个。

12. Jredis 和 Redisson 有什么区别和关系?

两者区别

jedis:提供了比较全面的redis命令的支持。

redisson:实现了分布式和可扩展性的java数据结构,与jedis相比redisson的功能相对简单,不支持排序、事务、管道、分区等redis特性。

两者关系

Redisson 是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象。

Bloom filter、BitSetSet
SetMultimapScoredSortedSet
SortedSetMapConcurrentMap
ListListMultimapQueue
BlockingQueueDequeBlockingDeque
SemaphoreLockReadWriteLock
AtomicLongCountDownLatch
Publish/SubscribeHyperLogLog

13. Jedis 和 Redisson 有什么优缺点?

Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持

Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。

Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

14. Redis 如何设置密码及验证密码?

Redis设置密码

config set requirepass 123456

Redis授权密码

auth 123456

15. 【字节跳动】你们公司项目中使用 Redis 主从还是集群?

Redis有三种集群模式,分别是:主从模式、哨兵模式、Cluster模式。

Rdis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master;为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充;所以在3.x提出cluster集群模式。

集群一个节点宕机,怎么办,该如何做?

哨兵模式是指在主从集群的基础上,搭建一个哨兵集群,哨兵本身也是一个redis进程,只不过它不会对外提供读写服务,只用来监控主从节点的健康状态。当主节点挂掉后,哨兵集群会通过投票机制,选出一个新的主节点,保证集群正常对外提供服务。

主从模式下 master slave 如何同步数据?

  • 增量同步:主从同步实际上同步的是指令,主节点把对数据造成修改的指令存储下来,同步到子节点,子节点一边执行同步过来的指令,一边向主节点反馈进度。

  • 快照同步:在主节点使用bgsave将数据生成快照文件,快照文件被发送到子节点,子节点接收到快照文件后,立即清空内存中的数据,然后加载快照文件。在快照文件传输的过程中,主节点的指令还一直被写入内存中,如果同步时间过长,或者buffer过小,都有可能造成数据丢失

16. Redis 集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

17. Redis 如何测试连通性?

欢迎大家关注微信公众号: Java精选 ,专注分享前沿资讯,BATJ 大厂面试题解读,架构技术干货,微服务、高可用等架构设计,10年开发老兵帮你少走弯路,欢迎各领域程序员交流学习!

此类面试题只能在微信小程序: Java精选面试题 ,查阅全部内容,感谢支持!

18. Redis 事务命令都有哪几个?

MULTI、EXEC、DISCARD、WATCH

multi:标记一个事务块的开始,返回ok。

exec:执行所有事务块内,事务块内所有命令执行的先后顺序的返回值,操作被,返回空值nil。

discard:取消事务,放弃执行事务块内的所有命令,返回ok。

watch:监视key在事务执行之前是否被其他指令改动,若已修改则事务内的指令取消执行,返回ok。

unwatch:取消watch命令对key的监视,返回ok。

19. Redis key 如何设置过期时间和永久有效?

Redis key设置过期时间使用EXPIRE命令。

Redis key设置永久有效使用PERSIST命令。

20. Redis 回收进程是如何工作的?

客户端运行新的命令,添加了新的数据时Redis检查内存使用情况,如果大于maxmemory的限制,则根据设定好的策略进行回收。

新的命令被执行等,通过不断地穿越内存限制的边界,不断达到边界后回收到边界以下。

如果一个命令的结果导致大量内存被使用,例如很大集合的交集保存到一个新的Key,不用多久这个使用的内存量就会超越内存限制。