面试官最喜欢问的Redis知识

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis是一个开源(BSD许可)的,用C语言编写的基于内存的数据结构存储系统(是一个高性能的 key-value存储系统)。而且会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化。Redis可以用在数据库,缓存和消息中间件。Redis作为一种高性能的key-value内存缓存数据库,在各大互联网公司的面试中也是经常被问到。

01前言


Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis是一个开源(BSD许可)的,用C语言编写的基于内存的数据结构存储系统(是一个高性能的 key-value存储系统)。而且会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化。Redis可以用在数据库,缓存和消息中间件。Redis作为一种高性能的key-value内存缓存数据库,在各大互联网公司的面试中也是经常被问到。


02常用基本数据类型


Redis支持丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。


1、String 字符串

字符串有C字符串和SDS字符串两种,C字符串里面不能包含空字符,所以C字符串只能保存文本数据,不能保存图片、音频、视频、压缩文件等二进制数据。


SDS是二进制安全的字符串,不仅可以保存文本数据,还可以保存任意格式的二进制数据。


总结:Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS作为字符串表示。


比起C字符串,SDS具有以下优点:


  1. 常数复杂度获取字符串长度
  2. 杜绝缓冲区溢出
  3. 减少修改字符串长度时所需的内存重分配次数
  4. 二进制安全
  5. 兼容部分C字符串函数

c2958bacc050757bc38ba9b09d6b92b0_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


2、链表List

List结构为链表提供了表头指针head、表尾指针tail,以及链表长度计数器len,特性如下:

双端:链表节点带有prev和next指针,获取某个节点的前置节点和后置节点的复杂度都是O(1)

无环:表头节点的prev指针额表尾节点的next指针都指向null,对链表的访问以null为终点


带表头指针和表尾指针:通过list结构的head指针和tail指针,程序获取链表的表头节点和表尾节点的复杂度为O(1)

带链表长度计数器:程序使用list结构的len属性来对list持有的链表节点进行计数,程序获取链表节点数量的复杂度为O(1)

多态:链表节点使用void*指针来保存节点的值,并且可以通过list结构的dup、free、match、三个属性为节点值设置类型特定的函数,所以链表可以用于保存各种不同类型的值

总结:链表被广泛用于实现Redis的各种功能,比如列表键,发布与订阅,慢查询,监视器等

每个链表节点由一个listNode结构来表示,每个节点都有一个指向前置节点和后置节点的指针,redis的链表是双向链表。

每个链表使用一个list结构来表示,这个结构带有表头节点指针,表尾节点指针,以及链表长度信息

链表表头节点的前置节点和表尾节点的后置节点都指向null,所以redis的链表实现是无环链表。

通过为链表设置不同的类型特定函数,redis的链表可以用于保存各种不同类型的值。

3、字典hash(或map)


又称为符号表、关联数组或映射,是一种用于保存键值对(key和value进行关联)的抽象数据结构。

Redis的字典使用哈希表作为底层实现,一个哈希表里面可以有多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对。

解决键冲突:当有两个或以上数量的键被分配到了哈希表数组的同一个索引上面时,称这些键发生了冲突。

Redis的哈希表使用链地址法来解决冲突,每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表连接起来,如此解决键冲突。

61eedcb003af69a52f52dfd558a40804_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

Rehash:随着操作的不断执行,哈希表报存的键值对会逐渐地增多或减少,为了让哈希表的负载因子维持在一个合理的范围之内,当哈希表保存的键值对数量太多或太少时,程序需要对哈希表进行扩展或收缩。此时就是执行rehash(重新散列)的操作来完成,步骤如下:

3d8775f103b4e41a278fc0d5ed2c819d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

以下条件的任意一个被满足时,程序会自动开始对哈希表执行扩展操作:

  • 服务器目前没有执行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的负载因子大于等于1。
  • 服务器目前正在执行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的负载因子大于等于5。
  • 当哈希表的负载因子小余0.1时,程序自动开始对哈希表执行收缩操作。

回顾总结:字典被广泛用于实现redis的各种功能,其中包括数据库和哈希键。


