首页 技术 正文
技术 2022年11月23日
0 收藏 341 点赞 4,873 浏览 1615 个字

背景

redis功能强大,几乎已经成了现代大中型服务必备的缓存技术了。 除了十分给力的缓存功能,redis当做消息队列,数据库也有着不错的表现。

我们都知道,redis 有五种数据类型,string,list, hash, set 和zset。 其中 最基本的,同时也是最常用的 就是string了。 本文就来谈谈 redis内部,string 的实现原理:SDS(simple dynamic string)。

redis简单动态字符窜:SDS

  • 在redis里,C语言的字符窜只用来放字符串字面量,即只有当无序对字符串修改的时候才用C的字符串,例如打印日志的时候。
  • 除了基本的字符串存储之外,sds还用做缓冲区。AOF模块的缓冲区,和客户端状态的输入缓冲区,都是sds实现的。
SDS 定义
struct sdshdr {    // buf 中已占用空间的长度
int len; // buf 中剩余可用空间的长度
int free; // 数据空间
char buf[];
};

图示如下:

  • 简单解释一下: buf是一个字节数组,是用来放具体数据的。其长度是按一定策略伸缩的,具体解释在下面。 len 表示buf 中已经使用掉的长度,free表示 buf中尚未使用的长度。

  • buf内 sds 的字符串,总是以空字符结尾,这一点同c字符串一致。 因此sds 可以直接重用一部分c字符串函数库的函数。

SDS 与C字符串的对比 和优点

1,O(1) 获取字符串长度

  • 因为sds已经存了数据的长度,所以获取字符串长度复杂度为O(1),而C字符串获取长度为O(n)。

2,杜绝缓冲区溢出导致的内存问题

  • 假设内存区域有s1:“hi”,s2: “redis” 两个字符串,位置紧邻,如下图:

  • 此时需要给s1 追加一个“boy”, 如果是C字符串,忘记了在追加之前先给s1 分配空间,此时追加将导致 s2的值被意外的修改。 而使用 sds则不会有这个问题。 因为其封装好的函数,会在追加数据之前先检查 空间是否够用,如果不够用就扩容。

3,通过空间预分配和空间惰性释放 减少内存分配问题

  • 当给sds的值追加一个字符串,而当前的剩余空间不够时,就会触发sds的扩容机制。扩容采用了空间预分配的优化策略,即分配空间的时候:如果sds 值大小< 1M ,则增加一倍; 反之如果>1M , 则当前空间加1M作为新的空间。

  • 当sds的字符窜缩短了,sds的buf内会多出来一些空间,这个空间并不会马上被回收,而是暂时留着以防再用的时候进行多余的内存分配。这个是惰性空间释放的策略

4, 二进制安全

  • c字符串必须符合某种编码(例如ASCII),且不能包含空字符。 这些限制使得 c字符窜不能保存图片,音频等二进制文件。 而sds的api 都是二进制安全的,其所有api 都会以处理二进制的方式来处理buf内的数据,所以不会有任何的限制。

SDS 的API接口列表

函数 作用 复杂度
sdsnew 以一个c字符窜为参数新建sds O(N)
sdsempty 新建空的sds字符串 O(1)
sdsfree 释放sds O(N)
sdslen 获取已使用长度 O(1)
sdsavail 获取未使用长度 O(1)
sdsdup 创建一个sds的副本 O(N)
sdsclear 清空 O(1)
sdscat 追加C字符串到sds O(N)
sdscatsds 追加sds字符串到sds O(N)
sdscpy 用c字符串覆盖sds值 O(N)
sdsgrowzero 用空字符串扩展 sds至给定长度 O(N)
sdsrange 删除给定区间外的数据 O(N)
sdscmp 对比sds是否相同 O(N)
sdstrim 从sds中去除给定c字符串中出现过的字符 O(N*M)

总结

sds 其实就是字符串数组的一个封装,但是由于考虑了多种场景,作者给它适配了多个高效、优雅的接口,使得 sds成为了一个存储字符串的优秀设计。使得sds成为一个独立的、可提供高效优质服务的基础实体。

我们在设计一些偏底层的数据结构、对象、甚至是数据库表的时候,可以参考sds的设计,从中寻找一些启发。

参考: 《Redis 设计与实现》 黄健宏

有收获就点个赞吧~

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,991
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,505
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,349
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,134
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,766
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,844