【Redis】面试题汇总

news2024/9/29 11:27:04

  • Redis
    • 什么是Redis、使用场景有哪些
    • Redis 为什么这么快?
    • Redis 数据类型及使用场景
    • 五种常见的 Redis 数据类型是怎么实现?
    • Redis是单线程吗
    • Redis 采用单线程为什么还这么快?
    • Redis 如何实现数据不丢失?
    • Redis 如何实现服务高可用?
    • 集群脑裂导致数据丢失怎么办?
    • Redis 使用的过期删除策略是什么?
    • Redis 持久化时,对过期键会如何处理的?
    • Redis 主从模式中,对过期键会如何处理?
    • Redis 内存满了,会发生什么?
    • 什么是Redis 内存淘汰策略
    • Redis 内存淘汰策略有几种
    • LRU 算法和 LFU 算法有什么区别?
    • 如何避免缓存穿透、缓存击穿、缓存雪崩?
    • 如何设计一个缓存策略,可以动态缓存热点数据呢?
    • 常见的缓存更新策略?
    • 如何保证缓存和数据库数据的一致性?
    • Redis 如何实现延迟队列?
    • Big Key问题
    • 大量数据要导入Redis该怎么办
    • Redis 事务支持回滚吗?

Redis

什么是Redis、使用场景有哪些

答:

  • Redis: Redis是一种基于内存的数据存储,因为它基于内存所以读写速度非常快。而且Redis的命令执行是单线程的,不会存在并发安全问题。

  • Redis可以用来数据缓存分布式锁消息队列等场景。

Redis 为什么这么快?

答:

  1. Redis 基于内存,内存的访问速度比磁盘快很多;
  2. Redis 是单线程事件循环IO 多路复用
  3. Redis 内置了多种优化过后的数据类型,性能非常高。
  4. Redis 通信协议实现简单且解析高效。

Redis 数据类型及使用场景

答:

  • 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
  • 4 种特殊数据类型:HyperLogLog(基数统计)、Bitmap (位图)、GEO (地理位置)、Stream。

  • String 类型的应用场景:缓存对象常规计数分布式锁共享 session 信息等。
  • List 类型的应用场景:消息队列(但是有两个问题:1. 无法避免消息丢失;2. 一条消息无法被多个消费者一起消费)等。
  • Hash 类型:缓存对象(用于对象属性需要经常进行修改的)、购物车等。
  • Set 类型:聚合计算(并集、交集、差集)场景,比如点赞(例如一个用户只能点一次赞)、共同关注、抽奖活动等。
  • Zset 类型:排序场景,比如排行榜、电话和姓名排序等。

Redis 后续版本又支持四种数据类型,它们的应用场景如下:

  • BitMap(2.2 版新增):二值状态统计的场景,比如签到、判断用户登陆状态、连续签到用户总数等;
  • HyperLogLog(2.8 版新增):海量数据基数统计的场景,比如百万级网页 UV 计数(一天内用户的多次访问只算一次)等;
  • GEO(3.2 版新增):存储地理位置信息的场景,比如滴滴叫车;
  • Stream(5.0 版新增):消息队列,相比于基于 List 类型实现的消息队列,有这两个特有的特性:自动生成全局唯一消息ID,支持以消费组形式消费数据。

五种常见的 Redis 数据类型是怎么实现?

答:

在这里插入图片描述

1、String 类型内部实现

  • Redis的字符串用的并不是原生C语言的字符串,用的是一个结构体SDS(简单动态字符串),
  • SDS相比于原生C语言的字符串,1. 他是二进制安全的(C语言的字符串底层是一个字符数组,并且使用了一个结束标识符)2. SDS的结构体维护了一个当前字符串的长度,相比于C语言,它的时间复杂度是O(1)。3. SDS实现了内存的扩充
  • String有3种编码方式:rawembstrint
  • raw:基于简单动态字符串(SDS)实现,存储上限为512mb。RedisObject使用一个指针指向的SDS
  • embstr:分配的头信息和SDS是一块连续的内存空间。根据SDS存储的字节大小会将raw转为embstr
  • int:如果字符串存储的是整数值,并且是在8个字节以内,则会采用int编码。会直接将值存放到ptr属性的位置。