a、Redis中的字典使用哈希表作为底层实现,每个字典带有两个哈希表,一个平时使用,一个仅在进行rehash时使用。


b、当字典被用作数据库的底层实现,或者哈希键的底层实现时,redis使用murmurHash2算法来计算键的哈希值


c、哈希表使用链地址法来解决键冲突,被分配到同一个索引上的多个键值对会连接成一个单向链表


d、在对哈希表进行扩展或收缩操作时,程序需要将现有的哈希表包含的所有键值对redhs到新哈希表里面,并且这个rehash过程并不是一次性地完成的,而是渐进式地完成的。


4、集合set整数集合是redis用于保存整数值得集合抽象数据结构,它可以保存类型为int16 int32 或int64的整数值,并且保证集合中不会出现重复元素。

整数集合是集合键的底层实现之一。

整数集合的底层实现为数组,这个数组以有序、无重复的方式保存集合元素,在有需要时,程序会根据新添加的元素的类型,改变这个数组的类型。

升级操作作为整数集合带来了操作上的灵活性,并且可能地节约了内存。

整数集合只支持升级操作,不支持降级操作。


5、sorted set 集合

sorted set有序集合的编码可以是ziplist或者skiplist.

Ziplist编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素则保存元素的分值。

压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向,分值较大的元素则被放置在靠近表尾的地方。

b3955b6b95c3528f3ea45bd6fe08bd84_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

6、压缩列表

压缩列表是列表键和哈希键的底层实现之一,当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么redis就会使用压缩列表来做列表键的底层实现。


03Redis的高可用


3.1 Sentinel哨兵

哨兵是Redis的高可用性解决方案:由一个Sentinel 或多个Sentinel 实例组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

8b65f50eb3954c00a4ad6fee375e0c74_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

3.2 选举领头Sentinel

当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel 对下线主服务器执行故障转移操作。5efa7985e995bd43986c9cf2651eff8b_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

c26016728d0b0197f6a2900bdb95d258_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


3.3 故障转移

在选举产生出领头Sentinel 后,领头Sentinel 将对已下线主服务器执行故障转移操作,该操作包含以下三个步骤:

在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器。让已下线主服务器属下的所有从服务器改为复制新的主服务器。将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器。


04Redis持久化


Redis是一个内存数据库,它将自己的数据库状态存储在内存里面,所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失不见。为了解决这个问题,Redis提供了RDB持久化功能,这个功能可以将Redis在内存中的数据库状态保存奥磁盘里面,避免数据意外丢失。

4.1 RDB持久化

8cb3ec4bb34ef8b8e6683e18baf33858_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

RDB文件是保存在磁盘里面的,所以即使Redis服务器进程退出,甚至运行Redis服务器的计算机停机,但只要RDB文件仍然存在,Redis服务器就可以用它来还原数据库状态。

RDB文件写入:有2个命令可以用于生成RDB文件:一个是SAVE,一个是BGSAVE。

5d78ca5fb4f088976b6c566e1ef8b9ab_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

重点内容:RDB文件用于保存和还原Redis服务器所有数据库中的所有键值对数据。SAVE命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器。BGSAVE命令由子进程执行保存操作,所以该命令不会阻塞服务器。服务器状态中会保存所有有用save选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行BGSAVE命令。RDB文件是一个经过压缩的二进制文件,由多个部门组成。对于不同类型的键值对,RDB文件会使用不同的方式来保存他们。

4.2 AOF持久化

概念:AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的,如图

6ed56ee99ccdfbe53d24b6c79f009975_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

c1f7475125fac2b1acb5508d453a4f4b_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png



4.3 AOF持久化的实现

AOF持久化功能的实现可以分为命令追加、文件写入、文件同步三个步骤。命令追加:当AOF持久化功能处于打开状态时,服务器在执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾:

3bf02d11caa1e938e8768b071d6157fc_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

