1、什么是SDS?

Redis 自定的字符串存储结构,关于redis,你需要了解的几点!中我们对此有过简要说明。

Redis 底层是用C语言编写的,可是在字符存储上,并未使用C原生的String类型,而是定义了自己的字符串结构 Simple Dynamic Stirng,简称SDS。

SDS基本结构如下:

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

例如,字符串“Redis”存储示意图为:

图1

当前存储字符串长度为5,未使用长度为0,字节数组存储的字符为“Redis\0”。

这里需要注意的是:内部数据数组存储字符串形式符合C语言要求,以‘\0’结尾。且len字符串长度不包含结尾标识符‘\0’。

buf[]的这种遵循C语言形式的存储,使得Redis可以直接使用C语言的相关字符串函数进行SDS对象的操作。

二、SDS的优势

1、O(1)时间复杂度获取字符串长度

SDS内部维护着一个字符串长度的len变量,可以直接读取,时间复杂度为O(1)。

对于传统的C字符串:字符+“\0”,想要获取字符长度,则需要遍历整个字符串,直到遇到结束字符,时间复杂度为O(n)。

2、缓冲区溢出规避

所谓缓冲区溢出即所需要的内存超出了实际的内存。因此对于C字符串来说,要特别注意内存分配,回收使用问题。

比如,向一个现有字符串内添加特定字符时,需要保证当前已经分配了这足够的内存。

图2

与C不同的是,SDS的空间预分配策略可以避免缓冲区溢出发生,

当需要对SDS进行操作时,首先会检查当前空间是否满足需求,不足则扩展当前分配空间。内存检查相对于C变成了内部预置操作。

3、减少内存重分配次数

上面我们讲到过,C字符操作前都需要进行内存的分配操作,同时,操作完成后,也需要进行相应的内存回收操作。一次操作至少涉及一次内存分配操作。

大家都知道内存的重分配是一个比较复杂且需精细控制的过程,耗时耗资源。针对此弊端,Redis 在SDS内存配置策略上采用了空间预分配+惰性删除相结合的策略。

a)空间预分配:

空间预分配用于优化SDS字符扩展操作。

所谓预分配,也即是说在一次扩展操作中,扩展的空间大小会大于实际需要的空间大小。
如下,图1执行图2操作后SDS变更为:

图3

预分配空间的大小基于以下规则计算:

SDS len<1M:分配len长度空间作为预分配空间;

SDS len>=1M:分配1M空间作为预分配空间;

这样,在下次进行字符操作的时候,如果所需要的空间小于当前SDS free空间,则可以直接行操作,而不需要再执行内存扩展,重分配操作。

SDS的预分配机制使得一次扩展操作所需的内存重分配次数变为<=1。

b)惰性删除机制

所谓惰性删除,即调整删除SDS中部分数据时,不会立刻执行内存重分配,而是会保留空出来内存,并更新内部free属性。以备将来有字符扩展需求,可以直接使用。

当然,Redis也提供了主动释放未使用内存的方法。

如下,删除“ent”之后的SDS结构:

图4

SDS的内存分配机制,尤其对于以写为主的应用场景,能够提供更加优异的性能表现。

3、二进制安全

C字符串由于特殊的编码要求只能保存文本数据。

SDS相关的功能方法会以二进制的形式来操作SDS存储的数据,没有任何中间操作,存储最原始的数据,因此不会有字符层面的因素影响。

SDS可以保存任何源的二进制数据,字符、图片、文件或者序列化的对象等等。