2、Hash 类型内部实现

  • Hash结构默认采用ZipList编码。因为ZipList不是键值存储,所以使用相邻的两个entry分别保存field和value
  • 当数据量较大时,则会转为Dict编码。

3、List 类型内部实现

  • 3.2版本之前,Redis采用ZipListLinkedList来实现List,当元素数量少的时候采用ZipList编码,多的时候用LinkedList编码。
  • 3.2版本之后,Redis统一采用QuickList来实现List

4、Set 类型内部实现

  • 采用Dict编码,Dict中的key用来存储元素,value统一为null
  • 当存储的数据都是整数,并且元素数据较少时,采用的时IntSet编码(一块连续的内存空间)。

5、ZSet 类型内部实现

ZSet底层数据结构必须满足键值存储键必须唯一可排序这几个需求。

  • Dict + SkipList。Dict 保证键值存储、键必须唯一,SkipList保证可排序。缺点:Dict里面存储一份数据,SkipList中也需要存储一份数据。非常消耗内存。
  • 果存储的数据量比较少时,采用 zipList。为了保证ZSet的需求
    • 使用连续的两个entry来记录element和score。
    • 并按score值升序进行排列。

Redis是单线程吗

答:

  • Redis的命令处理是单线程执行的。
  • 在Redis 6.0 网络IO处理采用了多线程执行。
  • Redis在启动的时候,也会启动后台线程(BIO)的。这些后台线程会去执行一些比较耗时的操作。例如数据持久化等。

Redis 采用单线程为什么还这么快?

答:

  • Redis本身就是基于内存操作,执行速度非常快,它的性能瓶颈是网络延迟,而不是执行速度。
  • Redis 采用单线程模型可以避免多线程之间的竞争。多线程还要考虑线程安全问题,实现复杂度也会大大增多。

Redis 如何实现数据不丢失?

答:

  • 为了保证内存数据的不丢失,Redis实现了持久化机制。

有2种持久化的方式:

  • RDB持久化
  • AOF持久化

1、RDB持久化

RDB持久化是什么: 简单来说就是把内存中的所有数据都记录到磁盘RDB文件中。

什么时候执行RDB:在三种情况下RDB会被执行:

  • 执行save命令:主进程去执行RDB,其他命令会被阻塞。
  • 执行bgsave命令:开启一个子进程去执行RDB,主进程不会受影响。
  • Redis停机时:Redis停机时会执行一次save命令,实现RDB持久化。

RDB执行原理:

  1. bgsave 执行时,主进程会 fork 创建一个子进程。子进程和主进程共享同一块内存区域。
  2. 子进程负责将内存中的数据写入到RDB文件,主进程还可以继续进行工作。主要依靠的是 copy-on-write 技术。
    • 当主进程执行读操作时,与往常一样,直接访问内存中的数据即可。
    • 当主进程执行写操作时,会在内存中拷贝一份要修改的数据,对拷贝的数据执行写操作,这样不会影响到子进程读取的内存数据。

2、AOF持久化

AOF持久化是什么: 把Redis每一条写操作命令记录在AOF文件中。

什么时候执行AOF:有3种刷盘时机

  1. always:每执行一次写命令,立即记录到AOF文件
  2. everysec:每隔1秒写到AOF文件。
  3. no:写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘

RDB持久化缺点: RDB恢复数据快,但是最后一次快照之后的数据可能会丢失。

AOF持久化缺点: AOF数据安全性更好,但是恢复数据时需要执行每条命令,恢复速度慢。

在很多场景下,通常是结合使用RDB和AOF。

Redis 如何实现服务高可用?

答:

要想设计一个高可用的 Redis 服务,要从 Redis 的多服务节点来考虑,比如 Redis 的主从集群哨兵模式分片集群

1、主从集群

为什么需要主从集群:单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离

