关于Redis的最常见的十道面试题

面试题一:Redis为什么执行这么快?

Redis运行比较快主要原因有以下几种:

  1. 纯内存操作:Redis将所有数据存储在内存中,这意味着对数据的读写操作直接在内存中运行,而内存的访问速度远远高于磁盘。这种设计使得Redis能够已接近硬件极限的速度处理数据读写
  2. 单线程模型:Redis使用单线程模型来处理客户端请求。这可能听起来效率不高,但是实际上,这种设计避免了多线程频繁切换和过度竞争带来的性能开销。Redis每个请求的执行时间都是很短的,因此单线程下,也能处理大量的并发请求
  3. I/O多路复用:Redis使用了I/O多路复用技术,可以在单线程的环境下同时监听多个客户端连接,只有当有网络事件(如用户发送一个请求)发生的时候才会进行实际的I/O操作。这样有效的利用了CPU资源,减少了无谓的等待
  4. 高效数据结构:Redis提供了多种高效的数据结构,如哈希表、有序集合等。这些数据结构的实现都经过了优化,使得Redis在处理这些数据结构的操作是非常高效的

面试题二:Redis是单线程执行还是多线程执行?它有线程安全问题吗?为什么吗?

Redis版本在6.0之前都是使用的单线程运行的。所有的客户端的请求处理、命令执行以及数据读写操作都是在一个主线程中完成得。这种设计目的就是为了防止多线程环境下的锁竞争和上下文切换所带来的性能开销,这样保证在高并发场景下的性能

Redis版本在6.0中,开始引入了多线程的支持,但是这仅限于网络I/O层面,即在网络请求阶段使用工作线程进行处理,对于指令的执行过程,仍然是在主线程来处理,所以不会存在多个线程通知执行操作指令的情况

关于线程安全问题,从Redis服务层面俩看,Redis Server本身就是一个线程安全按的K-V数据库,也就是说在Redis Server上面执行的指令,不需要任何同步机制,不会存在线程安全问题

面试题三:在实际工作中,使用Redis实现了哪些业务场景?

Redis在实际工作中广泛应用于多种业务场景,以下是一些常见的例子:

缓存:Redis作为Key-Value形态的内存数据库,最先会被想到的应用场景就是作为数据缓存。Redis提供了键过期功能,也提供了键淘汰策略,所以Redis用在缓存的场合非常多

排行榜:很多网站都有排行榜应用,如京东的月度销量榜单、商品按时间上新排行榜等。Redis提供的有序集合(zset)数据类

分布式会话:在集群模式下,一般会搭建以Redis等内存等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理

分布式锁:在高并发的情景,可以利用Redis的setnx功能来编写分布式锁

面试题四:Redis常用数据类型有哪些?

Redis中,常见的数据类型有如下几种:

  1. 字符串(String):最简单的数据类型,可以包含任意数据,如文本、二进制数据等。常见的使用场景是存储Session信息、存储缓存信息、存储整数信息,可以使用incr实现整数+1,使用decr实现整数-1
  2. 列表(List):有序的字符串元素集合,支持双端进行插入和删除操作,可以用作队列或栈
  3. 哈希(Hash):用于存储对象,类似于关联数组。每个哈希可以包含字段和与之相关联的值。常见使用场景是存储Session信息、存储商品的购物车,购物车非常适用于哈希字典表示,使用人员唯一编号作为字典的key,value值可以存储商品的id和数量等信息、存储详情页等信息
  4. 集合(Set):一个无序并唯一的键值集合。它常见的使用场景是是仙女关注功能,比如关注我的人和我关注的人,使用集合存储,可以保证人员不重复
  5. 有序集合(Sorted Set):使用zset表示,相当于Set集合类型多了一个排序属性score(分值)。。它常见的使用场景是可以用来存储排名信息,关注列表功能,这样就可以根据关注实现排序展示

面试题五:存储Session信息你会使用哪种数据类型?为什么?

在实际工作中,小型的项目会使用Redis存储Session信息,但是不同业务场景存储Session信息的类型也是不同的,具体来说:

存储数据简单(不涉及局部更新):使用String类型粗怒触Session,这样做的优缺点如下:

优点:

        存取操作简单直观,只需要单个键执行操作即可

        多余小型Session,存储开销相对于较小

缺点:

        如果Session数据复杂或者需要频繁更新其中的部分字段,则每次更新都需要重新序列化整个Session对象

        不利于查询Session内特定字段值

存储数据复杂(涉及局部更新):如果Session数据结构复杂且需要频繁更新或查询其中个别字段,通常建议使用哈希表存储Session。每个Session视为一个独立的哈希表,Session ID作为key,Sesion内各个字段作为field-value对存储在哈希表中。示例:HSET session:123 userId 123 username user1,这样做的优缺点如下:

优点:

        可以方便地进行字段级别的读写操作,例如 HGET session:23 userd 和 HSET session:123 lastAccessTime now

        更新部分字段时无需修改整个Session内容

缺点:

        相对于简单的字符串存储,哈希表占用的空间可能更大,尤其时当Session数据包含多个值的时候

小结: 如果 Session 数据结构复杂且需要频繁更新或查询其中的个别字段,通常建议使用哈希表来存储 Session;而在 Session 数据较为简单、不涉及局部更新的情况下,使用字符串存储也是可行的选择

面试题六:有序集合底层是如何实现的?

在Redis7之前,有序集合使用的是ziplist(压缩列表)+skiplist(跳跃表),当数据列表元素小于128个,并且所有元素成员的长度都小于64字节时,使用压缩列表存储,否则使用调表存储

在Redis之后,有序集合使用listPack(紧凑列表)+skiplist(跳跃表)

面试题七:什么是跳表?为什么使用跳表?

skiplist是一种以空间换时间的数据结构。由于链表无法进行二分查找,因此借鉴数据库索引的思想,提取出链表中的关键姐点(索引),现在关键节点上查找,在进入下层链表查找提取多层关键节点,就形成了跳表。但是由于索引要占据一定的空间,所以索引添加的越多,占用的空间越多。

于一个单链表来讲,即便链表中存储的数据是有序的,如果我们要想在其中查找某个数据,也只能从头到尾遍历链表。这样查找效率就会很低,时间复杂度会很高O(N)

从这个例子里,我们看出,加来一层索引之后,查找一个结点需要遍历的结点个数减少了,也就是说查找效率提高了。时间复杂度从原来的O(n)到O(logn),是一空间换时间的解决方法

面试题八:说一下跳表的查询流程?

跳表的查询流程如下:

  1. 起始搜索:查询操作从跳表的顶层开始,跳表的顶层包含一个或多个节点,从最顶层的头节点开始,将当前节点设置为头节点
  2. 检查下一个节点:检查当前节点的下一个节点,如果节点的分值小于目标分值,则向右移动检查下一个节点,重复此步骤,直到找到一个大于目标值的节点,或者最后一个节点
  3. 逐层探索:如果当前下一个结点的值大于目标值,或者最后一个节点,则将当前指针向下层进行搜索,重复上述步骤
  4. 终止并返回:在查找的过程中,如果找到了和目标分支相同的值,或者遍历完所有层级仍然未找到对应的节点,则说明要查找的元素不存在于跳表中,则终止查找并返回查询到的内容或NULL值

面试题九:说一下跳表的添加流程?为什么要有“随机层数”这个概念?

跳表的添加流程主要是包括以下步骤:

查找插入位置:首先,我们需要找到新元素应该插入的位置。这个过程与跳表查找操作类似,我们从最高层所以一年开始,逐层向下查找直到找到最后一个位置,使得该位置前面的元素小于新元素,后面的元素大于新元素

生成随机层数:在确定新元素插入位置后,我们需要决定新元素在跳表中的层数。这个层数是通过一个随机函数生成的。每个节点肯定都有第一层指针(每个节点都在第一层链表中)。如果一个节点有第i层指针(即节点已经在第一层到第i层链表中),那么他又第(i+1)层指针的

插入新元素:根据生成的随机层数,我们在相应的层中插入新元素。对于每一层,我们都需要更新相应的前驱和后继指针,使得它们指向新插入的元素

更新跳表的最大层数:如果新插入的元素的层数大于跳表的当前最大层数,我们需要更新跳表的最大层数

