Redis面试问题(牛客整理版)未完成

news2024/11/15 23:26:37

文章目录

参考资料

codehot.cn
javaguide
《Redis设计与实现》
Redis中文文档:https://www.redisio.com/Getting-started.html

出处

以下问题出自牛客
作者:setsna
链接:https://www.nowcoder.com/discuss/603841169302245376?sourceSSR=users
来源:牛客网

1,介绍一下redis在工作中的用途

2,redis在工作中一般可以承受多少的qps?

3,redis有哪些数据结构,分别常用与哪些场合?

4,redis跳表实现细节,为什么选用跳表,而不选择红黑树和B+树?

5,redis中使用Lua脚本为什么能保证事务性?

6,在分布式锁实现时,Setnx一定是可靠的吗,为什么(主从不一致)?

7,如果需要保证可靠,需要怎样的机制保证(Raft算法)?

8,redis为什么要防止bigkey?

9,redis是内存相关的数据库,那么有1G的数据,想要以key-value的方式存储,那么是每个key的数据多一些更占内存,还是少一些更占内存,根据所学的redis底层数据结构实现进行分析和回答

10,redis的网络IO模型介绍

11,epoll和select模型的区别

12,redis中TTL到期后是如何回收的?

13,在使用分布式锁时,如何保证解锁时是之前上过的锁?

14,使用redis实现分布式缓存时,需要注意哪些问题?

15,说下缓存击穿,缓存穿透,缓存雪崩有什么区别?

缓存过期时间

缓存过期删除

img

实际使用惰性删除+定期删除的形式

懒惰删除是指 Redis 会在查询 key 的时候检测这个 key 是否已经过期,如果已经过期,那么 Redis 就会顺手删除这个 key。

单纯使用懒惰删除肯定是不行的,因为一个 key 过期之后,可能一直没有被使用过。所以 Redis 结合了定期删除策略。Redis 每运行一段时间,就会随机挑选出一部分 key,查看是否过期,如果已经过期了,就把 key 删除掉。

定期删除

img

在每一个定期删除循环中,Redis 会遍历 DB。如果这个 DB 完全没有设置了过期时间的 key,那就直接跳过。否则就针对这个 DB 抽一批 key,如果 key 已经过期,就直接删除。

如果在这一批 key 里面,过期的比例太低,那么就会中断循环,遍历下一个 DB。如果执行时间超过了阈值,也会中断。不过这个中断是整个中断,下一次定期删除的时候会从当前 DB 的下一个继续遍历。

随机只是为了保证每个 key 都有一定概率被抽查到。假设说我们在每个 DB 内部都是从头遍历的话,那么如果每次遍历到中间,就没时间了,那么 DB 后面的 key 你可能永远也遍历不到。

img

定期删除的频率

假如说 hz 的值是 N,那么就意味着每 1/N 秒就会执行一次后台任务。举例来说,如果 hz=10,那么就意味着每 100ms 执行一次后台任务。

在 Redis 里面有一个参数叫做 hz,它代表的是 Redis 后台任务运行的频率。正常来说,这个值不需要调,即便调整也不要超过 100。与之相关的是 dynamic-hz 参数。这个参数开启之后,Redis 就会在 hz 的基础上动态计算一个值,用来控制后台任务的执行频率。

img

从库处理过期 key

在 Redis 的 3.2 版本之前,如果读从库的话,是有可能读取到已经过期的 key。后来在 3.2 版本之后这个 Bug 就被修复了。不过从库上的懒惰删除特性和主库不一样。

img

持久化

RDB 简单来说就是快照文件,也就是当 Redis 执行 SAVE 或者 BGSAVE 命令的时候,就会把内存里的所有数据都写入 RDB 文件里

AOF 是之前我们就提到过的 Append Only File。Redis 用这个文件来逐条记录执行的修改数据的命令

