Redis (String 底层数据结构)

Redis是查询数据很快的no Sql数据库。其原因不只是因为它存储在内存中,还因为它存储各种类型的数据结构。比如这期说到的String类型。String类型在Redis中应用很广泛。Redis中存储数据是以键值对的方式。这个键都是String类型。所以下面我们看下String类型的底层数据结构吧。

1. 简单字符串(SDS)

1.1Redis是由C语言开发的。为啥字符串没有使用C字符串呢?

  1. 这是因为C字符串是以\0为结尾。所以保存的字符串长度总是比原字符串长1。而且存储的特殊字符也可能由于\0得特性导致数据丢失。如果Redis想要存储文件数据则就不能使用C字符串。否则会导致数据丢失。
  2. C字符串是以char\[\]数组来实现的,在创建出来之后就不能改变其长度了,所以如果执行字符串拼接或者字符串截取就需要创建新的char\[\]数组。这样就就会徒增性能的消耗。

1.2 Redis 字符串实现

Redis使用SDS来实现。

1.2.1 SDS结构
c 复制代码
struct sdshdr {
    //记录buf数组中已使用字节的数量
    //等于SDS所保存字符串的长度
    int len;
    //记录buf数组中未使用字节的数量
    int free;
    //字节数组,用于保存字符串
    char buf[];
};

  Redis虽然还是以\0为结尾但是不会再遇到\0就认为字符串到头了。这样做的好处还可以使用C语言中一些操作字符串的方法。

1.2.2 获取字符串长度

  C字符串需要判断\0的位置,所以计算长度是O(n)。而SDS有len字段可以直接判断字符串长度。所以是O(n)。

1.2.3 杜绝缓冲区溢出
  1. C语言字符串如果需要把一个字符串后面拼接另一个字符串。因为C语言字符串没有记录字符串的长度。假定没有分配足够的内存给后面一个字符串的长度。则会导致产生缓存区溢出。
  2. SDS在进行拼接时会判断可用长度free是否可以容纳拼接字符串的长度。如果不能够容纳则会进行扩容。扩容后达到足够容纳拼接字符串的可用空间后才会继续进行拼接操作。这样就不会造成缓存区的溢出了。
1.2.4 减少修改字符串时带来的内存重分配次数
  1. 正如上面所说拼接字符串。C语言需要每次都对目标字符串进行内存重新分配。所以只要每次操作都需要进行重新分配。
  2. 为了解决上面的问题SDS实现了空间预分配和惰性空间释放两种策略。
    a. 空间预分配
    ⅰ. 对SDS进行修改后如果长度小于1MB。那么SDS就会分配和len一样长度的大小的额外空间。比如分配后的长度为13。最终的len = 13 + 13 + 1 = 27。额外的一字节用于保存空字符。
    ⅱ. 如果分配后长度大于1MB。那么SDS就会分配多1MB的额外的空间。比如分配后的长度为30MB。最终的len = 30MB + 1MB + 1字节。
    b. 惰性空间释放
    ⅰ. 如果把字符串缩短。也不会把空余出来的空间给立马释放掉。会等待字符串变长时使用。SDS也提供了响应的API。让我们可以完全释放掉free的空间。
1.2.5 二进制安全

  C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。

  SDS的API都是二进制安全的(binary-safe),所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读取时就是什么样。

总结

所以根据上面的几个方面我们可以看出Redis使用SDS对字符串进行了优化。保证了字符串的安全性,提高了字符串操作的性能。

参考:《Redis开发与实现》

相关推荐
C++ 老炮儿的技术栈1 小时前
从 Qt Designer 属性编辑器的层级可以看到继承链
c语言·数据库·c++·qt·sqlite·visual studio
MC皮蛋侠客1 小时前
Redis 系列(一):全景与最小闭环——从 `SET` 命令到内存数据结构
数据结构·数据库·redis
疯狂打码的少年1 小时前
【数据结构】队列:定义、顺序队列与链式队列
数据结构·笔记
蔬菜_2 小时前
前端转全栈-day5(数组、list、set)
java·前端·数据结构·list
zt1985q2 小时前
本地部署开源网络书签与内容管理工具 Karakeep 并实现外部访问
运维·服务器·网络·数据库·网络协议·开源
CV-X.WANG3 小时前
从零理解 ORB-SLAM3(二):系统全景、执行上下文与核心数据结构
数据结构
IvorySQL3 小时前
PostgreSQL 日报| PostgreSQL 19 默认 WAL 压缩算法(8 月 8 日)
数据库·postgresql·区块链
Doraemomo4 小时前
数据结构-二叉树
数据结构
油丶酸萝卜别吃4 小时前
MySQL B+ 树查询全过程详解
数据库·mysql
leisoo80974 小时前
股票数据本地化存储实战:JSON、数据库与列式存储的方案对比
jvm·数据库·json