一起学Redis(1)——简单动态字符串

Redis是企业使用非常广泛的内存数据库,通常用作缓存,也是典型的NoSql数据库。NoSql数据库生产上比较受欢迎的主要有面向键值对的Redis和MemcacheDB,文档存储的MongoDB还有按列存储的HBase、Cassandra。这里我们主要研究学习Redis。

前面说到Redis既然是一种数据库,那研究数据库,最基本也就是最核心的一定是它的存储设计,由于Redis的读写快速、使用简单,因而受到广大开发者的欢迎和喜爱。Redis里面存储的形式键值对,而键和值都是对象,数据库键总是一个字符串对象(string object),而值可以是字符串对象、列表对象(list object)、哈希对象(hash object)、集合对象(set object)、有序集合对象(sorted set object)这五种对象中的一种。比如说,执行以下命令将在数据库中创建一个键为字符串对象,值也为字符串对象的键值对:

redis-> SET msg "hello world"
OK

而执行以下命令将在数据库中创建一个键为字符串对象,值为列表对象的键值对:

redis-> RPUSH numbers 1 3 5 7 9
(integer) 5

那我们现在就来说一说这个字符串对象。字符串对象内部没有直接使用C语言传统的字符串表示,而是自己构建了一种简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。SDS除了用来保存数据库中字符串值以外,还用作缓冲区(buffer):AOF中的缓冲区,客户端的输入缓冲区,这些后面再详细介绍。

再来看看SDS的定义,redis下载后到src目录下可以看到源码,sds.h/sdshdr中包含:

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

SDS遵循了C字符串以空字符结尾的惯例,保存’\0’但是不计算在SDS的len属性里面,这样的目的是重用一部分string.h里面定义的函数。
那SDS和C语言的字符串有什么区别,又有什么优势?先看SDS无非多了两个变量记录这个字节数组的属性,C语言获取字符串长度需要遍历整个字符串并计数,时间复杂度为O(n),SDS则为O(1)。C
字符串会产生缓冲区溢出,如果在调用strcat函数之前没有分配内存,可能会导致本来不属于这个字符换的内存空间被修改。如果对C字符串进行截取,比如trim操作,忘记释放内存,则又会导致内存泄漏,所以对C字符串的操作要更多的对内存进行分配和释放。

SDS解决了上面的问题,实际上是Redis对上面的问题进行了一定的封装:

1.空间预分配

空间预分配用于优化SDS的字符串增长操作:当SDS的API对SDS进行修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间。
具体如下:如果对SDS进行修改之后,SDS的长度小于1MB,那么程序分配和len属性同样大小的未使用空间,这时len=free;如果大于1MB,那么程序会分配1MB的未使用空间,那么SDS的buf数组实际长度为 len+1MB+1byte。这种预分配可以减少内存分配的次数,属于以空间换时间。

2.惰性空间释放

聪明的你一定一看名字就知道啥意思了,用于优化SDS的字符串缩短操作,程序不立即使用内存重分配回收缩短后多出来的字节,在修改buf的同时修改len 和 free,从而记录已用和未用空间,并等待将来使用。与此同时,SDS提供了响应的API,让我们有需要时,真正的释放SDS未使用的空间。

3.二进制安全

对C字符串了解的,一定知道其除了末尾可以有空字符,字符串里不能包含空字符,并且必须符合某种编码(ASCII码),从而限制了C字符串只能保存文本数据,不能保存图片、音频等等二进制数据。SDS可以,它是二进制安全的,虽然Redis一般用于保存文本数据,但是数据库用来保存二进制数据的场景也不少见,我在工作中就遇到一个场景,A站点生成了图片验证码,转成字节数组放入Redis,B站点和A共享Redis集群,B站点取出该字节数组,还原成图片流,并在浏览器输出。

SDS还提供了一些具体操作的API,如果不是在Redis上做开发的C语言程序员,一般用不到那些API,这里就不做过多的研究,有兴趣的读者可以阅读相关书籍或者源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值