过期时间如何确定

  • 可以从业务场景出发。比如说,当某个数据被查询出来以后,用户大概率在接下来的三十分钟内再次使用这个对象,那么就可以把过期时间设置成 30 分钟。

  • 是根据缓存容量和缓存命中率确定过期时间的。正常来说,越高缓存命中率,需要越多的缓存容量,越长的过期时间。所以最佳的做法还是通过模拟线上流量来做测试,不断延长过期时间,直到满足命中率的要求。

    命中率的计算:

    如果公司要求平均响应时间是 300ms,命中缓存响应时间是 100ms,没命中缓存的响应时间是 1000ms,假设命中率是 p,那么 p 要满足 100×p+1000×(1−p)=300。

缓存淘汰策略

万一我达到了内存使用上限,但是我又需要加入新的键值对,怎么办?

可以认为已经在缓存中的数据可能用不上了,虽然还没有过期,但是还是可以考虑淘汰掉,腾出空间来存放新的数据。这些新的数据比老的数据有更大的可能性被使用。

LRU

LRU(Least Recently Used)是指最近最少使用算法

缓存容量不足的时候,就从所有的 key 里面挑出一个最近一段时间最长时间未使用的 key。

这个算法从实现上来说很简单,只需要把 key 用额外的链表连起来,每次访问过的挪到队首,那么队尾就是最近最久未访问过的 key。

LFU

LFU(Least Frequently Used)是最不经常使用算法

按照访问频率来给所有的对象排序。每次要淘汰的时候,就从使用次数最少的对象里面找出一个淘汰掉。

缓存模式

img

我觉得上面的模式,只有Cache Aside和延迟双删比较常用。

Cache Aside

旁路缓存,写和读由业务方来控制。

img

img

数据都是以数据库为准的,也就是说如果写入数据库成功了,就可以认为这个操作成功了。即便写入缓存失败,但是缓存本身会有过期时间,那么它过期之后重新加载,数据就会恢复一致。

不管是先写数据库还是先写缓存,Cache Aside 都不能解决数据一致性问题,在两个线程同时更新数据时会有数据不一致问题

img

删除缓存

写数据时,写数据库,删除缓存,会有读写不一致问题,发生在一个线程更新数据,一个线程缓存未命中回查数据库时。

img

延迟双删

写数据的时候先写数据库,然后第一次删除缓存,定一个定时器,在一段时间之后再次执行删除。

img

第二次删除就是为了避开删除缓存中的读写导致数据不一致的场景。

img

有小概率出现出现以下不一致情况,但是因为两次删除的时间间隔很长,不至于出现图片里的这种情况。延迟双删的缺点是由于存在两次删除,所以实际上缓存命中率下降的问题更加严重。

总结:这么多模式里面,我比较喜欢延迟双删,因为它的一致性问题不是很严重。虽然会降低缓存的命中率,但是我们的业务并发也没有特别高,写请求是很少的。命中率降低一点点是完全可以接受的。

img

缓存一致性问题

解决缓存穿透、击穿和雪崩问题

缓存穿透

缓存穿透是指数据既不在缓存中,也不在数据库中,导致查询落到数据库上。最常见的场景就是有攻击者伪造了大量的请求,请求某个不存在的数据。如果你没有在服务层面上采用熔断、限流之类的措施,那么数据库就可能崩溃。

回写特殊值

第一种思路是在缓存未命中,而且数据库里也没有的情况下,往缓存里写入一个特殊的值。

这个值就是标记数据不存在,那么下一次查询请求过来的时候,看到这个特殊值,就知道没有必要再去数据库里查询了。

如果攻击者每次都用不同的且都不存在的 key 来请求数据,那么这种措施毫无效果。并且,因为要回写特殊值,那么这些不存在的 key 都会有特殊值,浪费了 Redis 的内存。这可能会进一步引起另外一个问题,就是 Redis 在内存不足,执行淘汰的时候,把其他有用的数据淘汰掉。

布隆过滤器

看一下key是否存在,原理后面补todo

缓存击穿

