我命由我,不由天!


  • 搜索
prometheus docker golang linux kubernetes

redis-字符串内部(二十三)

发表于 2021-06-06 | 0 | 阅读次数 394

丝分缕析——探索“字符串”内部

Redis中的字符串是可以修改的字符串,在内存中是以字节数组的形式存在的。C语言里面的字符春标准形式以NULL作为结束符,但在Redis里面字符串不是这么表示的。因为获取NULL结尾的字符串要strlen函数,复杂度为O(n)。

Redis的字符串叫“SDS”,也即是Simple Dynamic String。它的结构是一个带长度信息的字节数组。

struct SDS<T>{
	T capacity; // 数组容量
  T len;      // 数组长度
  byte flags; // 特殊标志位,不用理睬它
  byte[] conten; // 数组内容
}

capacity 表示分配数组的长度,len表示字符串的实际长度。字符串是可以修改的,要支持append操作,如果数组没有冗余空间,追加操作必然涉及分配新数组,然后将旧内容复制过来,在append新内容。

SDS结构使用泛型T,而不直接使用int,因为当字符串比较短时,len和capacity可以使用byte和short来表示,Redis为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。

Redis规定字符串的长度不得超过512MB,创建字符串时len和capacity一样长,不会多分配冗余空间,因为大多数场景下,不会使用append操作来修改字符串。

embstr VS raw

Redis 的字符串又两种存储方式,在长度特别短时,使用embstr 形式存储,而当长度超过44字节时,使用raw形式存储。

set codehole ndosdoand
debug object codehole

encoding字段,有存储形式

Redis对象头结构

struct RedisObject{
	int4 type; 
	int4 encoding;
	int24 lru;
	int32 refcount;
	void *ptr;
}robj;

不同的对象具有不同的类型type,同一个类型的type会有不同的存储形式encoding。为了记录对象的LRU信息,使用24个bit来记录LRU信息。每个对象都是引用计数,当引用计数为零时,对象就会被销毁,内存被回收。ptr指针将指向对象内容的具体存储位置。这样一个RedisObject对象头结构需要占据16字节的存储空间。

再看SDS结构体的大小,在字符串比较小时,SDS对象头结构的大小是capacity+3。

struct SDS {
	int8 capacity; // 1byte
  int8 len;      // 1byte
  int8 flags;    // 1byte
  byte[] conten; // 数组内容
}

embstr存储形式是这样一种存储形式,它将RedisObject对象头结构和SDS对象连续存在一起,使用malloc方法一次分配,而raw存储形式不一样,需要使用两次malloc方法,两个对象头在内存地址上一般是不连续的。

image.png
而内存分配器jemalloc、tcmalloc等分配内存大小的单位都是2/4/8/16/32/64字节等,为了容纳一个完整的embstr对象,jemalloc最少会分配32字节的空间,如果字符串再稍微长一点,那就是64字节的空间。如果字符串总体超出64字节,Redis认为是一个大字符串,不再适合使用emdstr形式存储,而使用raw形式

当内存分配器分配64字节空间时,这个字符串长度最大可以是 44 字节

SDS结构体中的content中的字符串是以NULL结尾的字符串,之所以多出这样一个字节,是为了便于直接使用glibc的字符串处理函数,以及便于字符串的调试打印输出。

16 字节(RedisObject对象头)+ 3字节(SSD对象)+1字节(NULL结尾)= 20字节

扩容策略

在字符串长度小于1MB之前,扩容空间采用加倍策略,也就是保留100%冗余空间。当字符串长度超过1MB之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配1MB大小的冗余空间

  • 本文作者: Dante
  • 本文链接: https://gaodongfei.com/archives/redis-字符串
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
redis-lru(二十二)
redis-hash结构(二十四)
  • 文章目录
  • 站点概览
Dante

Dante

119 日志
5 分类
5 标签
RSS
Creative Commons
0%
© 2023 Dante
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4
沪ICP备2020033702号