Redis是一个基于内存的数据库,所有的数据都存储在内存中。所以如何优化存储,减少内存空间占用是一个非常重要的话题。精简键名和键值是最直观的减少内存占用的方式,如将键名very.important.person:20改成VIP:20。
但有时仅凭精简键名和键值所减少的空间并不足以满足需求,这时就需要根据Redis内部编码规则来节省更多的空间。
Redis为每种数据类型都提供了两种内部编码方式,以散列类型为例,散列类型是通过散列表实现的,这样就可以实现O(1)时间复杂度的查找、赋值操作,然而当键中元素很少的时候,O(1)的操作并不会比O(n)有明显的性能提高,所以这种情况下Redis会采用一种节约内存但性能稍差(获取元素的时间复杂度为O(n))的内部编码方式。
内部编码方式的选择对于使用者来说是透明的,Redis会根据实际情况自动调整。当键中元素变多时Redis会自动将该键的内部编码方式转换成散列表。如果想查看一个键的内部编码方式可以使用”object encoding”命令,例如:
127.0.0.1:6379> lpush list a
(integer) 2
127.0.0.1:6379> object encoding list
"ziplist"
Redis的每个value都是使用一个redisObject结构体保存的,redisObject的定义如下:
typedef struct redisObject
{
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
其中type字段表示的是value的数据类型,取值可以是如下内容:
/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
encoding字段表示的就是value的内部编码方式,取值可以是:
#define REDIS_ENCODING_RAW 0 /* Raw representation */
#define REDIS_ENCODING_INT 1 /* Encoded as integer */
#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
#define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */