当前位置: 首页 > news >正文

Redis八股

Redis 相关基础概念(面试问)

什么是redis

基于内存的数据库,读写速度快,常用于缓存,分布式锁等场景

Redis(Remote Dictionary Server)的本质是一种非关系型的键值数据库,更具体地说,它是一种数据结构服务器。与传统的键值存储不同,Redis不仅限于存储简单的键值对,还提供了丰富多样的数据结构和功能,使其成为一个非常灵活且功能全面的存储解决方案。
在这里插入图片描述

为什么用 Redis 作为 MySQL 的缓存?

简答:主要是因为 Redis 具备「高性能」和「高并发」两种特性
高性能(能提升性能,基于内存,直接在内存中操作
假如用户第一次访问 MySQL 中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据缓存在 Redis 中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了,操作 Redis 缓存就是直接操作内存,所以速度相当快(redis基于内存,读写速度快)
高并发(内存操作的低延迟,减少对数据库的直接访问,提高并发
单台设备的 Redis 的 QPS(Query Per Second,每秒钟处理完请求的次数) 是 MySQL 的 10 倍,Redis 单机的 QPS 能轻松破 10w,而 MySQL 单机的 QPS 很难破 1w。
所以,直接访问 Redis 能够承受的请求是远远大于直接访问 MySQL 的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

Redis 和 Memcached 有什么区别?

(redis支持的数据类型更丰富,支持持久化【保证重启时,数据不丢失–AOF/RDB/混合】,可扩展性和高可用(支持主从复制和集群部署
在这里插入图片描述

Redis 数据类型(抽象数据模型,数据结构是实现数据类型的具体方式

在这里插入图片描述

各自应用场景

在这里插入图片描述

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

在这里插入图片描述

String

String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value其实不仅是字符串, 也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M
字符串对象的内部编码(encoding)有 3 种 :int、raw和 embstr
String 类型的底层的数据结构实现主要是 int 和 SDS(简单动态字符串)
在这里插入图片描述

Hash,List,Set,Zset
BitMap,HyperLogLog,GEO,Stream

Redis 数据结构(面试常问)

在这里插入图片描述
*加粗样式

Redis 是怎样实现键值对(key-value)数据库

在这里插入图片描述

SDS

Redis 是用 C 语言实现的,但是它没有直接使用 C 语言的 char* 字符数组来实现字符串,而是自己封装了一个名为简单动态字符串(simple dynamic string,SDS) 的数据结构来表示字符串,也就是 Redis 的 String 数据类型的底层数据结构是 SDS。
为什么不用char*—有缺陷

  • 获取字符串长度的时间复杂度为 O(N); ----SDS改进为O(1)(SDS 结构因为加入了 len 成员变量
  • 字符串的结尾是以 “\0” 字符标识,字符串里面不能包含有 “\0”字符,因此不能保存二进制数据;
  • 字符串操作函数不高效且不安全,比如有缓冲区溢出的风险,有可能会造成程序运行终止;(SDS通过alloc改善
  • 在这里插入图片描述

链表

在这里插入图片描述### 压缩列表
在这里插入图片描述

在这里插入图片描述

Redis 是单线程吗?

Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的

但是,Redis 程序并不是单线程的,Redis 在启动的时候,是**会启动后台线程(BIO)**的

为「关闭文件、AOF 刷盘、释放内存」这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么 Redis 主线程就很容易发生阻塞,这样就无法处理后续的请求了

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

1.在内存中完成,CPU不是瓶颈(CPU是瓶颈,才会考虑多线程)
2.避免了多线程竞争
3.I/O多路复用(I/O多路复用是一种允许单个进程或线程同时处理多个I/O操作的技术
I/O多路复用的核心思想是使用一个或多个系统调用来监视多个I/O通道(如文件描述符),并在I/O通道准备好进行读写操作时通知应用程序。这样,应用程序就可以在单个线程中处理多个I/O请求,而无需为每个I/O请求创建单独的线程或进程。(意思就是监听,准备好开始读写了再通知线程来处理)
在这里插入图片描述
网络硬件的提升–导致瓶颈可能出现再网络IO上,所以网络I/O采取多线程
命令的执行仍然是单线程
在这里插入图片描述

Redis 持久化(AOF,RDB,混合持久化

如何实现数据不丢失

为了保证内存中的数据不会丢失,Redis 实现了数据持久化的机制
在这里插入图片描述
Redis 共有三种数据持久化的方式:
AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点

AOF 日志(append only file)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RDB(Redis Database)快照

在这里插入图片描述
Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。所以执行快照是一个比较重的操作,如果频率太频繁,可能会对 Redis 性能产生影响。如果频率太低,服务器故障时,丢失的数据会更多。

RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据,而 AOF 文件记录的是命令操作的日志,而不是实际的数据。

混合持久化方式

RDB 优点是数据恢复速度快,但是快照的频率不好把握。频率太低,丢失的数据就会比较多,频率太高,就会影响性能。
AOF 优点是丢失数据少,但是数据恢复不快。(因为AOF记录的是命令。恢复相当于得一条条执行命令)
为了集成了两者的优点, Redis 4.0 提出了混合使用 AOF 日志和内存快照,也叫混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险。

Redis 集群

Redis 如何实现服务高可用?

服务高可用(High Availability, HA)是指通过设计和实施特定的技术手段,确保服务能够在面对各种故障和异常情况时,仍然能够持续运行,从而提供几乎不间断的服务。高可用性是衡量服务稳定性和可靠性的重要指标。)—个人理解 就是抗风险能力 面对各种故障时,仍然能正常

主从复制是 Redis 高可用服务的最基础的保证,实现方案就是将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,且主从服务器之间采用的是「读写分离」的方式。

具体来说,在主从服务器命令传播阶段,主服务器收到新的写命令后,会发送给从服务器。但是,主服务器并不会等到从服务器实际执行完命令后,再把结果返回给客户端,而是主服务器自己在本地执行完命令后,就会向客户端返回结果了。如果从服务器还没有执行主服务器同步过来的命令,主从服务器间的数据就不一致了。

所以,主从复制 无法实现强一致性保证(主从数据时时刻刻保持一致),数据不一致是难以避免的
在使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复。
为了解决这个问题,Redis 增加了哨兵模式(Redis Sentinel),因为哨兵模式做到了可以监控主从服务器,并且提供主从节点故障转移的功能。

什么是哨兵模式

一组组件(哨兵)负责监控其他组件的状态,并在检测到问题时采取措施以维护系统的稳定性和可用性。

什么是redis切片集群

Redis 切片集群(Redis Cluster)是一种分布式的数据库解决方案,用于处理大规模数据集和高并发访问的场景。当单台服务器的内存不足以存储所有的缓存数据,或者单台服务器的处理能力无法满足高并发请求时,Redis Cluster 提供了一种水平扩展的方法

当 Redis 缓存数据量大到一台服务器无法缓存时,就需要使用 **Redis 切片集群(Redis Cluster )**方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。
Redis Cluster 方案采用哈希槽(Hash Slot),来处理数据和节点之间的映射关系。

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

简言之就是:由于网络问题,集群节点之间失去联系。主从数据不同步;重新平衡选举,产生两个主服务。等网络恢复,旧主节点会降级为从节点,再与新主节点进行同步复制的时候,由于会从节点会清空自己的缓冲区,所以导致之前客户端写入的数据丢失了。

什么是脑裂

在这里插入图片描述
解决方案
设置一个阈值:主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的写请求了。(断联的从库多了或从库复制主库的延迟高了都不准写了)
当主节点发现从节点下线或者通信超时的总数量小于阈值时,那么禁止主节点进行写数据,直接把错误返回给客户端。

Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。
「过期字典」保存了数据库中所有 key 的过期时间

在这里插入图片描述
Redis 使用的过期删除策略是「惰性删除+定期删除」这两种策略配和使用。
惰性删除策略的做法是,不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。
在这里插入图片描述

定期删除策略的做法是,每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。
在这里插入图片描述
在 Redis 的运行内存达到了某个阀值,就会触发内存淘汰机制,这个阀值就是我们设置的最大运行内存,此值在 Redis 的配置文件中可以找到,配置项为 maxmemory。

Redis 过期删除与淘汰

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

过期删除策略是「惰性删除+定期删除」这两种策略配和使用

惰性删除(我懒,不主动删除,每次都是等你需要这个key了 我在检查它过没过期

惰性删除策略的做法是,不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。

定期删除(每隔一段时间随机抽查

定期删除策略的做法是,每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。、

Redis 内存满了,会发生什么?-> redis内存淘汰策略

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

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

LRU( Least Recently Used ) 最近最少使用

Redis 实现的是一种近似 LRU 算法,目的是为了更好的节约内存,它的实现方式是在 Redis 的对象结构体中添加一个额外的字段,用于记录此数据的最后一次访问时间。

当 Redis 进行内存淘汰时,会使用随机采样的方式来淘汰数据,它是随机取 5 个值(此值可配置),然后淘汰最久没有使用的那个。

但是 LRU 算法有一个问题,无法解决缓存污染问题,比如应用一次读取了大量的数据,而这些数据只会被读取这一次,那么这些数据会留存在 Redis 缓存中很长一段时间,造成缓存污染。

LFU ( Least Frequently Used) 最近最不常用的

LFU 算法是根据数据访问次数来淘汰数据的,它的核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
LFU 算法相比于 LRU 算法的实现,多记录了「数据的访问频次」的信息

Redis 缓存设计(重点中的重点)

缓存雪崩(同一时间大量缓存失效了,全部都去访问数据库,给数据库整崩了)

当大量缓存数据在同一时间过期(失效)时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题

如何解决

同一时间大量缓存失效了
解法1:把缓存失效时间随机打散
解法2:设置缓存不过期(通过后台服务更新缓存数据)
在这里插入图片描述

缓存击穿(某个热点数据的缓存过期了 一堆人要访问它 ,只有问数据库,数据库被高并发请求给干崩了)

我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据
如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。

如何解决

一堆线程都要访问一个数据 解法1:加锁,同一时间只允许一个线程请求
解法2:不让热点数据过期
在这里插入图片描述

缓存穿透(数据库中根本没有要找的数据)

当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦缓存恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。
当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题

如何解决

1.对非法请求的限制
2.设置空值或默认值
3.使用布隆过滤器快速检查,避免查询数据库
(布隆过滤器(Bloom Filter)是一种空间效率很高的概率型数据结构,用于判断一个元素是否在一个集合中
布隆过滤器在实际应用中非常广泛,特别是在大数据和分布式系统中,它可以显著减少不必要的磁盘I/O操作,提高系统性能。然而,由于其概率型的特点,布隆过滤器并不适用于需要完全准确的场合。
在这里插入图片描述

如何动态缓存热点数据

在这里插入图片描述

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

先删除缓存,再更新数据库,在「读 + 写」并发的时候,还是会出现缓存和数据库的数据不一致的问题
而先更新数据库,再删缓存
在这里插入图片描述

在这里插入图片描述

缓存更新策略

Cache Aside(旁路缓存)策略

应用程序直接交互
在这里插入图片描述
注意,写策略的步骤的顺序不能倒过来,即不能先删除缓存再更新数据库,原因是在「读+写」并发的时候,会出现缓存和数据库的数据不一致性的问题。
Cache Aside 策略适合读多写少的场景,不适合写多的场景

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

无论是「先更新数据库,再更新缓存」,还是「先更新缓存,再更新数据库」,这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象
----------->引出Cache Aside 策略,中文是叫旁路缓存策略。
不更新缓存,而是删除缓存中的数据。然后,到读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中。

相关文章:

  • 从这五部分入手可以完成一份出色的英文论文
  • 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?(jvm)
  • Vitis IDE 艰难切换--从传统 Vitis GUI 到 2024.1 统一软件界面
  • 【探索Linux】P.36(传输层 —— TCP协议段格式)
  • spring如何给bean动态取不同的别名
  • Windows编程上
  • 现代工作场所中的睡岗检测算法应用
  • 操作系统缓存与缓冲
  • wordpress企业主题和wordpress免费主题
  • ai智能语音机器人电销系统:让销售更快速高效
  • 基于Teager-Kaiser能量算子的肌电信号降噪方法(MATLAB)
  • Python基础入门知识
  • 巴西社交APP出海热潮!本土网盟CPI流量助力海外广告引流新方向
  • 六西格玛绿带培训ROI:你的投资究竟值不值?
  • Qt——升级系列(Level Eight):界面优化
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • angular组件开发
  • Fundebug计费标准解释:事件数是如何定义的?
  • HTTP--网络协议分层,http历史(二)
  • If…else
  • IOS评论框不贴底(ios12新bug)
  • opencv python Meanshift 和 Camshift
  • python3 使用 asyncio 代替线程
  • Sequelize 中文文档 v4 - Getting started - 入门
  • Spring Boot MyBatis配置多种数据库
  • 搭建gitbook 和 访问权限认证
  • 目录与文件属性:编写ls
  • 前端临床手札——文件上传
  • 山寨一个 Promise
  • 双管齐下,VMware的容器新战略
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 用element的upload组件实现多图片上传和压缩
  • 智能合约开发环境搭建及Hello World合约
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • %check_box% in rails :coditions={:has_many , :through}
  • (70min)字节暑假实习二面(已挂)
  • (LeetCode C++)盛最多水的容器
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (分布式缓存)Redis持久化
  • (十三)MipMap
  • (算法)求1到1亿间的质数或素数
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • ***原理与防范
  • ./configure,make,make install的作用
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Core 中插件式开发实现
  • .NET Framework .NET Core与 .NET 的区别
  • .net mvc部分视图
  • .NetCore 如何动态路由