数据不在缓存中,导致请求落到了数据库上。比如说同一时刻有几百个人请求某个大博主的数据,这些请求都没有命中缓存,那么几百个查询请求都会落到数据库上。

因此,如果请求的数据并不是什么热点数据,那么击穿也没有什么问题,它就是普通的缓存未命中而已。

Singleflight

Singleflight 模式是指当缓存未命中的时候,访问同一个 key 的线程或者协程中只有一个会去真的加载数据,其他都在原地等待。

这个模式最大的优点就是可以减轻访问数据库的并发量。比如说如果同一时刻有 100 个线程要访问 key1,那么最终也只会有 1 个线程去数据库中加载数据。这个模式的缺点是如果并发量不高,那么基本没有效果。所以热点之类的数据就很适合用这个模式。

img

也就是说,就算是一个热点数据,当几百个请求缓存未命中的时候,在 singleflight 模式之下,也只有一个请求会真的去查询数据,剩下的都在等着这个请求查询回来的结果。

缓存雪崩

缓存雪崩是指缓存里大量数据在同一时刻过期,导致请求都落到了数据库上。

缓存雪崩基本上都是因为一次性加载了很多数据到缓存中,并且都设置为同一个过期时间。比如说在应用启动的时候,提前从数据库里查询数据,然后放到缓存里面,这样这一批数据就会在同一时刻过期。又比如榜单数据计算好了之后加载到缓存里,都是同一个过期时间,导致这一批榜单数据同一时间过期。

过期时间增加随机偏移量

最简单的思路,就是在过期时间的基础上加一个偏移量。

限流

缓存穿透和击穿只有在高并发下才会成为一个问题,所以一个很自然的想法就是使用限流。限流可以考虑在两个地方使用:服务层面和数据库层面。

异地多活

不管是缓存穿透、击穿还是雪崩,归根结底就是请求都落到了数据库上。除了这三个异常,Redis 本身也有可能崩溃,又或者因为网络问题连不上这个集群。

img

很多大厂会用一些异地多活的方案,就是使用两个 Redis 集群,然后两个集群之间要保持数据同步。那么其中一个 Redis 集群崩溃的时候,就可以用另外一个 Redis 集群。

Redis单线程

todo

分布式锁

用缓存来提升应用性能

一致性哈希 + 本地缓存 + Redis 缓存

我之前维护了一个强调高可用和高性能的服务。这个服务最开始使用的缓存方案是比较典型的,就是访问 Redis,然后访问数据库。后来有一次我们这边网络出了问题,连不上 Redis,导致压力瞬间都到了数据库上,数据库崩溃。

我后面做了两个事情,防止再一次出现类似的问题。第一个事情就是在数据库查询上加上了限流。另外一个事情就是引入了本地缓存。但是本地缓存一开始是没有启用的。我会实时监控 Redis 的状态,一旦发现 Redis 已经崩溃,就会启用本地缓存。启用本地缓存之后,好处是保住了数据库,并且响应时间还是很好。缺点就是本地缓存会面临更加严重的数据一致性问题。

img

在启用了本地缓存之后,还要监控 Redis 的状态。当 Redis 恢复过来,就可以逐步将本地缓存上的流量转发到 Redis 上。之所以不是立刻全部转发过去,是因为刚恢复的时候 Redis 上面可能什么数据都没有,导致缓存未命中,回查数据库。这可能会引起数据库的问题。

请求级别缓存

我来给你解释一下这种缓存的基本原理。使用这种缓存方案的前提是,你在一个请求里面会反复查询同一个请求数据多次。比如说,因为模块划分之后要恪守边界,所以每个模块都会自己去调用接口来获得同一份数据。

那么你就可以考虑将数据和请求关联在一起,做成一个在请求生命周期内有效的缓存。

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

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

相关文章

k3s中通过kuboard搭建rabbitmq

