首页 > 技术相关, 数据库 > 非关系型数据库(NoSQL)Redis实现之String实现

非关系型数据库(NoSQL)Redis实现之String实现

2011年6月25日 sigma 发表评论 阅读评论

Redis是一个性能非常优异的非关系型数据库,有测试表明,在Linux 2.6, Xeon X3320 2.5Ghz配置的系统中,Redis性能能够达到SET操作每秒钟 110000 次,GET操作每秒钟 81000 次。

其本质上是一个键值(Key-Value)数据库,类似于memcache,但其支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。据新浪微博首席架构师透露,新浪微博系统里就采用了Redis数据库。Redis的最新版本是2.2.11,现在开发非常活跃,更新非常快。

Redis有四种数据类型:string,list,set及sorted set。其中,String是最基本的数据类型,也是其他几种数据类型的基础,其中所有的key值就是String类型的。下面介绍string类型的数据结构及操作:

Redis的String实现是在sds.c文件中实现的(sds代表Simple Dynamic Strings)。

String的结构体定义sdshdr在sds.h中定义:

 struct sdshdr {
    long len;
    long free;
    char buf[];
};
 

 

buf区域是存储真正的string值,len域是为了能够在O(1)时间获取buf的长度,free是指buf中的剩余比特数。

在sds.h中,还定义了一个字符串指针类型,名为sds,意思是指向buf区的指针:

 typedef char *sds;
 

在sds.c中,有一个创建redis string的函数,该函数会在内存中创建一个sdshdr结构体,并且返回buf区域的指针,可以实现快速的创建Redis string并返回sh-buf:

 sds sdsnewlen(const void *init, size_t initlen) {
    struct sdshdr *sh;

    sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
#ifdef SDS_ABORT_ON_OOM
    if (sh == NULL) sdsOomAbort();
#else
    if (sh == NULL) return NULL;
#endif
    sh->len = initlen;
    sh->free = 0;
    if (initlen) {
        if (init) memcpy(sh->buf, init, initlen);
        else memset(sh->buf,0,initlen);
    }
    sh->buf[initlen] = '\0';
    return (char*)sh->buf;
}
 

给定一个buf,在sds.c中第一个函数快速的返回该buf对应Redis string的len值函数sdslen:

 size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    return sh->len;
}
 

在这里解释下,结构体的sizeof值不包括指针的值,我原来以为指针是int型(32位机器),应该算一个int,而事实上,通过实验,sdshdr的sizeof值就是len+free的size。所以上面s-(sizeof(strcut sdshdr))就是指向原来的sdshdr结构体的指针。

在这里,很多人也许对sdsnewlen以及sdslen这两个函数觉得奇怪,为什么sdsnewlen不直接返回sdshdr结构体,sdslen为什么不直接用shshdr做参数。个人感觉这里为了提高性能,在sdsnewlen中,直接返回最常需要的值:buf区的内容(比如我们查询key,我们不会关注len以及free,一般都是buf的值);而在sdslen中,由于我们经常使用buf,所以也只知道buf的指针,而不知道sdshdr的指针,因此,直接用sds指针方便。

另外,我看代码时有另外一个疑问,sizeof这东西会不会很占时间,后来想了想,对于这种定长的结构(包括元数据类型,数据,结构体等),sizeof应该是编译时确定的,直接静态链接,不会消耗运行时间。因此对性能没有影响。后来上网查了下,并自己写了些代码编译成汇编码,确认了我的想法。

本文作者: Sigma    在新浪微博关注SigmaSigmaWeibo    RSS订阅本博客
本文链接: http://www.sigma.me/2011/06/25/redis-string-implement.html
本博客采用知识共享署名—非商业性-禁止演绎使用3.0协议进行许可,转载请保留作者和原文链接。

  1. 2011年6月29日01:14 | #1

    @Yan

    你怎么又玩SQL sever了。。。

  2. 2011年6月29日01:05 | #2

    你怎么对NoSQL数据库这么感兴趣?这两天在搞SQL Server性能调优,苦逼啊。

  3. 2011年6月27日03:23 | #3

    我来逛逛,顺便帮博主顶一下,嘿嘿。

  4. 2011年6月28日06:15 | #4

    第一次来观摩此博客 留个记号 方便下次造访 谢谢博主

  5. 2011年7月6日15:00 | #5

    谢谢分享!

  6. 张禄
    2014年2月25日21:50 | #6

    请问struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)))这句看不懂,到底是怎么实现sds到sdshdr的???

  7. 张禄
    2014年2月25日22:36 | #7

    @张禄 我懂了,不过谢谢你的文章。它是根据地址来找到一个sdshdr结构

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

无觅相关文章插件,快速提升流量