千家信息网

Redis字符串对象实用笔记

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,字符串对象字符串数据类型是Redis里最常用的类型了,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合适的编码。字符串对象的编
千家信息网最后更新 2026年11月03日Redis字符串对象实用笔记

字符串对象

字符串数据类型是Redis里最常用的类型了,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合适的编码。字符串对象的编码一共有三种:int、raw、embstr。

Redis对象

Redis用统一的数据结构来表示一个对象,具体定义如下:

typedef struct redisObject { unsigned type:4; unsigned encoding:4; // 当内存超限时采用LRU算法清除内存中的对象 unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or       * LFU data (least significant 8 bits frequency       * and most significant 16 bits access time). */ // 该对象被引用数 int refcount; // 对象的值指针 void *ptr;} robj;

其中type字段代表对象的类型,取值一共有7种:

/* A redis object, that is a type able to hold a string / list / set *//* The actual Redis Object */#define OBJ_STRING 0 /* 字符串对象. */#define OBJ_LIST 1  /* 列表对象. */#define OBJ_SET 2  /* 集合对象. */#define OBJ_ZSET 3  /* 有序集合对象. */#define OBJ_HASH 4  /* 哈希对象. *//* The "module" object type is a special one that signals that the object * is one directly managed by a Redis module. In this case the value points * to a moduleValue struct, which contains the object value (which is only * handled by the module itself) and the RedisModuleType struct which lists * function pointers in order to serialize, deserialize, AOF-rewrite and * free the object. * * Inside the RDB file, module types are encoded as OBJ_MODULE followed * by a 64 bit module type ID, which has a 54 bits module-specific signature * in order to dispatch the loading to the right module, plus a 10 bits * encoding version. */#define OBJ_MODULE 5 /* 模块对象. */#define OBJ_STREAM 6 /* 流对象. */

然后是encoding字段,代表着对象值的实际编码类型,取值一共有11种:

/* Objects encoding. Some kind of objects like Strings and Hashes can be * internally represented in multiple ways. The 'encoding' field of the object * is set to one of this fields for this object. */#define OBJ_ENCODING_RAW 0  /* 简单动态字符串 */#define OBJ_ENCODING_INT 1  /* long类型的整数 */#define OBJ_ENCODING_HT 2  /* 字典 */#define OBJ_ENCODING_ZIPMAP 3 /* 压缩字典 */#define OBJ_ENCODING_LINKEDLIST 4 /* 不再使用的旧列表,使用双端链表. */#define OBJ_ENCODING_ZIPLIST 5 /* 压缩列表 */#define OBJ_ENCODING_INTSET 6 /* 整数集合 */#define OBJ_ENCODING_SKIPLIST 7 /* 跳跃表和字典 */#define OBJ_ENCODING_EMBSTR 8 /* embstr编码的简单动态字符串 */#define OBJ_ENCODING_QUICKLIST 9 /* 编码为ziplist的列表 */#define OBJ_ENCODING_STREAM 10 /* 编码为listpacks的基数树 */

前面已经提到字符串对象只用到了long类型的整数、简单动态字符串、embstr编码的简单动态字符串这三种编码。

OBJ_ENCODING_INT

当字符串对象的值是一个整数且可以用long来表示时,字符串对象的编码就会是OBJ_ENCODING_INT编码。

可以看到,当值非常大的时候还是用OBJ_ENCODING_RAW来存储的。

OBJ_ENCODING_RAW

当字符串对象的值是一个字符串且长度大于44字节时,字符串对象的编码就会是OBJ_ENCODING_RAW编码。具体结构在下文。

OBJ_ENCODING_EMBSTR

当字符串对象的值是一个字符串且长度小于等于44字节时,字符串对象的编码就会是OBJ_ENCODING_EMBSTR编码。OBJ_ENCODING_EMBSTR编码和OBJ_ENCODING_RAW编码的区别主要有以下几点:

  • OBJ_ENCODING_RAW编码的对象在分配内存时会分配两次,分别创建redisObject对象和SDS对象。而OBJ_ENCODING_EMBSTR编码则是一次就分配好。
  • 同样的,OBJ_ENCODING_RAW编码的对象释放内存也需要两次,OBJ_ENCODING_EMBSTR编码则是一次。
  • OBJ_ENCODING_EMBSTR编码的数据都存储在连续的内存上,OBJ_ENCODING_RAW编码则不是。
/* Create a string object with EMBSTR encoding if it is smaller than * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is * used. * * The current limit of 44 is chosen so that the biggest string object * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44robj *createStringObject(const char *ptr, size_t len) { if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)  return createEmbeddedStringObject(ptr,len); else  return createRawStringObject(ptr,len);}

SDS

字符串是Redis里非常常见的类型,而用C实现的Redis和Java不一样。在C里字符串是用长度为N+1的字符数组实现的,且使用空字符串'\0'作为结束符号。获取字符串的长度需要遍历一遍,找到空字符串'\0'才知道字符串的长度,复杂度是O(N)。

如果有一个长度非常大的字符串,单线程的Redis获取它的长度就可能会阻塞很久,这是不能接受的,所以Redis需要一种更高效的字符串类型。

Redis实现了一个叫SDS(simple dynamic string)的字符串类型,其中有两个变量来分别代表字符串的长度和字符数组未使用的字符数量,这样就可以用O(1)的复杂度来获取字符串的长度了,而且同样也是使用空字符串'\0'作为结束符号。

struct sdshdr { // 字符串长度 int len; // 字符数组未使用的字符数量 int free; // 保存字符串的字符数组 char buf[];}

扩容机制

SDS在字符数组空间不足于容纳新字符串的时候会自动扩容。

如果把一个C字符串拼接到一个SDS后面,当字符数组空间不足时,SDS会先扩容到刚好可以容纳新字符串的长度,然后再扩充新字符串的空字符长度,最终SDS的字符数组长度等于 2 * 新字符串 + 1(结束符号'\0')。不过当新字符串的大小超过1MB后,扩充的空字符长度大小会固定为1MB。

之所以会有这个机制,是因为Redis作为一个NoSQL数据库,会频繁的修改字符串,扩容机制相当于给SDS做了一个缓冲池。把SDS连续增长N次字符串需要内存重分配N次优化成了SDS连续增长N次字符串最多需要内存重分配N次,这其实和Java里的StringBuilder实现思想是一样的。

后记

我看过两本关于Redis的书,里面都是讲Redis如何实战的,并没有讲Redis的设计和实现。这也就导致了面试很尴尬,因为面试官最喜欢问原理相关的东西了,所以以后学习技术的时候不要从实战类的书籍开始了,还是先看懂原理比较好。

参考资料

这是《Redis设计与实现》里字符串一节的总结。


总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。

字符 字符串 对象 编码 长度 类型 内存 数组 数据 空字符 分配 动态 整数 代表 字典 时候 机制 符号 存储 学习 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技 山东特亿宝互联网科技有限公司 中国互联网科技工作委员会毛军 鸠鸠互联网科技 互联网核心科技是什么 以房互联网科技 艾特科技互联网 安徽鑫晟辉互联网科技 互联网之后的科技是什么 互联网科技实习生岗位职责 南山科技园互联网公司有哪些 世界互联网科技公司市值排名 玉溪互联网科技怎么选 朱啸虎曾投资哪些互联网科技企业 互联网金融科技名词解释 滨湖区互联网智能科技产品有哪些 广州互联网高科技取餐柜 科技和互联网行业的特点 高科技和互联网的现代国家 每日互联网科技新闻 新华互联网科技 互联网巨头科技公司 北京互联网科技 互联网 科技服务平台 海南科技产业互联网平台 深圳市运趣互联网科技有限公司 互联网科技实习生岗位职责 沐思想互联网科技有限公司 互联网公司属于科技吗 保山浩联互联网科技有限公司
0