关于“随机层数”的概念,其主要目的是为了保持跳表的平衡性。如果我们固定每个元素的层数,那么在某些情况下,跳表可能会退化成普通的链表,从而导致查找效率降低。通过随机选择每个元素的层数,我们可以确保跳表的高度大致为log(n),从而保证查找、插入和删除操作的时间复杂度为O(log n)

给定如上跳表,假设要插入节点2。首先需要判断节点2是否已经存在,若存在则返回false。否则,随机生成待插入节点的层数

/*** 生成随机层数[0,maxLevel)* 生成的值越大,概率越小** @return*/
private int randomLevel() {int level = 0;while (Math.random() < PROBABILITY && level < maxLevel - 1) {++level;}return level;
}

这里的PROBABILITY =0.5。上面算法的意思是返回1的概率是1/2,返回2的概率是1/4,返回3的概率是1/8,依次类推。看成一个分布的话,第0层包含所有节点,第1层含有1/2个节点,第2层含有1/4 个节点…

注意这里有一个最大层数maxLevel ,也可以不设置最大层数。通过这种随机生成层数的方式使得实现起来简单。假设我们生成的层数是3

在1和3之间插入节点2,层数是3,也就是节点2跳跃到了第3层

public boolean add(E e) {if (contains(e)) {return false;}int level = randomLevel();if (level > curLevel) {curLevel = level;}Node newNode = new Node(e);Node current = head;//插入方向由上到下while (level >= 0) {//找到比e小的最大节点current = findNext(e, current, level);//将newNode插入到current后面//newNode的next指针指向该节点的后继newNode.forwards.add(0, current.next(level));//该节点的next指向newNodecurrent.forwards.set(level, newNode);level--;//每层都要插入}size++;return true;
}

我们通过一个例子来模拟,由于实现了直观的打印算法。假设我们要插入1, 6, 9, 3, 5, 7, 4, 8 过程如下:

add: 1
Level 0:  1add: 6
Level 0:  1 6add: 9
Level 2:      9
Level 1:      9
Level 0:  1 6 9add: 3
Level 2:    3   9
Level 1:    3   9
Level 0:  1 3 6 9add: 5
Level 2:    3     9
Level 1:    3 5   9
Level 0:  1 3 5 6 9add: 7
Level 2:    3       9
Level 1:    3 5     9
Level 0:  1 3 5 6 7 9add: 4
Level 2:    3         9
Level 1:    3   5     9
Level 0:  1 3 4 5 6 7 9add: 8
Level 2:    3           9
Level 1:    3   5       9
Level 0:  1 3 4 5 6 7 8 9

面试题十:使用Redis如何实现分布式锁?

实现分布式锁

使用Redis实现分布式锁可以通过setnx(set if not exists)命令实现,但当我们使用setnx创建键值成功时,则表中加锁成功,否则代码加锁失败,实现示例如下:

127.0.0.1:6379> setnx lock true
(integer) 1#创建锁成功
#逻辑业务处理..

当我们重复加锁时,只有第一次会加锁成功

127.8..1:6379> setnx lock true # 第一次加锁
(integer) 1
127.8.8.1:6379> setnx lock true # 第二次加锁
(integer) 0

从上述命令可以看出,我们可以看执行结果返回是不是1,就可以看出是否加锁成功

释放分布式锁

127.0.0.1:6379> de1 lock
(integer) 1 #释放锁

然而,如果使用 setnx ock true 实现分布式锁会存在死锁问题,以为 setnx 如未设置过期时间,锁忘记删了或加锁线程宕机都会导致死锁,也就是分布式锁一直被占用的情况

解决死锁问题

死锁问题可以通过设置超时时间来解决,如果超过了超时时间,分布锁会自动释放,这样就不会存在死锁问题了也就是 setnx和 expire 配合使用,在 Redis 2.6.12 版本之后,新增了一个强大的功能,我们可以使用一个原子操作也就是一条命令来执行 setnx 和expire 操作了,实现示例如下:

127.0.0.1:6379> set lock true ex 3 nx
OK #创建锁成功
127...1:6379> set lock true ex 3 nx
(ni1) #在锁被占用的时候,企图获取锁失败

其中ex为设置超时时间, nx 为元素非空判断,用来判断是否能正常使用锁的。
因此,我们在 Redis 中实现分布式锁最直接的方案就是使用 set key value ex timeout nx 的方式来实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/47242.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LNMP架构部署及应用

