Redis-牛客面经八股
1. 详细的说说Redis的数据类型
redis中常用的五种数据结构:string、list、set、zset、hash。
- string结构底层是一个简单动态字符串,支持扩容,存储字符串。
- list存储线性有序且可重复的元素,底层数据结构可以是双向链表/压缩列表。
- set存储不可重复的元素,一般用于求交集、差集等,底层数据结构可以是hash和整数数组。
- zset存储的是有序不可重复的元素,zset为每个元素添加了一个score属性作为排序依据,底层数据结构可以是ziplist和跳表。
- hash类型存储的是键值对,底层数据结构是ziplist和hash。redis会在性能以及节省内存间考虑,选择最适合当前状态的底层数据结构实现
2. 说说Redis的单线程架构。
- redis采用的是单线程+IO多路复用技术。
- 这里单线程指的是redis中读写操作和网络IO使用的是由一个线程来完成,但是其他操作是有其他线程完成,例如持久化操作。
- 单线程既可以简化数据结构和算法的实现,同时也消除了线程切换和锁竞争所带来的消耗。
- redis中采用的IO多路复用技术实现了单线程下同时处理多个IO请求。
- redis为什么这么快:
- 单线程进行读写操作,避免线程切换和锁竞争带来的消耗。
- redis操作是在内存中进行的。
- 最重要的就是:采用了IO多路复用技术,实现了在网络IO中能够处理大量并发请求,实现高吞吐率。
3. 说说Redis的持久化策略。
redis的持久化策略有三种:
- RDB持久化:将当前进程中的数据已生成快照的方式保存到硬盘中,是redis默认的持久化机制。
- 优点:持久化时生成的文件体积小,恢复数据快,
- 缺点:每次运行都需要执行fork操作,RDB持久化策略,没有做到实时的持久化,有时可能会丢失最后一步的数据。
- AOF持久化:以独立日志的方式记录每次写入的命令,重启时执行AOF中的命令即可恢复数据。
- 优点:AOF持久化的安全性更高,保证了数据持久化的实时性。
- 缺点:文件要大很多,恢复速度慢。
- RDB-AOF持久化:这种方式是基于AOF持久化方式构建出来的。兼具RDB和AOF的优势。
4. 说说Redis的缓存淘汰策略。
可以分为三大类:惰性删除、定期删除、maxmemory-policy;
- 惰性删除:客户端访问一个key的时候,Redis会先检查它的过期时间,如果发现过期就立刻删除这个key。
- 定期删除:redis会将设置了过期时间的key放到一个独立的字典中,并对该字典进行每秒10次的过期扫描,过期扫描不会遍历字典中所有的key,而是采用了一种简单的贪心策略,该策略如下:1、从过期字典红随机选择20个key,2、删除这20个key中已过期的key,3、如果已过期key的比例超过25%,则重复步骤1;
- 当写入数据将超出maxmemory限制时,Redis会采用maxmemory-policy所制定的策略进行数据淘汰 即 LRU (最近最少使用原则)LRU算法的不足之处在于,若一个key很少被访问,只是刚刚偶尔被访问了一次,则它就被认为是热点数据,短时间内不会被淘汰。 LFU算法正式用于解决上述问题,LFU(Least Frequently Used)是Redis4新增的淘汰策略,它根据key的最近访问频率进行淘汰。LFU在LRU的基础上,为每个数据增加了一个计数器,来统计这个数据的访问次数。当使用LFU策略淘汰数据时,首先会根据数据的访问次数进行筛选,把访问次数最低的数据淘汰出内存。如果两个数据的访问次数相同,LFU再比较这两个数据的访问时间,把访问时间更早的数据淘汰出内存。
5. 如何实现Redis高可用?
- 主从复制:写一定是在主服务器上,然后主服务器同步给从服务器。
- 缺点:当主服务器挂掉的时候,不能自动切换到从服务器上。主从服务器存储数据一样,内存可用性差。
- 优点:在一定程度上分担主服务器读的压力。
- 哨兵模式:构建多个哨兵节点监视主从服务器,当主服务器挂掉的时候,自动将对应的从服务器切换成主服务器。
- 优点:实现自动切换,可用性高。
- 缺点:主从服务器存储数据一致,内存可用性差。还要额外维护一套哨兵系统,较为麻烦。
- 集群模式:采用无中心节点的方式实现。多个主服务器相连,一个主服务器可以有多个从服务器,不同的主服务器存储不同的数据。
- 优点:可用性更高,内存可用性高。
6. 如何利用Redis实现一个分布式锁?
- 方案一:SETNX + EXPIRE
- 方案二:SETNX + value值是(系统时间 + 过期时间)
- 方案三:使用Lua脚本(包含SETNX + EXPIRE两条指令)
- 方案四:SET的扩展命令(SET EX PX NX)
- 方案五:SET EX PX NX + 校验唯一随机值,再释放锁
- 方案六:开源框架:Redisson
- 方案七:多机实现的分布式锁Redlock
7. Redis怎么实现延时消息?
redis可以通过zset有序集合来实现延时消息功能。可以将发送的时间作为score,发送的内容作为value存储在zset中,轮询zset检查当前时间是否达成消息的发送时间,来实现延时消息的投递。
8. Redis中的String怎么实现的?
String是由SDS(简单动态字符串)实现的,结构包含字符串长度、分配的内存空间和字符串数组。
支持二进制安全数据存储(可以存储包含\0的数据),自动预分配内存空间减少内存重分配次数,通过len字段实现字符串长度O(1)获取。
Redis会根据数据内容动态调整编码格式较少内存占用,int编码、embstr编码、raw编码
- int编码:当数据是数值字符串时,直接使用64位长整型存储,避免字符串解析开销
- embstr编码:字符串长度<=44字节,SDS与对象元数据RedisObject连续存在同一块内存中
- raw编码:字符串长度>44字节,SDS与对象元数据RedisObject分开存储,通过指针关联
9. Redis中的Zset怎么实现的?
- ZSet的数据结构:
- 数据量较小的时候使用压缩表ziplist,数据和score按照score顺序成对存储
- 数据量较大的时候使用跳表skiplist+哈希表dict,skiplist按照score顺序存储数据,实现数据有序以及范围查询等功能,dict存储数据和score的对应关系,实现数据唯一以及快速查询单个数据功能
- ziplist什么时候会转成skiplist+dict?
- 元素个数超过配置zset-max-ziplist-entries,默认是128
- 任意一个元素大小超过zset-max-ziplist-value,默认是64字节
10. 使用 Redis 实现一个排行榜怎么做?
redis实现一个排行榜
使用ZSet集合存储数据和分数,ZADD添加数据、ZRANK查看排名、ZSCORE查看分数、ZRANGE查询升序排名,ZREVRANGE查询降序排名。
设置日榜、周榜、月榜可以通知key进行区分
11. 如何用Redis实现注册中心?
使用redis实现注册中心,注册中心需要满足服务注册、心跳续期、健康检查、服务发现、服务下线几个功能:
- 服务注册:使用Hash存储服务实例信息,HSET 服务名 服务实例ID 实例数据,服务名是redis的key,服务实例ID作为Hash的key,实例数据作为Hash的value,实例数据可以包含ip、端口、是否存活等信息;最后给key设置一个过期时间
- 心跳续期:服务注册的时候有设置一个过期时间,服务实例需要定期更新对应的key过期时间,实现心跳续期
- 健康检查:定期扫描服务key(可以通过lua脚本试下),清理失效的实例
- 服务发现:通过HGETALL获取服务key所有存活的实例
- 服务下线:服务实例下线自动删除服务key
12. 介绍一下Redis的线程模型。
- Redis采用单线程处理命令请求,避免多线程竞争,保证原子性。主线程执行所有数据操作,非阻塞I/O多路复用处理高并发连接。
- 从6.0版本开始支持多线程处理网络I/O(如解析请求/返回结果),但核心逻辑仍为单线程。异步任务(持久化等)由后台线程完成,不影响主线程性能。
13. 介绍一下Redis的事务。
- 通过MULTI和EXEC组合实现事务,DISCARD取消事务
- WATCH实现乐观锁,UNWATCH关闭乐观锁
- 对于指令错误可实现原子化操作,对于运行错误不可实现原子化操作
- 不可回滚
- 顺序执行
14. 介绍一下Redis IO多路复用模型。
- Redis采用IO多路复用技术实现单线程处理高并发请求,通过select/epoll等系统调用监控多个网络连接状态。
- 当某个socket就绪(可读/可写)时,主线程通过事件分派器触发对应操作,避免传统阻塞IO的资源浪费。
- 该模型在单线程中实现高效请求处理,减少上下文切换开销,支撑Redis高吞吐量特性。
15. 说说Redis的大key,为什么会产生大key?
- redis大key指的是存储超大值(字符串过大、集合元素过多等)的键
- 为什么会产生大key,大key有什么问题,如何解决?
- 设计不合理,没有拆分数据结构导致产生大key,大key容易引发持久化超时、读取操作超时阻塞等,通过优化设计,拆分数据结构解决
16. 介绍一下Redis的集群模式。
- Redis集群模式是一种分布式解决方案,通过分片(16384个哈希槽)将数据分散到多个节点,支持自动数据迁移和故障转移。
- 每个节点可为主从结构,主节点处理读写,从节点备份并在主节点故障时接替,实现高可用。客户端通过重定向机制访问数据,无需代理,支持横向扩展与容错。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Chu_Yu-blog!








