Redis面试题汇总
- Redis面试题汇总
-
- 1. 什么是Redis?
- 2. 什么是分布式缓存?
- 3. Memcached 和 Redis的对比:
- 4. 缓存数据的处理流程:
- 5. 为什么要有缓存?
- 6. 常用的数据类型以及相应的应用场景?
- 7. Redis 为什么不使用多线程?
- 8. Redis6.0 之后为何引入了多线程?
- 9. 详细介绍Redis的单线程模型?
- 10. 详细介绍Redis的多线程模型?
- 11. redis多线程是怎么做到无锁的?
- 12. Redis 怎么判断数据是否过期?
- 13. Redis怎么删除过期的数据(删除策略)?
- 14. Redis 内存淘汰机制?或者说Redis的内存用完了会发生什么?
- 15. Redis 持久化机制?
- 16. 什么是AOF重写?
- 17. 为什么重写后的AOF文件为什么可以变小?
- 18. Redis事务
- 19. 为什么 Redis 不支持事务回滚?
- 20. 什么是缓存穿透?如何解决?
- 21. 什么是布隆过滤器?
- 22. 什么是缓存雪崩?如何解决?
- 23. 什么是缓存击穿?如何解决?
- 24. 为什么Redis很快?
- 25. Redis集群
- 26. Redis常用命令总结
- 27. 分布式锁
- 28. keys命令和scan命令对比?
- 29. 消息队列
- 30. Redis持久化数据和缓存怎么做扩容?
Redis面试题汇总
1. 什么是Redis?
Redis 是一个使用 C 语言开发的 非关系型 数据库,Redis 的数据是存在 内存 中的,读写速度非常快。Redis 经常用来做 缓存、分布式锁,消息队列。Redis 支持多种数据类型、事务、持久化、Lua 脚本、多种集群方案。
2. 什么是分布式缓存?
分布式缓存就是以集群的方式搭建缓存(根据缓存的存储情况可以分为:集中式缓存,本地缓存,分布式缓存),主要解决的是单机缓存的容量受服务器限制并且无法保存通用的信息。因为,本地缓存只在当前服务里有效,比如如果你部署了两个相同的服务,他们两者之间的缓存数据是无法共享的。主要的技术是 Memcached 和 Redis。
3. Memcached 和 Redis的对比:
- 共同点 :
- 都是基于内存的数据库;
- 都有过期策略;
- 两者的性能都非常高。
- 区别 :
- Redis 支持更丰富的数据类型,Memcached 只支持最简单的 k/v 数据类型;
- Redis 支持数据的持久化,Memecache 把数据全部存在内存之中;
- Redis 有灾难恢复机制;
- Redis 在服务器内存使用完之后,可以将不用的数据放到磁盘上。但是,Memcached 在服务器内存使用完之后,就会直接报异常;
- Redis 有原生的集群模式,Memcached 没有,需要依靠客户端来实现往集群中分片写入数据;
- Redis 使用单线程的多路 IO 复用模型(Redis 6.0 引入了多线程 IO ),Memcached 是多线程的非阻塞 IO 复用模型;
- Redis 支持发布订阅模型、Lua 脚本、事务等功能,Memcached 不支持;
- Redis 对于过期数据同时使用了惰性删除与定期删除,Memcached 只用了惰性删除 。
4. 缓存数据的处理流程:
- 用户发出一个请求,后台首先从缓存中取数据,如果取到了(这就是所谓的缓存命中)就直接返回。
- 如果缓存中不存在,就去看数据库中是否存在。
- 如果数据库中存在,就更新缓存中的数据,并且返回结果。
- 如果数据库中不存在,返回空数据。
5. 为什么要有缓存?
操作缓存就是直接操作内存,速度相当快,使用缓存后,服务器每秒可以执行的查询次数远远大于直接使用数据库。但是,使用缓存后,需要保持数据库和缓存中的 数据一致性。
6. 常用的数据类型以及相应的应用场景?
- string:简单的key-value类型(相当于java中的Map),适用于需要计数的场景,比如统计用户的访问次数、热点文章的点赞转发数量等。
- list:使用双向链表实现(相当于java中的双向队列),适用于发布与订阅、消息队列、慢查询。
- set:无序集合(相当于java中的HashSet),适用于存放不能重复的数据以及需要获取多个数据源交集和并集等场景,比如统计共同粉丝和共同爱好等。
- zset:有序集合,在set的基础上增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列(相当于Java 中 HashMap 和 TreeSet 的结合),适用于需要对数据根据某个权重进行排序的场景。比如统计礼物排行榜等。
- hash:相当于java中的HashMap,数组 + 链表实现,适用于对象数据的存储,比如用户信息,商品信息等等。
- bitmap:存储的是连续的二进制数字(0 和 1),二进制数字中每一个 bit 位表示某个元素对应的值或者状态,适合需要保存状态信息的场景,比如统计用户是否签到、是否在线、是否点赞过某个视频等。
7. Redis 为什么不使用多线程?
- 单线程编程容易并且更容易维护;
- Redis 的性能瓶颈不再是 CPU ,主要在内存和网络(纯内存操作,已经很快了);
- 多线程就会存在死锁、线程上下文切换等问题。
8. Redis6.0 之后为何引入了多线程?
Redis6.0 引入多线程主要是为了提高网络 IO 读写性能。因为对于一些大键值对(几十 MB 或者几百 MB 的数据)的删除操作,Redis 可能会需要在释放内存空间上消耗较多的时间,这些操作就会阻塞待处理的任务,影响执行的效率。
** 注意:(1) 严格来讲从Redis4.0之后并不是单线程,除了主线程外,它也有后台线程在处理一些较为缓慢的操作,例如清理脏数据、无用连接的释放、大 key 的删除等等。(2) Redis 的多线程只是在网络数据的读写这类耗时操作上使用了, 执行命令仍然是单线程顺序执行。
9. 详细介绍Redis的单线程模型?
Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器。文件事件处理器包括有①多个socket;②IO多路复用程序(通过包装select、epoll、evport和kqueue这些I/O多路复用函数库来实现的);③文件事件分派器;④事件处理器(命令请求处理器,命令回复处理器,连接应答处理器等等)。文件事件处理器使用 I/O 多路复用程序来同时监听来自客户端的连接(监听多个套接字socket),当socket可用时,会把这个socket放入一个队列中排队,然后每次从队列中取出一个socket给事件分派器,事件分派器再把socket分派给对应的事件处理器去处理。
客户端与Redis通信的一次流程:
- Redis启动初始化时,将连接应答处理器跟AE_READABLE事件关联。
- 若一个客户端发起连接,会产生一个AE_READABLE事件,然后由连接应答处理器负责和客户端建立连接,创建客户端对应的socket,同时将这个socket的AE_READABLE事件和命令请求处理器关联,使得客户端可以向主服务器发送命令请求。
- 当客户端向Redis发请求时(不管读还是写请求),客户端socket都会产生一个AE_READABLE事件,触发命令请求处理器。处理器读取客户端的命令内容, 然后传给相关程序执行。
- 当Redis服务器准备好给客户端的响应数据后,会将socket的AE_WRITABLE事件和命令回复处理器关联。
- 当客户端准备好读取响应数据时,会在socket产生一个AE_WRITABLE事件,由对应命令回复处理器处理,即将准备好的响应数据写入socket,供客户端读取。
- 命令回复处理器全部写完到 socket 后,删除该socket的AE_WRITABLE事件和命令回复处理器的映射。
推荐阅读:https://blog.csdn.net/xp_xpxp/article/details/100999825
10. 详细介绍Redis的多线程模型?
- 服务器启动时启动一定数量线程,每个线程对应一个队列。
- 服务器收到的每个请求都会放入全局读队列clients_pending_read,然后将队列中的元素分发到每个线程对应的队列io_threads_list中。
- 每个线程接收请求参数并做解析,解析完之后设置一个标记CLIENT_PENDING_READ,标识参数解析完成,可以操作数据库了。
- 主线程遍历每个线程的队列ÿ