首页 > 数据库 >常见面试题-Redis底层的SDS、ZipList、ListPack

常见面试题-Redis底层的SDS、ZipList、ListPack

时间:2023-11-12 21:32:26浏览次数:40  
标签:面试题 SDS ZipList entry 字符串 长度 data 节点

Redis 的 SDS 了解吗?

答:

Redis 创建了 SDS(simple dynamic string) 的抽象类型作为 String 的默认实现

SDS 的结构如下:

struct sdshdr {
  // 字节数组,用于保存字符串
  char buf[];
  // buf[]中已使用字节数量,称为SDS的长度
  int len;
  //  buf[]中尚未使用的字节数量
  int free;
}

为什么 Redis 不使用 C 语言默认的字符串呢?(Redis 是用 C 实现的)

  • 提升获取长度性能:使用 SDS 可以以 O(1) 的时间复杂度取到字符串的长度,因为 SDS 中存储了字符串的长度;在 C 语言的字符串中,需要遍历才可以获取长度
  • 保障二进制安全:C 字符串只能包含符合某种编码格式的字符,如 ASCII、UTF-8,并且除了字符串末尾外,不能含有 '\0',这是因为 C 字符串是以 '\0' 结尾的,而在视频、图片中的数据以 '\0' 作为分隔符很常见,因此 C 字符串无法存储这些数据;而在 SDS 中存储了字符串的长度,因此不需要分隔符
  • 减少内存再分配数:SDS 采用了空间预分配策略,每次 SDS 进行空间扩展时,程序会同时分配所需空间和额外的未使用空间,以减少内存的再分配次数。额外分配的未使用空间大小取决于空间扩展后SDS的len属性值。
  • 如果len < 1M,那么分配的未使用空间大小与 len 相同
  • 如果len >= 1M,那么分配的未使用空间大小为 1M

SDS 也采用了惰性空间释放策略,即 SDS 字符串长度变短,并不会立即释放空间,而是将未使用的空间添加到 free 中,以便后期扩展 SDS 时减少内存分配次数

Redis 的 zipList

答:

Redis 的压缩列表即 ziplist,可以包含多个节点,每个节点可以保存一个长度受限的字符数组或者整数

因为 ziplist 节约内存的性质,哈希键、列表键和有序集合键初始化的底层实现皆采用 ziplist

ziplist 底层结构由 3 部分组成:head、entries、end,这三部分在内存上连续存放

  • head
    head由三部分组成
  • zlbytes:占4B,表示 zipList 整体所占字节数,包括 zlbytes 本身长度
  • zltail:占4B,用于存放 zipList 最后一个 entry 在整个数据结构中的偏移量,可用于定位链表末尾的 entry
  • zllen:占2B,存放列表包含的 entry 个数
  • entries
    entries 是真正的列表,由很多 entry 构成,由于元素类型、数值不同,每个 entry 的长度也不同
    entry由三部分组成
  • prevlength:记录上一个 entry 的长度,用于逆序遍历,默认长度为 1 字节,如果上一个 entry 的长度 >= 254B,prevlength 就会扩展为 5B
  • encoding:标志后面的 data 的具体类型。如果 data 为整数,encoding 固定长度为1B,如果data为字符串,encoding可能为1B、2B、5B,data字符串不同的长度,对应着不同的encoding长度
  • data:真正存储的数据,数据类型只能是整数或字符串
  • end
    end只包含一部分,称为 zlend,占1B,值为255,也就是8个1,表示 zipList 列表的结束

常见面试题-Redis底层的SDS、ZipList、ListPack_Redis

Redis 的 listPack

答:

Redis 的 zipList 存在一些缺点:

  • 实现复杂,为了实现逆序遍历,每一个 entry 都存储了前一个 entry 的长度,这样在插入和更新时可能会造成连锁更新连锁更新举例:假如 ziplist 中每一个 entry 都是很接近但又不到 254B,此时每个 entry 的 prevlength 使用 1 个字节就可以保存上个节点的长度,但是此时如果向 ziplist 中间插入一个新的节点,长度大于 254B,那么新插入节点后边的节点需要把 prevlength 扩展为 5B 来存储新插入节点的长度,那么扩展后该节点长度又大于 254B,因此后边节点需要再次扩展 prevlength 来存储该节点的长度,导致了插入节点后边的所有节点都需要更新 prevlength 的值,这属于是极端情况下才会发生