部署LNMP架构流程 1.安装Nginx&#xff08;上传软件包&#xff0c;执行脚本&#xff09; yum -y install pcre-devel zlib-devel gcc gcc useradd -M -s /sbin/nologin nginx tar zxf nginx-1.12.0.tar.gz cd nginx-1.12.0 ./configure --prefix/usr/local/nginx --usernginx…

python原型链污染

python原型链污染 ​ 后面会有跟着Article_kelp慢慢操作的&#xff0c;前面先面向题目学习。 背景&#xff1a; ​ 国赛遇到了这个考点&#xff0c;然后之后的DASCTF夏季挑战赛也碰到了&#xff0c;抓紧粗略学一手&#xff0c;学了JavaScript之后再深究原型链污染。 简介&a…

传输层和网络层的关系,ip协议+ip地址+ip报头字段介绍(4位TOP字段,8位生存时间(ttl)),ip地址和端口号的作用

目录 传输层和网络层的关系 引入 介绍 ip协议 介绍 ip地址 引入 数据传递过程 举例(ip地址的作用) ip报头 格式 4位版本号 ip地址不足的问题 8位服务类型 4位TOP(type of service)字段 最小延时 最大吞吐量 4位首部长度 16位总长度 8位协议号 首部校验和…

《样式设计001:表单的2种提交方式》

描述&#xff1a;在开发小程序过程中&#xff0c;发现一些不错的案例&#xff0c;平时使用也比较多&#xff0c;稍微总结了下经验&#xff0c;以下内容可以直接复制使用&#xff0c;希望对大家有所帮助&#xff0c;废话不多说直接上干货&#xff01; 一&#xff1a;表单的2种…

【强化学习的数学原理】课程笔记--4(随机近似与随机梯度下降,时序差分方法)

目录 随机近似与随机梯度下降Mean estimationRobbins-Monro 算法用 Robbins-Monro 算法解释 Mean estimation用 Robbins-Monro 算法解释 Batch Gradient descent用 SGD 解释 Mean estimation SGD 的一个有趣的性质 时序差分方法Sarsa 算法一个例子 Expected Sarsa 算法n-step S…

电容认识和特点总结

图片 常见的电容名字及特点 名字特点容量和耐压独石电容MLCCMulti layer Ceramic Capacitors (多层陶瓷电容) 常见的贴片电容&#xff0c;容量大于瓷片电容0.5pF~100uF,耐压<100V瓷片/陶瓷电容耐压远高于独石电容,容量小<0.1uf&#xff0c;用于晶振旁路电容滤波铝电解电…

PY32F002B单片机 ISP 串口下载注意事项

一、PY32F002B ISP 串口下载的连接方式 仿真上的 VCC 和 GND 连接到 MCU 的 VCC 和 VSS&#xff0c; 仿真的 TX 接 MCU 的 RX&#xff0c;RX 接 MCU 的 TX。 二、因为 PY32F002B 没有 BOOT&#xff0c;需要用 ISP 串口下载的话需要下载串口引导程序。 下载这个目录下的 IAP…

Python酷库之旅-第三方库Pandas(036)

目录 一、用法精讲 111、pandas.Series.item方法 111-1、语法 111-2、参数 111-3、功能 111-4、返回值 111-5、说明 111-6、用法 111-6-1、数据准备 111-6-2、代码示例 111-6-3、结果输出 112、pandas.Series.xs方法 112-1、语法 112-2、参数 112-3、功能 112-…

几种常用排序算法

1 基本概念 排序是处理数据的一种最常见的操作&#xff0c;所谓排序就是将数据按某字段规律排列&#xff0c;所谓的字段就是数据节点的其中一个属性。比如一个班级的学生&#xff0c;其字段就有学号、姓名、班级、分数等等&#xff0c;我们既可以针对学号排序&#xff0c;也可…

OpenGL-ES 学习(7) ---- VBO EBO 和 VAO

目录 VBO(Vertex Buffer Object)EBO(Element Buffer Object)VAO(Vertex Array Object) VBO(Vertex Buffer Object) EBO(Element Buffer Object) VBO(Vertex Buffer Object) 实际是指顶点缓冲器对象 在 opengl-es 2.0 的编程中&#xff0c;用于绘制图元的顶点数据是从 CPU 传…