介绍主从集群:主节点负责写操作,从服务器负责读操作。主节点会把信息同步给从节点,保证数据的一致性。

有两种同步方式:

  • 全量同步:主从第一次同步是全量同步,主节点会将完整数据生成的RDB发给从节点。从节点加载RDB文件的数据。
  • 增量同步:从节点会提交自己的offset给主节点,主节点会把log文件中从offset之后的操作命令发给从节点。从节点执行命令进行同步。

2、哨兵模式

为什么需要哨兵模式:为了保证主从集群能够进行自动故障恢复。

哨兵监控原理:

  • 哨兵每隔1s向集群的每个实例发送ping命令
  • 如果有实例未在规定的时间响应,则认为该实例主观下线
  • 如果超过指定数量的哨兵都认为该实例主观下线了,则该实例客观下线

集群故障恢复原理

  • 主节点发生故障后,哨兵会从从节点中的选出一个作为主节点。
  • 挑选一个延迟最小优先级最高数据最完整的节点来晋升为新的主节点

3、分片集群

主从集群和哨兵模式解决了高并发读高可用的问题。

分片集群解决的是:海量数据存储高并发写的问题。

分片集群中有多个主节点,每个主节点保存不同的数据。主节点与主节点通过ping命令检测健康状态。

每个主节点都有自己的从节点。

集群脑裂导致数据丢失怎么办?

答:

  • 修改配置文件的配置,禁止主节点进行写数据,直接把错误返回给客户端。

Redis 使用的过期删除策略是什么?

答:

有两种过期删除策略:

  1. 惰性删除
    • TTL到期后不会立刻删除,而是在访问一个key的时候,先检查该key的存活时间,如果已经过期才执行删除。
    • 缺点:如果一个key过期了,只要这个key一直未被访问,则会一直存留在内存中。
  2. 周期删除
    • 每隔一段时间,随机的挑选部分过期的key,然后执行删除。
    • 缺点:过期键可能不会立即被删除,每次随机选择一部分的key检查。难以确定删除操作的频率。如果执行的太频繁,就会对 CPU 不友好;如果执行的太少,过期键不会立即被删除。

Redis 持久化时,对过期键会如何处理的?

答:

  • RDB持久化:在写入RDB文件之前,会先对key进行过期检查,过期的key不会被写入到RDB文件中。
  • AOF持久化:如果某个key还未过期,则记录此key。当某个key过期被删除了,则会在AOF文件的末尾添加一条删除命令。

Redis 主从模式中,对过期键会如何处理?

答:

  • Redis主从模式中,对过期键的处理主要由主节点负责,主节点删除过期键后,会发出删除命令通知从节点

Redis 内存满了,会发生什么?

答:

  • 在 Redis 的运行内存达到了某个阀值,就会触发内存淘汰机制,这个阀值就是我们设置的最大运行内存,此值在 Redis 的配置文件中可以找到,配置项为 maxmemory

什么是Redis 内存淘汰策略

答:

  • 内存淘汰策略:就是当Redis内存使用达到设置的阈值时,Redis主动挑选部分key删除以释放更多内存的流程。
  • Redis是在什么时候检查内存的:任何的命令执行之前,都要做内存检查。

Redis 内存淘汰策略有几种

答:

Redis支持8种不同策略来选择要删除的key:

  • noeviction:不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。
  • volatile-ttl::对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰

  • allkeys-random:对全体key,随机进行淘汰。也就是直接从db->dict中随机挑选
  • volatile-random:对设置了TTL的key,随机进行淘汰。也就是从db->expires中随机挑选。

  • allkeys-lru:对全体key,基于LRU算法进行淘汰
  • volatile-lru:对设置了TTL的key,基于LRU算法进行淘汰

  • allkeys-lfu:对全体key,基于LFU算法进行淘汰
  • volatile-lfu:对设置了TTL的key,基于LFU算法进行淘汰

LRU 算法和 LFU 算法有什么区别?

答:

  • LRU:最少最近使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
  • LFU:最少频率使用。会统计每个ky的访问频率,值越小淘汰优先级越高。