如果仅仅是单个rabbitmq容器在单台服务上运行,并不是搭建rabbitmq集群,则不需要使用到service。仅仅通过容器暴露端口到宿主机的形式。 1、拉取 RabbitMQ 镜像 我这边选择的版本是 rabbitmq:3.12-management在终端中执行以下命令以拉取 rabbitmq:3.12-m…

两道关于xssDOM型的案例

第一道 代码分析:data是要插入到html页面的标签及属性,下面的for循环的作用则是将你插入的标签里的属性给全部删除。 图中,把我img的src属性给删掉了。 但当我多写几个属性时,奇怪的事情发生了。 他只把我得src给删掉了&#xff…

SQL基础教程(八)SQL高级处理

※食用指南:文章内容为《SQL基础教程》系列学习笔记,该书对新手入门非常友好,循序渐进,浅显易懂,本人主要用来补全学习MySQL中未涉及的部分,便于刷题和做项目。 官方电子书:《SQL基础教程》第2…

掌握TCP连接管理与流量控制:从零开始

文章目录 1. TCP连接管理1.1 三次握手(Three-way Handshake)1.2 四次挥手(Four-way Handshake)1.3 TCP连接管理的重要性 2. TCP流量控制2.1 滑动窗口(Sliding Window)2.2 拥塞控制(Congestion C…

【ARM+Codesys 客户案例 】基于RK3568/A40i/STM32+CODESYS开发的控制器在自动输送分拣系统上的应用,支持定制

2021年“京东618” 累计下单金额超3438亿元,再次刷新纪录! 从下单到收货,各种货品均可在短短几天内通过四通八达的物流网络送达全国任何一个家庭。电子商务和快递物流的迅猛发展对仓储、分拣、配送效率和准确性均提出了更高的要求,加速了智能物流的发展。…

Java Resilience4j-RateLimiter学习

一. 介绍 Resilience4j-RateLimiter 是 Resilience4j 中的一个限流模块&#xff0c;我们对 Resilience4j 的 CircuitBreaker、Retry 已经有了一定的了解&#xff0c;现在来学习 RateLimiter 限流器&#xff1b; 引入依赖&#xff1b; <dependency><groupId>io.g…

序列建模之循环和递归网络 - 递归神经网络篇

序言 在序列建模的广阔领域中&#xff0c;递归神经网络&#xff08; Recursive Neural Network, RNN \text{Recursive Neural Network, RNN} Recursive Neural Network, RNN&#xff09;&#xff0c;注意此处的 RNN \text{RNN} RNN与常用于序列处理的循环神经网络在命名上有所…

【生成式人工智能-十五-经典的影像生成方法-GAN】

经典的影像生成方法-GAN GANDiscriminatorGenerator还需要加入额外信息么 GAN可以加在其他模型上面我们可以用影像生成模型做什么&#xff1f; 前面讲过VAE和Flow-based以及diffusion Model &#xff0c;今天讲最后一种经典的生成方法GAN。 GAN 前面讲的几种模型都是用加入额外…

红黑树剖析(插入部分)

文章目录 红黑树插入节点情景分析情景1&#xff1a;红黑树为空树情景2&#xff1a;插入节点的Key已存在情景3&#xff1a;插入节点的父节点为黑色节点情景4&#xff1a;插入节点的父节点为红色情景4.1 叔叔节点存在并且为红色节点情景4.2 叔叔节点存在而且是黑色节点情景4.3 叔…

xss 一些例子

目录 XSS 1.Ma Spaghet!​编辑 2.Jefff​编辑 3.Ugandan Knuckles​编辑 4.Ricardo Milos​编辑 5.Ah Thats Hawt​编辑 6.Ligma​编辑 7.Mafia​编辑 简单解法就是换一个函数 作者得原意解法 8.Ok, Boomer​编辑 XSS 1.Ma Spaghet! 这里接收了一个somebody参数&…

Chain of Thought (CoT) 系列论文:大模型思维链,提升 LLM 的推理能力

文章目录 1. COT&#xff1a;Chain of Thought1. 研究背景2. CoT的原理3. CoT Prompt 1. COT&#xff1a;Chain of Thought COT 是 2022.01 由 google 提出的针对提升 LLM 的推理能力的 Prompt Engineering 方法。 paper&#xff1a; Chain-of-Thought Prompting Elicits Re…

一器多能,数据文件处理的瑞士军刀 — dasel

Dasel&#xff1a;简化数据操作&#xff0c;提升开发效率。- 精选真开源&#xff0c;释放新价值。 概览 dasel是一款专为开发者设计的高效数据文件操作工具&#xff0c;它允许用户通过统一的接口对JSON、TOML、YAML、XML和CSV等格式的文件进行数据选择、插入和删除操作。这款工…

Kafka基本概念及消费流程

Kafka是消息中间件的一种&#xff0c;相较于其他消息中间件&#xff0c;其以极高的吞吐量闻名&#xff0c;常用于构建实时数据管道和流应用&#xff0c;能够处理高吞吐量的数据流。以下是Kafka中的重要概念&#xff1a; 1. 生产者 生产者是向Kafka主题发送消息的客户端。生产…

登录 k8s-Dashboard 显示 Your connection is not private

文章目录 一、背景二、解决方案 一、背景 部署好 kubernetes-Dashboard 后使用 master节点的 ipport 登录 Dashboard 显示 Your connection is not private 无论是 Edge 还是 Google Chrome 都是这样的情况 二、解决方案 点击网页空白处&#xff0c;英文输入法输入&#xf…

论文解读:LONGWRITER: UNLEASHING 10,000+ WORD GENERATION FROM LONG CONTEXT LLMS

摘要 现象&#xff1a;当前的大预言模型可以接受超过100,000个tokens的输入&#xff0c;但是却难以生成超过2000个token的输出。 原因&#xff1a;监督微调过程(SFT)中看到的样本没有足够长的样本。 解决方法&#xff1a; Agent Write&#xff0c;可以将长任务分解为子任务&a…

为什么MCU I2C波形中会出现的脉冲毛刺?

在I2C的波形中&#xff0c;经常会发现有这样的脉冲毛刺&#xff0c;会被认为是干扰或者器件不正常。 看到这个波形时&#xff0c;可以先数一下出现在第几个clock的位置&#xff0c;如果出现在第9个clock的低电平期间&#xff0c;就不是干扰或者器件异常导致。 在I2C的协议中&a…

Java并发类的主要API方法-CountDownLatch和CyclicBarrier

1.概念介绍 CountDownLatch 是一个计数器&#xff0c;计数器的初始值由创建它时指定。每次调用 countDown() 方法时&#xff0c;计数器会减1&#xff0c;直到计数器值变为0时&#xff0c;所有调用 await() 的线程都会被唤醒继续执行。 CyclicBarrier 是 Java 中另一个常用的同…

基于CDIO概念的人工智能物联网系统开发与实施的人才培养研究

目录 1. 引言&#xff08;Introduction&#xff09; 2. AIoT技术及其培训特点&#xff08;The Characteristics of AIOT and Its Training&#xff09; 3. 基于CDIO概念的AIoT课程改革&#xff08;CDIO Concept-based Reform of AIOT Course&#xff09; 4. AIoT课程内容安…

SweetAlert2

1. SweetAlert2 SweetAlert2是一个基于JavaScript的库, 用于在网页上替换标准的警告框(alert), 确认框(confirm)和提示框(prompt), 并提供更加美观和用户友好的界面.需要在项目中引入SweetAlert2, 可以通过CDN链接或者将库文件下载到你的项目中来实现这一点. 通过CDN引入:<…

C++:stack类(vector和list优缺点、deque)

目录 前言 数据结构 deque vector和list的优缺点 push pop top size empty 完整代码 前言 stack类就是数据结构中的栈 C数据结构&#xff1a;栈-CSDN博客 stack类所拥有的函数相比与string、vector和list类都少很多&#xff0c;这是因为栈这个数据结构是后进先出的…