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开发与实现》

相关推荐
深盾科技_Virbox5 分钟前
软件授权工具静默安装实践
java·运维·数据库·安全·软件需求
AI人工智能+电脑小能手28 分钟前
【大白话说Java面试题 第172题】【07_Redis篇】第8题:`setnx` 做分布式锁存在的问题
java·redis·分布式锁·死锁·setnx
延凡科技33 分钟前
延凡科技综合监控预警处置平台—— 一体化视频AI安防闭环系统设计与功能实现[特殊字符]️
数据库·人工智能·科技·安全·能源
老马聊技术34 分钟前
Rocky Linux 9.0 安装 MySQL8.x详细教程
linux·数据库
醇氧1 小时前
主流 Agent 开发框架全解析(2026 最新)
大数据·数据库·人工智能·开源
吴声子夜歌1 小时前
Redis 6.x——整合SpringBoot
数据库·spring boot·redis
ATA88881 小时前
AI辅助生成SQL实战从连接配置到执行计划优化的完整技术流程
数据库·人工智能·智能问数
咏方舟【长江支流】1 小时前
【开源】跨语言·跨平台·跨数据库(4) ——用宝框架 ORM 数据源适配器
数据库·开源·ai编程·orm·咏方舟-长江支流·用宝框架·用宝框架orm
Rain的Java大神实战圈1 小时前
每日排行榜功能如何设计
redis·架构设计·面试经验·场景设计题
JZC_xiaozhong1 小时前
OA调价审批后,采购调价单如何自动同步到ERP?解决漏录错价难题
大数据·linux·服务器·前端·数据库·数据孤岛解决方案·数据集成与应用集成