Redis如何实现的LRU和LFU:

在这里插入图片描述

LRU:在 Redis 的对象结构体中添加一个字段,用于记录此数据的最后一次访问时间。

LFU:同样也是使用LRU的字段进行记录,统计的并不是真实的访问次数,而是通过计算得到的逻辑访问次数

在这里插入图片描述

如何避免缓存穿透、缓存击穿、缓存雪崩?

答:

  • 缓存穿透:请求的数据缓存和数据库中都不存在
    • 缓存空值
    • 使用布隆过滤器
  • 缓存击穿:缓存中热点数据过期了,大量请求直接访问到了数据库。
    • 互斥锁:只让一个业务线程重建缓存。其他线程等待锁的释放,然后重新查询缓存,要么直接返回空值。
  • 缓存雪崩:大量缓存数据在同一时间失效,大量请求直接访问到了数据库。
    • 不同key的失效时间添加随机值
    • 不设置缓存的过期时间

如何设计一个缓存策略,可以动态缓存热点数据呢?

答:

热点数据动态缓存的策略总体思路:通过数据最新访问时间来做排名,并过滤掉不常访问的数据,只留下经常访问的数据。

比如需要缓存用户经常访问的Top 1000商品。

  1. 设置一个Zset集合,容量大小为1000,score为当前商品访问的时间,element为商品id。
  2. 用户查询一个商品的信息时,首先查询缓存中Zset集合是否存在,第一次是不存在。如果存在,则再根据id去另一个缓存结构中查询信息。
  3. 查询数据库获取信息。之后判断缓存中Zset集合大小是否达到1000,如果没有达到,则将该商品id和访问时间设置到Zset集合中。并将商品的信息缓存到另一个缓存结构中。如果达到了1000,则删除Zset中排名第一个的元素(Zset中访问时间按升序排序),然后将该商品信息放入Zset中。

常见的缓存更新策略?

答:

  • 写操作
    • 先更新数据库、删除缓存
  • 读操作
    • 先查询缓存,缓存命中直接返回
    • 缓存未命中,查询数据库,写入缓存

如何保证缓存和数据库数据的一致性?

答:

  • 写操作时
    • 先更新数据库、删除缓存。(但再并发情况下,有可能出现数据不一致)

在这里插入图片描述

改进

  1. 方案一(防止被其他重写):延时双删。先更新数据库,然后删除缓存,稍后再删除一次缓存。
  2. 方案二(防止删除时失败):重试机制。可以把要删除缓存的数据放到消息队列,如果删除成功则从消息队列移除。否则重试。

Redis 如何实现延迟队列?

答:

  • 可以使用Zset集合实现。score为当前时间+要延迟的时间
  • 通过 zadd 向集合中添加消息
  • 再利用 zrangebysocre key min max 命令(min:0,max:当前时间),循环查询符合相应时间的消息,然后进行业务处理。

Big Key问题

答:

什么是Big Key

  • Bigkey通常指的是某个Key所占的内存较大、或者是某个Key中成员数量较多。这样的Key叫做BigKey
  • 推荐值:单个Key的value小于10KB,对于集合类型的key,建议元素数量小于1000

Big Key的危害

  1. 客户端阻塞: Redis执行命令是单线程处理的,如果操作一个BigKey比较耗时,则会阻塞客户端。
  2. 工作线程阻塞: 对元素较多的hash、list、Zset做运算运算时,会使工作线程被阻塞。
  3. CPU压力: 对BigKey的数据序列化和反序列化会导致CPU的使用率飙升。

如何发现Big Key

  1. 使用 redis-cli --bigkeys 命令查找Bigkey。缺点:该命令只能返回每种类型中最大的那个 bigkey,对于集合类型,它返回的是个数最多的,而不是占用内存最多的。
  2. 利用scan命令可以自己编写程序扫描,scan每次都是扫描的一部分(相对于扫描全部的key,对线程还友好一点),并且返回下一次的游标位置。