因此为了更好的性能,在 Redis7.0 中,将 ziplist 全部替换为了 listpack,但是为了兼容,还是保留了 ziplist 的相关属性

  • head
    head包括两部分:
  • totalBytes:占4B,存放 listPack 整体所占字节数,包含 totalBytes 本身
  • elemNum:占 2B,存放 entry 个数
  • entries
    entries是真正的列表,由很多entry组成,每个entry长度不同
    entry包括三部分(删除了prevlength,增加了element-total-len)
  • encoding:标志后面的 data 的具体类型。如果 data 为整数,encoding 固定长度为 1B,如果 data 为字符串,encoding 可能为 1B、2B 或 5B,data 字符串不同的长度,对应着不同的 encoding 长度
  • data:存储真正数据
  • element-total-len:记录当前 entry 长度,用于实现逆序遍历,占1、2、3、4或5字节

常见面试题-Redis底层的SDS、ZipList、ListPack_List_02

标签:面试题,SDS,ZipList,entry,字符串,长度,data,节点
From: https://blog.51cto.com/u_16186397/8331122

相关文章

  • 每天5道Java面试题(第10天)
    1. 自己实现一个HashMap?HashMap的实现思路:1,利用key的hashCode计算当前对象在数组中的下标。2,存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,覆盖原始值;(2)如果key不同(出现冲突),则将当前key-value放入链表中3,获取值时,直接找到对应hash值对应的下标,再进行判断key是否相同,......
  • python面试题收集
    1.Python是如何进行内存管理的?答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制一、对象的引用计数机制Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。引用计数增加的情况:1,一个对象分配一个新名称2,将其放入一个容器中(如列......
  • Java 面试题之 Logback 打印日志是如何获取当前方法名称的?
    在Java中,有四种方法可以获取当前正在执行方法体的方法名称,分别是:使用Thread.currentThread().getStackTrace()方法使用异常对象的getStackTrace()方法使用匿名内部类的getClass().getEnclosingMethod()方法Java9的Stack-WalkingAPI本文将根据以上四种方法来给......
  • 自己觉得重要的话(可当面试题的话)
    JavaBean在IOC容器中的声明周期:大体上就是先:实例化然后注入属性,然后初始化,然后就创建完成了,完成之后:就可以通过:classPathxmlApplicationContext的getBean()id或name作为参数,然后获取这个Bean!......
  • 常见面试题-计算机网络相关
    1.OSI七层模型?OSI七层模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层TCP/IP五层模型:应用层、传输层、网络层、链路层、物理层应用层应用层是由网络应用程序使用的,是离用户最近的一层应用层通过各种协议,为网络应用提供服务,常见协议如下:FTP-文件传输协议HTTP/......
  • 每天5道Java面试题(第9天)
    1. HashMap和Hashtable有什么区别?存储:HashMap允许key和value为null,而Hashtable不允许。线程安全:Hashtable是线程安全的,而HashMap是非线程安全的。推荐使用:在2. 如何决定使用HashMap还是TreeMap?对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择,因......
  • 秦疆的Java课程:24 基础 数据类型扩展及面试题讲解
    1、整数扩展进制二进制数:0b开头八进制数:0开头十六进制数:0x开头publicclassDEMO1{publicstaticvoidmain(String[]args){//整数扩展:进制intA=10;intB=0b10;//二进制intC=010;//八进制intD......
  • Android并发编程高级面试题汇总(含详细解析 十二)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......
  • Android并发编程高级面试题汇总(含详细解析 十五)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......
  • 每天5道Java面试题(第7天)
    1. Files的常用方法都有哪些?Files.exists():检测文件路径是否存在。Files.createFile():创建文件。Files.createDirectory():创建文件夹。Files.delete():删除一个文件或目录。Files.copy():复制文件。Files.move():移动文件。Files.size():查看文件个数。Files.read():读取文件。......