面试官:说说Redis的SDS底层实现原理

news2024/12/23 18:05:08

文章目录

  • 前言
  • 面试开始
    • 1、说说Redis基本类型有哪些
    • 2、String类型常用于什么场景
    • 3、String类型采用什么数据结构
    • 4、继续深入讲讲SDS实现细节
    • 5、你说说SDS和C语言字符串的区别
      • 5.1、SDS获取长度时间复杂度更低
      • 5.2、SDS杜绝缓冲区溢出
      • 5.3、SDS减少字符串内存重分配次数
      • 5.4、SDS二进制安全
      • 5.5、兼容部分C字符串函数
          • 参考资料:`《Redis设计与实现》`

前言

该文章已面试场景进行叙述,场景纯属编造,请勿当真!

大家好,我是徐志斌。

现在找工作真的好难,今天我早早的来到了面试现场,这家公司的HR小姐姐也是很热情的接待了我。

正当在会议室中沉浸在和HR姐姐聊天的喜悦中时,沉重的脚步声慢慢走来。只见一个身穿格子衫的秃头大哥抱着笔记本走进来,一看就是公司的技术大佬,我就知道今天的面试怕是凶多吉少。

在这里插入图片描述

面试开始

1、说说Redis基本类型有哪些

:我以为能问多难得问题,这种问题我还不是手到擒来
面试官:口气真是不小,老夫从业20年也不敢简历写精通Redis

Redis数据库常用的基本类型有5种,分别是:

  • String
  • List
  • Hash
  • Set
  • ZSet

2、String类型常用于什么场景

Redis的String类型使用的场景很多,例如:

  • 数据缓存
  • 计数器
  • 分布式锁
  • 分布式限流
  • 存储Token等时效信息

使用起来非常简单高效,我个人在开发过程中,经常会使用到String类型结构进行功能实现,比如说存储验证码用户身份信息等。

3、String类型采用什么数据结构

:怎么突然就问到底层实现了?你这个跨度真是够离谱的!
面试官:汗流浃背了吧,老弟!

Redis数据库虽然是用C语言开发的,但是String数据类型的底层并不是直接使用C语言的字符串结构(以空格结尾的字符数组),而是使用简单动态字符串(SDS),这个类型可以被修改。

AOF的缓冲区客户端状态中的输入缓冲区都是由SDS实现的。

4、继续深入讲讲SDS实现细节

:虎躯一震,心里慌了但又故作镇定,毕竟这块我曾经还是认真学习过

SDS结构是这样的,C语言代码如下(我随手拿起笔写出下面代码):

struct sdshdr {
	// SDS保存字符串长度(buf数组已使用字节数量)
	int len;
	// buf数组未使用字节数量
	int free;
	// buf字节数组,用于存储SDS字符串
	char buf[];
}

在这里插入图片描述

图中也可以看到,buf数组最后一个字节存储的是'\0',但这并不算入SDS的len属性SDS函数自动为该字节分配额外空间,并且添加到数组尾部,对于用户来说是无感知的。

好处:SDS可直接重用部分C语言字符串函函数(直接使用printf函数,无需为SDS编写专门打印的函数),后续5.5章节会提到。

5、你说说SDS和C语言字符串的区别

:呸呸呸!真该死啊,提C语言干嘛,这不给自己挖坑?

这个就说来话长了!

我先说C字符串吧,C语言的字符串是通过长度为N + 1的字符数组来表示,数组尾部总是空字符'\0',但是不满足Redis对字符串的高要求:安全、效率、功能等(这就是为什么Redis使用SDS的原因),C字符串结构:
在这里插入图片描述

它俩之间的主要区别有以下5点:

5.1、SDS获取长度时间复杂度更低

C语言字符串不记录自身长度信息,所以想要获取长度必须遍历整个字符串,该操作的时间复杂度为O(N)