如何删除Big Key

  • Redis 4.0以上,可以使用异步线程删除: unlink 命令
  • Redis 4.0之前,对于集合类型,可以分批次的删除集合元素,并且Redis也提供了集合扫描的命令:hscanzscan,分批次的删除扫描到的元素。

大量数据要导入Redis该怎么办

答:

大量数据导入时的主要耗时是在:网络传输耗时

命令批处理方案:

  1. 原生的M操作。例如:msethmset 实现批量插入
    • M操作是原子操作。中间不会穿插其他的操作。
    • MSET虽然可以批处理,但是却只能操作部分数据类型(String、hash)
  2. Pipeline命令。Pipeline可以执行各种的数据类型的命令,因此如果有对复杂数据类型的批处理需要,建议使用Pipeline功能。
    • Pipeline的多个命令之间不具备原子性

Redis 事务支持回滚吗?

答:

  • Redis 的事务可以确保一系列命令的原子性执行,但它并不支持事务回滚。也就是某个命令在执行过程中出错,那么后面的命令仍然会被继续执行。
  • MULTI 开启事务,EXEC 执行事务, DISCARD 取消事务(没有回滚作用)

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

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

相关文章

为什么中级职称评审不通过?有什么原因?

参与过职称评审或者有了解过职称评审的小伙伴们,应该都知道,职称评审都是有通过率,不是你去评,一定会评下来,一定会发证的,那么评审为什么不通过?有哪些原因呢? 现在职称评审人越来越…

vue框架中的组件通信

vue框架中的组件通信 一.组件通信关系二.父子通信1.props 校验2.prop & data、单向数据流 二.非父子通信-event bus 事件总线三.非父子通信 (拓展) - provide & inject四.v-model简化父子通信代码五. .sync修饰符 一.组件通信关系 组件关系分类: 1.父子关系…

细水雾发生器你的相信我的诚信

做销售就是两个信:你的相信!我的诚信!成交就两颗心:你的放心!我的用心!你给我一次合作的机会,我给你十分满意的产品。一次合作,终身朋友~ 产品的结构: 细水雾…

快速了解什么是MES系统

