Redis数据结构:string hash

Redis有5种数据结构:String、List、Hash、Set和Sorted Set。

这里仅仅谈String和Hash.

Redis没有使用C语言传统的字符串,而是使用了SDS(simple dynamic string)

struct sdshdr {
     int len;    //字符串长度,不含空字符
     int free;   // 未使用字节的数量,不含空字符
     char buf[];  // 保存字符串,最后一个字符是空字符
}

C语言字符串用长度是N+1的字符数组表示长度是N的字符串,字符数组最后一个元素是空字符'\0'。这种字符串的长度是静态的,所以安全性较差,当字符串扩展时容易发生溢出(buffer flow),这样会覆盖其他内存。而sds会检查扩展时的空间是否足够,所以说sds是一种可以动态扩展的字符串,通过预分配内存来实现扩展:

  1. 如果扩展之后,sds的长度len小于1M,那么将分配和len相同的空闲内存,此时buf数组的长度是len + len + 1.

  2. 如果扩展之后,sds的长度大于等于1M,那么将分配1M的空闲内存,此时buf数组的长度是len + 1MB + 1.

当sds缩短时不会释放空闲内存,这样避免重复分配内存。只有在真正有需要时,才会真正释放未使用的内存。

C语言字符串只能保存文本数据,不能保存二进制文件的数据,因为二进制文件中可能包含空字符,而sds却可以自如存取。

sds用途不仅仅是实现字符串,还被用作缓冲区,比如实现AOF缓冲区和客户端输入缓冲区。

Hash是一种保存键值对(key-value pair)的数据结构,其实现与JDK HashMap类似。

动态数据结构都要考虑扩展的策略。比如Hash,当K-V较多时,会影响性能,这就需要把原来的数据结构扩展,也就是rehash。

负载因子 load_factor = node_size / hash_size (有几个桶)

当load_factor大于等于1时,会扩展hash,当小于0.1时,会收缩hash。

当扩展时,hash_size 是 第一个大于等于node_size * 2^n

当收缩时,hash_size是 第一个大于等于node_size * 2^n

redis内有两个hash,互相作为rehash的对象。redis采用的是渐进式rehash,不会一次性、集中式地完成,而是分多次、渐进式地完成。这是因为hash中的元素一般会比较多,这样做的成本太高,所以要分摊到每次操作中。

在rehash的过程中,hash的操作是在两个表中进行的,比如查找,如果在第一个表中找不到,会在第一个表中寻找。

2017-12-26再阅:

本文看似简单,但涉及到不少重要的计算机思想。

  1. 数据结构大小(所占内存)动态扩展或者动态收缩,这种扩展策略可能分不同层级
  2. C语言字符串的缺点:容易溢出,不能存储某些特殊字符。
  3. 批量操作和逐个操作各有利弊,前者胜在一次集中处理,后者胜在多次渐进分摊。
  4. 2015年,架构中使用AB结构,现在在数据结构这一层次上也看到了这种设计。

2019-07-24
静态的数据结构能应对的非常简单,就是因为单一,而动态的数据结构则能应对多种场景。具体的例子是C语言字符串和Redis的SDS

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站...
    Java架构阅读 1,299评论 1 16
  • 前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站...
    小陈阿飞阅读 813评论 0 1
  • 概述 YYKit是集大成者的第三方表现,堪称国内最优秀的框架。因此,在YYKit中有太多的技术点值得挖掘思考,本文...
    sindri的小巢阅读 13,751评论 8 104
  • 来一波表情包亲,喜欢就收下,在文章的最下端哦 https://mp.weixin.qq.com/s?__biz=M...
    大力学姐阅读 944评论 0 0
  • 竹外桃花三两片,片片落成伊人面。 情深再无故人还,风浅流年知心乱。
    商南萧阅读 142评论 0 0