SDS不需要从头遍历获取长度,之前SDS图中也提到有len属性,这样可以直接获取SDS的长度,获取操作时间复杂度为O(1)。设置、更新SDS长度操作是由SDS API自动完成。

Redis使用SDS将获取字符串长度所需要的复杂度从O(N)——>O(1),这样就不会影响Redis的性能。Redis的Key底层就是通过SDS来实现的,所以对一个非常长的字符串多次进行STRLEN命令也不会影响系统性能!

5.2、SDS杜绝缓冲区溢出

C语言字符串不记录自身长度信息,很容易造成缓冲区溢出
例如:程序内存中存在两个相邻的C字符串,如图:
在这里插入图片描述
此时将S1内容修改为Redis Cluster,并且修改前并没有为S1分配足够的空间,此时修改后的结果如下:
在这里插入图片描述

SDS空间分配策略就不会出现上述情况:当SDS API需要对SDS进行修改,API会先检查SDS空间是否满足修改要求。如果不满足:SDS API自动将SDS空间扩展至修改所需的大小,SDS API中的sdscat函数就是这样的。

正如之前所说,SDS不需要手动修改SDS空间大小,并且不会出现缓冲区溢出问题。

5.3、SDS减少字符串内存重分配次数

C语言字符串增长、缩短操作都需要进行一次内存重分配

  • 增长:执行拼接操作前需要先通过内存重分配来扩展底层数组长度,如果没扩展就会产生缓冲区溢出
  • 缩短:执行截断操作前需要先通过内存重分配来释放不再使用的空间,如果没释放就会产生内存泄漏

但是内存重分配算法复杂,并且可能需要执行系统调用,所以是非常耗时的操作,但是Redis对性能要求是非常苛刻的,如果每次修改字符串长度都需要进行内存重分配,就会对性能造成极大的影响。

SDS为了避免这种情况,并不像C字符串那样长度一定是字符串数 + 1,在SDS中buf数组可以包含未使用字节空间,这个字节空间数量就是SDS的free属性,通过未使用字节空间实现了空间预分配惰性空间释放两种优化策略!


我先说说空间预分配

听名字也很好理解啦,就是SDS API对一个SDS进行扩容时,不仅分配修改所需必要空间,还会额外分配未使用的空间。

  • 如果修改后SDS的len < 1MB,那么会分配和len等大的free空间,例如:修改后SDS的len为13字节,那么free也为13字节,buf[]长度为:13 + 13 + 1 = 27字节
  • 如果修改后SDS的len ≥ 1MB,那么会分配1MBfree空间,例如:修改后SDS的len为30MB,那么会分配1MB的未使用空间,此时SDS的buf[]长度为:30MB + 1MB + 1字节

通过空间预分配策略,可以减少连续执行字符串变化操作所需的内存重分配次数,因为下次扩展SDS空间之前,如果SDS API检查空间充足,就直接使用了,不需要内存重分配了。

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

通过该策略,即使SDS连续增长N次,内存重分配次数也最多为N次。


关于惰性空间释放:

也比较好理解,区别于空间预分配,它是针对于SDS字符串缩短操作的。当SDS进行缩短操作时,程序不会立即进行内存重分配回收多出来的字节空间,而是使用free属性将多出来的数量记录下来,等待以后使用。

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

此时在对SDS进行扩容操作时,free空间足够就不需要进行内存重分配操作了。当然SDS API也提供了真正释放未使用空间的函数,无需担心内存浪费

5.4、SDS二进制安全

C语言字符串不能包含空字符,程序会认为空字符就是字符串结尾,所以C字符串只能存文本信息,不能存二进制数据,例如:视频、音频、图片等。

比如说字符串"Redis Cluster",对于C的函数只能识别"Redis""Cluster",如下图:

在这里插入图片描述

但是SDS是二进制安全的,SDS API以二进制方式处理存放在buf[]中的数据,写入和读取时数据没有任何区别,SDS使用len去取代空字符判断字符串是否结束,所以相比于C字符串,SDS不仅能存文本,还能存任意格式的二进制数据

