一 redis是怎样实现键值对数据库的
redis使用对象系统来实现键值对数据库,这个系统包括:字符串对象、列表对象、哈希对象、集合对象、有序集合对象。
二 redis对象定义(来自redis源码)
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
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;
2.1 变量解释
2.1.1 type: redis对象的类型,是一个常量,表示以上五种对象的任何一种。
/* The actual Redis Object */
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
2.1.2 ptr: 指向底层实现数据结构的指针
2.1.3 encodiing: 底层实现数据结构的类型,是一个常量,是某redis对象底层实现的一种。如字符串对象有三种实现(int、embstr、raw),encoding 代表其中一种。
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#
2.1.4 lru:记录该对象最后一次被访问的时间,与内存回收有关。
若服务器内存回收算法与lru有关,且打开了maxmemory选项,当服务器占用的内存数大于maxmemory时,空转时长(now-lru)比较高的部分键会被优先释放。
2.1.5 refcount: 引用计数,用于自动内存回收。
由于c语言没有自动内存回收功能,所以redis在对象系统中增加refcount来实现内存回收机制:
当创建redis对象时,引用计数为1;
当对象被新程序引用时,引用计数增1;
当不在被一个程序使用时,引用计数减1;
当引用计数变为0时,释放该对象内存。
ps: 由于键值对中,键的类型固定为字符串对象,所以通常我们说的字符串键,列表键、哈希键、均指的是值对象的类型。
2.2 在redis中创建一个键值对的过程。
2.2.1 执行命令:
set str1 "hello"
2.2.2 redis创建一个字符串对象,保存键的值:‘str1’,然后根据值本身的特征,根据某规则,选择encoding=‘embstr’,创建如下object(为表示清楚,采用js对象表示法):
{
type: 0,
encoding: 8,
lru: 1564126860413,
refcount: 1,
ptr: xxxxx// 指向embstr数据结构,该数据结构中保存着“hello”
}
2.2.3 redis判断值“hello”的类型,结合值的类型和特征,创建一个字符串对象。
三: 各redis对象的编码和使用情景。
3.1 字符串对象
字符串对象可使用的编码:
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
3.1.1 如果字符串对象保存的是一个整数值,且可以用long类型来表示,字符串对象会将整数值保存在ptr属性里面,并将对象的编码置为int;
image.png
3.1.2 如果字符串对象保存的是一个字符串值,并且字符串长度大于32字节,则使用sds来保存这个字符串值,并将对象的编码设置为raw;
image.png
3.1.3 如果字符串对象保存的是一个字符串值,并且字符串长度小于等于32字节;或者一个可以用long double类型表示的浮点数;则使用embstr方式保存这个字符串值,该编码调用一次内存分配函数来分配一块连续空间,空间中依次包含redisobject和sdshdr两个结构。
image.png
3.2 列表对象
列表对象可使用的编码:
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
3.2.1 当列表对象保存的所有字符串元素的长度都小于64字节;且保存的元素数量小于512个,使用ziplist编码
image.png
3.2.2 不满足3.2.1条件的,使用linkedlist编码
image.png
以上限制可以通过配置修改
3.3 哈希对象
哈希对象可以使用的编码
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
3.3.1 当哈希对象保存的所有键和值的长度都小于64字节,且键值对数量小于512个,使用ziplist编码
image.pngimage.png
3.3.2 不满足3.2.1条件的,使用hashtable编码
image.png
以上限制可以通过配置修改
3.4 集合对象
集合对象可以使用的编码
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
3.4.1 当集合对象所有元素都是整数值,且元素数量不超过512个,使用intset编码
image.png
3.4.2 不满足3.4.1条件的,使用hashtable编码
image.png
元素数量512可以通过配置修改
3.5 有序集合对象
有序集合对象可以使用的编码
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
3.5.1 当有序集合保存的元素数量小于128个,且所有元素成员的长度都小于64字节,使用ziplist编码
image.png
image.png
3.5.2 不满足3.5.1的,使用skiplist编码。同时保存在字典和跳跃表中。保存在字典中是为了满足按键查找分数。
image.png
以上限制可以通过配置修改
四:redis内存回收
redis对象的refcount和lru与内存回收有关。
参考:《redis设计与实现》
网友评论