近年来在制造业的推动下,大家是否会经常听到MES系统这一词,但是对于其具体能解决什么问题却不是很清晰。接下来,让大家快速地了解一下到底什么是MES系统以及MES系统能够解决什么问题。 什么是MES制造执行系统 制造执行系统(Manufa…

TBWeb开发版V3.2.6免授权无后门Chatgpt系统源码下载及详细安装教程

TBWeb系统是基于 NineAI 二开的可商业化 TB Web 应用(免授权,无后门,非盗版,已整合前后端,支持快速部署)。相比稳定版,开发版进度更快一些。前端改进:对话页UI重构,参考C…

Excel超级处理器,批量创建工作表,这也太方便了吧

在工作中,经常要创建或复制多个工作表,按照日期或指定的工作表名,为了能够更加方便快捷,那么下面介绍使用超级处理的应用。 超级处理器下载与安装 1、按照本月日期创建新工作表 2、按照本月日期复制工作表 3、按照单元格内容创建…

外显子测序wes

外显子是基因组中能够转录组出成熟RNA的部分。一个基因组中所有外显子的集合,即为外显子组。值得注意的是,通常所说的全外显子组测序,是指针对蛋白编码基因的外显子,很少涉及非编码基因。 基因(gene)是DNA中含有特定遗传信息的一…

AI智能电销机器人的营销策略是什么?

近年来,伴随着制造业新一轮的数字化智能化转型浪潮。各大企业开始使用电销机器人,解决了传统电销工作过程中的许多问题,更显著的是:电话机器人在替代人工工作基础上,节约人工成本70%以上,极大程度地高额完成…

从本地创建项目到 Gitee 提交的完整教程

1、本地创建一个新项目 2.进入想上传的项目的文件夹,然后右键点击git bash 3.初始化本地环境,把该项目变成可被git管理的仓库 4.添加该项目下的所有文件到暂存区 5.使用如下命令将文件添加到仓库中去 6.在gitee上创建以自己项目名称命名的空项目 7.将本地…

Windows上使用VSCode连接远程服务器(附图文过程)

1、下载VSCode 官网下载地址,选择需要的进行下载 2、安装SSH插件 安装完成之后,启动vscode,选择左侧Extensions 选项卡,在输入框搜索 remote ,选择安装Remote-SSH插件(我使用了汉化,如果要用…

ubuntu18.04与windows文件互传

目录 window下载Xftp软件ubuntu上的配置windows端Xftp软件的使用 window下载Xftp软件 下载:家庭/学校免费版 安装教程推荐下面的文章 xftp7免费版安装教程(详细) ubuntu上的配置 在进入系统后,确保有网络连接的情况下按Ctrl A…

制作适用于openstack平台的win10镜像

1. 安装准备 从MSDN下载windows 10的镜像虚拟机开启CPU虚拟化的功能。从Fedora 网站下载已签名的 VirtIO 驱动程序 ISO 。 创建15 GB 的 qcow2 镜像:qemu-img create -f qcow2 win10.qcow2 15G 安装必要的软件 yum install qemu-kvm qemu-img virt-manager libvir…

28map,set关联式容器

序列式容器 vector、list、deque(单纯的纯数据) 关联式容器 map、set,哈希,,,(数据之间有很强的关联性,不是单纯的为了存储数据) Set 底层是搜索树(红黑树) T是key ,compare是仿函数&#xff0…

书生·浦语大模型-第四节课笔记/作业

笔记 作业 xtuner train ./config/internlm2_chat_7b_qlora_alpaca_e3_copy.py --work-dir ./train微调前效果 微调后效果 微调过程-transformer-lora

Django中的定时任务与后台任务队列的实践

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在Web开发中,处理定时任务和后台任务队列是很常见的需求。Django作为一个功能强…

032——从GUI->Client->Server->driver实现ds18b20数据的采集

目录 1、客户端修改和通信帧确定 2、 修改服务器程序 3、 添加driver_handle程序 4、 测试 1、客户端修改和通信帧确定 上次写dht11的时候顺手把ds18b20的GUI一起改了所以这次直接去改client #ds18b20elif cmd[2] 0 and cmd[3] 6:if cmd[4] g:try:global_var.TEMcmd[5]…

在 Linux 上通过 udev 规则绑定 ttyUSB 设备的相对地址

文章目录 问题描述解决方案1. 分辨当前 USB 设备的绝对地址2. 使用绝对地址查看设备属性3. 使用 udev 规则绑定设备到相对地址3.1. 区分多个不同型号 USB 设备3.2. 区分多个相同型号 USB 设备 问题描述 Linux 系统开机时会随机为连接的 USB 设备随机分配 /dev/ttyUSB* 这样的绝…

ubuntu20 解决网线不能联网 RTL8111/8168/8411

这种问题一般是驱动没有正确安装。 ----RTL8111/8168/8411是一块比较坑的网卡。 1、 查看网卡信息 lspci |grep Ethernet2、 对于高版本的Ubuntu,能直接使用命令安装驱动。下面的r8168-dkms需根据网卡信息修改,上面的网卡信息还有8111,但逐个…

CSS画一条虚线,并且灵活设置虚线的宽度和虚线之间的间隔和虚线的颜色

CSS画一条虚线,并且灵活设置虚线的宽度和虚线之间的间隔和虚线的颜色。 先看效果图: 在CSS中,你可以使用border属性或者background属性来画一条虚线。以下是两种常见的方法: 方法一:使用border属性 你可以设置一个元素的border…

C#版Facefusion:让你的脸与世界融为一体!-05 人脸增强

C#版Facefusion:让你的脸与世界融为一体!-05 人脸增强 目录 说明 效果 模型信息 项目 代码 下载 说明 C#版Facefusion一共有如下5个步骤: 1、使用yoloface_8n.onnx进行人脸检测 2、使用2dfan4.onnx获取人脸关键点 3、使用arcface_w60…