Redis SDS 深入一点,看到更多!的更多相关文章

  1. C基础 带你手写 redis sds

    前言 - Simple Dynamic Strings  antirez 想统一 Redis,Disque,Hiredis 项目中 SDS 代码, 因此构建了这个项目 https://github.c ...

  2. [redis]SDS和链表

    一.SDS 1.SDS结构体 redis3.2之前:不管buf的字节数有多少,都用 4字节的len来储存长度,对于只存短字符串那么优点浪费空间,比如只存 name,则len=4 则只需要一个字节8位即 ...

  3. 理解 Redis(4) - 关于 string 的更多命令(SETEX, SETNX, INCR, DECR, MSET...)

    上一节介绍了关于字符串值的一些基本命令, 这一节将介绍一些进阶命令: 清理终端: 127.0.0.1:6379> clear 设置一个键值对, 同时设置过期时间为10秒: 127.0.0.1:6 ...

  4. Redis开发与运维:SDS

    STRING 我们会经常打交道的string类型,在redis中拥有广泛的使用.也是开启redis数据类型的基础. 在我最最开始接触的redis的时候,总是以为字符串类型就是值的类型是字符串. 比如: ...

  5. 阿里面试这样问:redis 为什么把简单的字符串设计成 SDS?

    2021开工第一天,就有小伙伴私信我,还给我分享了一道他面阿里的redis题(这家伙绝比已经拿到年终奖了),我看了以后觉得挺有意思,题目很简单,是那种典型的似懂非懂,常常容易被大家忽略的问题.这里整理 ...

  6. 图解Redis之数据结构篇——简单动态字符串SDS

    图解Redis之数据结构篇--简单动态字符串SDS 前言     相信用过Redis的人都知道,Redis提供了一个逻辑上的对象系统构建了一个键值对数据库以供客户端用户使用.这个对象系统包括字符串对象 ...

  7. Redis源码分析(sds)

    源码版本:redis-4.0.1 源码位置:https://github.com/antirez/sds 一.SDS简介 sds (Simple Dynamic String),Simple的意思是简 ...

  8. Redis 源码简洁剖析 02 - SDS 字符串

    C 语言的字符串函数 C 语言 string 函数,在 C 语言中可以使用 char* 字符数组实现字符串,C 语言标准库 string.h 中也定义了多种字符串操作函数. 字符串使用广泛,需要满足: ...

  9. 【Redis】简单动态字符串SDS

    C语言字符串 char *str = "redis"; // 可以不显式的添加\0,由编译器添加 char *str = "redis\0"; // 也可以添加 ...

随机推荐

  1. Nexus Repository Manager 3(CVE-2019-7238) 远程代码执行漏洞复现

    0x00 漏洞背景 Nexus Repository Manager 3是一款软件仓库,可以用来存储和分发Maven,NuGET等软件源仓库.其3.14.0及之前版本中,存在一处基于OrientDB自 ...

  2. Beta冲刺——5.26

    这个作业属于哪个课程 软件工程 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.组员一起学习Git分支管 ...

  3. DevOps - 从渐进式交付说起(含实践 Demo)

    作者:CODING - 王炜 1. 开篇 如果让你主导一款千万.甚至亿级用户产品的功能迭代,你会怎么做?你需要面对的挑战可能来自于: 商业战略的变化带来新的产品诉求,而产品的任何改动哪怕仅是界面调整, ...

  4. Java实现 LeetCode 242 有效的字母异位词

    242. 有效的字母异位词 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词. 示例 1: 输入: s = "anagram", t = " ...

  5. Java中那些烦人的位运算(&,|...)

    & 和 && 相同点: 都表示"与"操作.这里的"与"和数学中的"与或非"中的"与"意义相同,都 ...

  6. Java实现 蓝桥杯VIP 算法提高 洗牌

    算法提高 洗牌 时间限制:1.0s 内存限制:256.0MB 问题描述 小弱T在闲暇的时候会和室友打扑克,输的人就要负责洗牌.虽然小弱T不怎么会洗牌,但是他却总是输. 渐渐地小弱T发现了一个规律:只要 ...

  7. Java实现蓝桥杯快乐数

    [问题描述] 判断一个正整数是否是快乐数字? 如果一个数字能够通过有限次快乐变换成为1,则是快乐数字. 快乐变换是对一个数字的每一位的平方数求和. 例如: 对于68 68 => 62+82= 1 ...

  8. Java实现第九届蓝桥杯堆的计数

    堆的计数 题目描述 我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树. 每个节点有一个权值.对于小根堆来说,父节点的权值一定小于其子节点的权值. 假设N个节点的权值分别是1~N,你能求出 ...

  9. TZOJ 车辆拥挤相互往里走

    102路公交车是crq经常坐的,闲来无聊,他想知道最高峰时车上有多少人,他发现这辆车只留一个门上下人,于是他想到了一个办法,上车时先数一下车上人员数目(crq所上的站点总是人不太多),之后就坐在车门口 ...

  10. 练习C++的vector语法-约瑟夫问题

    //测试vector,约瑟夫问题 #include <iostream> #include <vector> using namespace std; int main() { ...