重点内容:AOF文件通过保存所有修改数据库的写命令请求来记录服务器的数据库状态AOF文件中的所有命令都以Redis命令请求协议的格式保存命令请求会先保存到AOF缓冲区里面,之后再定期写入并同步到AOF文件Appendfsync选项的不同值对AOF持久化功能的安全性及Redis服务器的性能有很大影响服务器只要载入并重新执行保存在AOF文件中的命令,就可以还原数据库本来的状态AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,但体积更小AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无需对现有AOF文件进行任何读入、分析或者写入操作在执行BGREWIRTEAOF命令时,Redis服务器会维护一个AOF重写缓冲区,该缓冲区会在子进程创建新的AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新的AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件的重写操作。


05生存时间或过期时间


5.1 设置过期时间

Redis通过expire命令或者pexpire命令,客户端可以以秒或者毫秒精度为数据库中的某个键设置生存时间(Time to Live TTL),在经过指定的秒数或者毫秒数之后,服务器就会自动删除生存时间为0的键

06fd8433d7299c56a0a20a4a28c7160f_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

d35ea3c15b5dea0536b90fdbd2588efb_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

客户端可以通过expire命令或者pexpireat命令,以秒或者毫秒精度给数据库中的某个键设置过期时间(expire time)

3f36705e74dc428531ae78382234bec7_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

32d88b8e04e472b3ae8949e844163aee_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


5.2 过期键删除

有如下几种删除策略:

16f05d7786edb1b23bba6413a8cee8ce_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


06荐语


Redis的知识内容非常丰富,Redis的应用场景也很多,尤其是在高并发和高可用等场景下,它给我们带来很大便利的同时,也极大的保障了系统的性能和安全等。推荐查阅以下关联文章:

Redis快速入门

Redis的三种模式:主从、哨兵、集群

使用RedisTemplate对Redis的常用操作

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 缓存 NoSQL
Redis 面试题
Redis 基础面试题
|
3月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
3月前
|
存储 NoSQL 算法
阿里面试:亿级 redis 排行榜,如何设计?
本文由40岁老架构师尼恩撰写,针对近期读者在一线互联网企业面试中遇到的高频面试题进行系统化梳理,如使用ZSET排序统计、亿级用户排行榜设计等。文章详细介绍了Redis的四大统计(基数统计、二值统计、排序统计、聚合统计)原理和应用场景,重点讲解了Redis有序集合(Sorted Set)的使用方法和命令,以及如何设计社交点赞系统和游戏玩家排行榜。此外,还探讨了超高并发下Redis热key分治原理、亿级用户排行榜的范围分片设计、Redis Cluster集群持久化方式等内容。文章最后提供了大量面试真题和解决方案,帮助读者提升技术实力,顺利通过面试。
|
3月前
|
存储 NoSQL 算法
面试官:Redis 大 key 多 key,你要怎么拆分?
本文介绍了在Redis中处理大key和多key的几种策略,包括将大value拆分成多个key-value对、对包含大量元素的数据结构进行分桶处理、通过Hash结构减少key数量,以及如何合理拆分大Bitmap或布隆过滤器以提高效率和减少内存占用。这些方法有助于优化Redis性能,特别是在数据量庞大的场景下。
面试官:Redis 大 key 多 key,你要怎么拆分?
|
4月前
|
存储 NoSQL Java
可能是最漂亮的Redis面试基础详解
我是南哥,相信对你通关面试、拿下Offer有所帮助。敲黑板:本文总结了Redis基础最常见的面试题!包含了Redis五大基本数据类型、Redis内存回收策略、Redis持久化等。相信大部分Redis初学者都会忽略掉一个重要的知识点,Redis其实是单线程模型。我们按直觉来看应该是多线程比单线程更快、处理能力更强才对,比如单线程一次只可以做一件事情,而多线程却可以同时做十件事情。但Redis却可以做到每秒万级别的处理能力,主要是基于以下原因:(1)Redis是基于内存操作的,Redis所有的数据库状态都保存在
100 7
可能是最漂亮的Redis面试基础详解
|
4月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
4月前
|
NoSQL 算法 Redis
Redis面试篇
Redis面试篇
85 5
|
4月前
|
缓存 NoSQL Java
Java中redis面试题
Java中redis面试题
76 1
|
3月前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
4月前
|
缓存 NoSQL 算法
面试题:Redis如何实现分布式锁!
面试题:Redis如何实现分布式锁!