暑假第一周学习内容-ZARA仿写

仿写ZARA总结 文章目录 仿写ZARA总结前言无限轮播图分栏控制器与UIScrollViewUIScorllView的协议部分UISegmentedControl的协议部分 自定义cell 前言 本文主要是用来总结仿写ZARA中遇到的一些问题&#xff0c;以及ZARA中学习到的一些新知识。 无限轮播图 这里我们先给出无限…

使用Windows Linux 子系统安装 Tensorflow,并使用GPU环境

在Microsoft Store商店安装Ubuntu 20.04 使用 nvidia-smi 命令查看GPU信息&#xff0c;查看支持的CUDA版本&#xff0c;这里最高支持11.7 安装cuda工具集 进入官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer&#xff0c;现在对应版本&#xff0c;点击 配置平台&…

LeNet实验 四分类 与 四分类变为多个二分类

目录 1. 划分二分类 2. 训练独立的二分类模型 3. 二分类预测结果代码 4. 二分类预测结果 5 改进训练模型 6 优化后 预测结果代码 7 优化后预测结果 8 训练四分类模型 9 预测结果代码 10 四分类结果识别 1. 划分二分类 可以根据不同的类别进行多个划分&#xff0c;以…

科研绘图系列:R语言分割小提琴图(Split-violin)

介绍 分割小提琴图(Split-violin plot)是一种数据可视化工具,它结合了小提琴图(violin plot)和箱线图(box plot)的特点。小提琴图是一种展示数据分布的图形,它通过在箱线图的两侧添加曲线来表示数据的密度分布,曲线的宽度表示数据点的密度。而分割小提琴图则是将小提…

绿色算力|暴雨服务器用芯片筑起“十四五”转型新篇章

面对全球气候变化、技术革新以及能源转型的新形势&#xff0c;发展低碳、高效的绿色算力不仅是顺应时代的要求&#xff0c;更是我国建设数字基础设施和展现节能减碳大国担当的重要命题&#xff0c;在此背景下也要求在提升算力规模和性能的同时&#xff0c;积极探索推动算力基础…

【iOS】APP仿写——网易云音乐

网易云音乐 启动页发现定时器控制轮播图UIButtonConfiguration 发现换头像 我的总结 启动页 这里我的启动页是使用Xcode自带的启动功能&#xff0c;将图片放置在LaunchScreen中即可。这里也可以通过定时器控制&#xff0c;来实现启动的效果 效果图&#xff1a; 这里放一篇大…

31_MobileViT网络讲解

VIT:https://blog.csdn.net/qq_51605551/article/details/140445491?spm1001.2014.3001.5501 1.1 简介 MobileVIT是“Mobile Vision Transformer”的简称&#xff0c;是一种专门为移动设备设计的高效视觉模型。它结合了Transformer架构的优点与移动优先的设计原则&#xff0…

在eclipse中导入本地的jar包配置Junit环境步骤(包含Junit中的方法一直标红的解决方法)

搭建JUnit环境 一、配置环境 跟上一篇的那种方法不一样&#xff0c;直接Add to Build Path 是先将jar包复制到项目的lib目录下&#xff0c;然后直接添加 选定项目>>>右键>>>Bulid Path>>>Add Libraries>>>Configure Build Path(配置构建路…

python—爬虫爬取电影页面实例

下面是一个简单的爬虫实例&#xff0c;使用Python的requests库来发送HTTP请求&#xff0c;并使用lxml库来解析HTML页面内容。这个爬虫的目标是抓取一个电影网站&#xff0c;并提取每部电影的主义部分。 首先&#xff0c;确保你已经安装了requests和lxml库。如果没有安装&#x…

Fast Planner规划算法(一)—— Fast Planner前端

本系列文章用于回顾学习记录Fast-Planner规划算法的相关内容&#xff0c;【本系列博客写于2023年9月&#xff0c;共包含四篇文章&#xff0c;现在进行补发第一篇&#xff0c;其余几篇文章将在近期补发】 一、Fast Planner前端 Fast Planner的轨迹规划部分一共分为三个模块&…