5.5、兼容部分C字符串函数

之前提到,SDS的末尾总是设置为'\0',就是为了能够使用C字符串函数库的部分函数(文章开头提到过这个特点),Redis就不需要专门为SDS编写这些函数了,减少了大量代码重复!


以上就是SDS和C语言字符串的区别所在,哎哟,累死我了(这还唬不住你?),面试官嘴角露出一丝微笑,我就知道这个回答他也是挺满意的(能不满意吗,面试时候要是这么答,那Offer必然手到擒来)

面试官:不错不错,SDS原理学习的非常扎实啊,不过其他类型底层实现原理呢?

本以为面试到此为止了,没想到这才刚刚开始…

参考资料:《Redis设计与实现》

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

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

相关文章

pytest全局变量的使用

这里重新阐述下PageObject设计模式&#xff1a; PageObject设计模式是selenium自动化最成熟&#xff0c;最受欢迎的一种模式&#xff0c;这里用pytest同样适用 这里直接提供代码&#xff1a; 全局变量 conftest.py """ conftest.py 全局变量&#xff0c;主要实…

基于Java+SpringBoot+LayUI仓库管理系统

一.项目介绍 本项目是使用JavaSpringBoot开发&#xff0c;可以实现仓库的注册、登录&#xff0c;登录后可进入系统&#xff0c;进行客户管理、供应商管理、商品管理、商品退货查询管理、登录日志及退出等几大模块。系统界面采用传统的后台管理界面&#xff0c;界面简单、直观。…

2023年“走红军走过的路”徒步穿越系列活动(大通湖站)盛大开赛!

“蟹”逅红色大通湖 徒步秋色水波中 ——“中国体育彩票” 2023年“走红军走过的路”徒步穿越系列活动&#xff08;大通湖站&#xff09;暨大通湖半程马拉松盛大开赛&#xff01; 11月5日上午8:30&#xff0c;2023年“走红军走过的路”徒步穿越系列活动&#xff08;大通湖站&…

数据结构-Prim算法构造无向图的最小生成树

引子&#xff1a; 无向图如果是一个网&#xff0c;那么它的所有的生成树中必有一颗生成树的边的权值之和是最小的&#xff0c;我们称 这颗权值和最小的树为&#xff1a;“最小生成树”&#xff08;MST&#xff09;。 其中&#xff0c;一棵树的代价就是树中所有权值之和。 而…

幂等最佳实践

1、什么是幂等&#xff1f; 根据百度百科解释&#xff1a; “幂等&#xff08;idempotent、idempotence&#xff09;是一个数学与计算机学概念&#xff0c;常见于抽象代数中。 在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数&…

删除word最后一页之后的空白页

最近编辑word比较多&#xff0c;有时最后一页&#xff08;最后一页内容还有可能是表格&#xff09;之后&#xff0c;还有一页空白页&#xff0c;单独按下backspace、del都删不掉&#xff0c;很让人着急。 经过查询有几种方法&#xff1a; &#xff08;1&#xff09;点击选中空…

kubernetes(5) 续4

目录 volumes emptyDir卷 hostpath卷 nfs卷 持久卷 storageclass statefulset控制器 mysql主从部署 volumes emptyDir卷 [rootk8s2 volumes]# vim emptydir.yaml apiVersion: v1 kind: Pod metadata:name: vol1 spec:containers:- image: busyboxplusname: vm1command: ["…

pyqt5的组合式部件制作(一)

以多选一的选择器为例&#xff0c;来实践一下工程实用级别的组合式部件设计。自己之前做的自定义的组合式部件&#xff0c;结构不够简单优化&#xff0c;在实际的工程里面&#xff0c;使用部件的过程比较繁琐。所以&#xff0c;这里来做一个优化的实验。 之所以做这个组合部件&…

