幸运蛋蛋pc开奖
这篇文章主要给大家介绍了关于Redis字符串对象的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

字符串对象

字符串数据类型是Redis里最常用的类型了,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合?#23454;?#32534;码。字符串对象的编码一共有三种: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

当字符串对象的值是一个字符串?#39029;?#24230;大于44字节时,字符串对象的编码就会是OBJ_ENCODING_RAW编码。具体结构在下文。

OBJ_ENCODING_EMBSTR

当字符串对象的值是一个字符串?#39029;?#24230;小于等于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编码的数据都存储在连续的内存?#24076;琌BJ_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 44
robj *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的设计和实现。这也就导致了面试很?#38480;危?#22240;为面试官最?#19981;段试?#29702;相关的东西了,所以以后学习技术的时候不要从实战类的书籍开始了,还是先看懂原理比较好。

参考资料

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


总结

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

最新资讯
转型阵痛中的世联行押注“互联网+”有戏吗?

转型阵痛中的世联行押

世联行在互联网+业务上开?#35745;?#39057;“发力?#20445;?#35851;求新的突破
“剪刀手”一出无隐私? 网络安全召唤AI反制技术

“剪刀手”一出无隐私

如需真正地在信息内容真?#31508;?#21035;中广泛且有效地应用AI技
中国电信明年?#20064;?#24180;推出 2000元以内5G手机

中国电信明年?#20064;?#24180;推

陆良军称,2020年中国5G手机将达到1.7亿部,中国电信将占6
拼价格、抢落地订单 2019年地图厂商圈地自动驾驶

拼价格、抢落地订单 2

一场关于自动驾驶的新战役正在地图领域打响,大数据背后
中国网络安全产?#21040;?#36229;600亿元 5G时代需要“零信任”

中国网络安全产?#21040;?#36229;

5G、AI、工业互联网的发展对网络安全要求越来越高,企业
失速的共享办公:WeWork上市遇阻戳破行业盈利泡沫

失速的共享办公:WeWork

严峻的市场环境折射出一级市场寒冬下,资本越发冷静理智
最新文章
安装redis(windows和Ubuntu)详解

安装redis(windows和Ub

这篇文章主要介绍了Redis在Ubuntu和Windows下的安装,文
Redis字符串对象实用笔记

Redis字符串对象实用

这篇文章主要给大家介绍了关于Redis字符串对象的相关
Redis精确去重计数方法(咆哮位图)

Redis精确去重计数方

这篇文章主要给大家介绍了关于Redis精确去重计数方法(
在Redis集群中使用pipeline批量插入的实现方法

在Redis集群中使用pip

这篇文章主要介绍了在Redis集群中使用pipeline批量插
Redis实战记录之限制操作频率

Redis实战记录之限制

这篇文章主要给大家介绍了关于Redis实战记录之限制操
redis中热key问题该如何解决

redis中热key问题该如

这篇文章主要给大家介绍了关于redis中热key问题该如何
幸运蛋蛋pc开奖 欢乐生肖平台哪个好 山东时时图 准确的后一万5个万能码 广西11选5最新一期 天天中彩老版 3b今晚开奖号走势图 手机版黄金岛官方下载 甘肃快三号码遗漏天数 北京时时高频票 浙江福彩12选五开奖一定牛