DevChat:开源AI编程助手的全面解析

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【场景方案】前端如何结合GPT提升我们的开发效率,个人经验总结,不定期更新~

文章目录 AI模型的选择提问的方式很重要心里建设提问方法论设立角色从总体到局部步骤拆分&#xff0c;循序渐进举例子说明主动让他联系上文不要太纠结提问的方式 网址推荐尾巴 不说废话&#xff0c;没有铺垫&#xff0c;直接开始讲重点 AI模型的选择 首先咱们要选择一个适合的…

3-知识补充-HTTP协议

3-知识补充-HTTP协议 文章目录 3-知识补充-HTTP协议HTTP协议基础什么是HTTP&#xff1f;HTTP协议的会话方式HTTP1.0和HTTP1.1的区别 请求和响应报文报文的格式报文解析实例-请求百度官网请求报文-GET请求请求报文-POST请求-学习用-非请求百度官网响应报文 响应状态码有代表性的…

第八章认识Express框架

目录 Express模块化路由 基本概述 基本使用 基本构建 案例项目 Express接收请求参数 基本概述 基本类别 Express接收GET请求参数 Express接收POST请求参数 Express接收路由参数 Express模块化路由 基本概述 在Express中&#xff0c;路由是指确定应用程序如何响应对…

功率放大器的工作原理及选购技巧

功率放大器是电子设备中非常重要的组成部分之一&#xff0c;它的主要功能是将输入信号的功率进行放大&#xff0c;以驱动高功率负载。在各种应用领域中&#xff0c;如音频放大器、无线电频率放大器、射频功率放大器等&#xff0c;功率放大器都发挥着非常重要的作用。下面将介绍…

Kubernetes二进制搭建

目录 一、K8S的架构 二、K8S创建Pod资源的工作流程 三、K8S资源对象和资源配置信息 K8S资源对象 K8S资源配置信息 四、K8S的的三种网络和三种接口 三种网络&#xff1a; 三种节点&#xff1a; 五、etcd 集群 etcd 的特点&#xff1a; 六、flannel flannel方案 K8S …

指令手册术语缩写

指令手册术语缩写 1 指令汇总表中的操作码列(不带VEX前缀的指令)2 指令汇总表中的操作码列(带有VEX前缀的指令)3 操作码汇总表中的指令列 本文属于《 X86指令基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 指令汇总表中的操作码列(不带VEX前缀的指令) 2 指令汇总表中的…

阿里云安全恶意程序检测(速通三)

阿里云安全恶意程序检测 特征工程进阶与方案优化pivot特征构建pivot特征pivot特征构建时间pivot特征构建细节特点 业务理解和结果分析结合模型理解业务多分类问题预测结果分析 特征工程进阶基于LightGBM模型验证模型结果分析模型测试 优化技巧与解决方案升级内存管理控制加速数…

【配置】如何在打包Spring Boot项目时按需使用日常、测试、预发、正式环境的配置文件

文章目录 前言1. 创建5个配置文件2. 在pom.xml文件中如下配置3. 在application.properties中加入环境变量 前言 在我们开发项目的时候&#xff0c;一般有四套环境&#xff1a;日常、测试、预发、正式。日常环境作为我们开发环境&#xff1b;测试环境给测试同学测试功能&#x…

基于厨师算法的无人机航迹规划-附代码

基于厨师算法的无人机航迹规划 文章目录 基于厨师算法的无人机航迹规划1.厨师搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用厨师算法来优化无人机航迹规划。 1.厨师搜索算法 …

Canal同步Mysql数据到ES以及Springboot项目查询ES数据

1、环境准备 服务器&#xff1a;Centos7 Jdk版本&#xff1a;1.8 Mysql版本&#xff1a;5.7.44 Canal版本&#xff1a;1.17 Es版本&#xff1a;7.12.1 kibana版本&#xff1a;7.12.1 软件包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1jRpCJP0-hr9aI…

C++进阶篇4---番外-AVL树

一、AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查 找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年发明了一…