0%

redis五种基本数据类型底层实现

东临碣石,以观沧海。水何澹澹,山岛竦峙。树木丛生,百草丰茂。秋风萧瑟,洪波涌起。日月之行,若出其中。星汉灿烂,若出其里。幸甚至哉,歌以咏志。 —— 汉·曹操 《观沧海》

一、介绍

  1. redis是以键值对存储数据的,所以对象又分为键对象和值对象,即存储一个key-value键值对会创建两个对象,键对象和值对象。

  2. 键对象总是一个字符串对象,而值对象可以是五大对象中的任意一种。

  3. 常用命令

    • type key:查看key所属数据类型
    • object encoding key:显示redis五大数据类型的底层数据结构
    • object idletime key:获得其lru时间
    • object refcount key:被引用次数

二、总览

  1. 五种数据类型底层数据结构总览
类型 编码
STRING(字符串) INT(长整型)
STRING(字符串) EMBSTR(简单动态字符串)
STRING(字符串) RAW(简单动态字符串)
LIST(列表) >=3.2版本快表QUICKLIST,<3.2版本则为双端链表LINKEDLIST或压缩列表ZIPLIST
SET(集合) INTSET(整数集合)
SET(集合) HT(字典)
ZSET(有序集合) ZIPLIST(压缩列表)
ZSET(有序集合) SKIPLIST(跳表)
HASH(哈希) ZIPLIST(压缩列表)
HASH(哈希) HT(字典)
  1. 存入key-value键值对时并不会指定对象的encoding,redis会根据不统的使用场景来为一个对象设置不同的编码,以达到节约内存、加快访问速度等目的。

  2. redis中的每个对象都是由redisObject结构来表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct redisObject{

//类型
unsigned type;// 4 bits

//编码
unsigned encoding;// 4 bits

//记录最后一次被程序访问的时间
unsigned lru;// 24 bits(3 bytes)

//引用计数
int refcount;// 4 bytes

//指向底层数据结构的指针
void *ptr; // 8 bytes(64位操作系统)
}robj
  1. RedisObject对象头需要占据16字节的存储空间

    • 不同的对象具有不同的类型type(4bit)
    • 同一个类型的type会有不同的编码方式encoding(4bit)
    • 为了记录对象的LRU信息,使用了24bit来记录LRU信息
    • 每个对象都有个引用计数,当引用计数为零时对象就会被销毁内存被回收。
    • ptr指针将指向对象内容(body)的具体存储位置。
  2. RedisObject对象个属性解读

    • type属性:记录了对象的类型,即redis五大数据类型,通过命令type key可得到
    • encoding属性和*prt指针:对象的prt指针指向对象底层的数据结构,而数据结构由encoding属性来决定,通过命令object encoding key可得到,每种数据类型的对象都至少使用了两种不同的编码
    • lru:该属性记录该对象最近一次被访问的时间,如果服务器打开了maxmemory选项,并且服务器用于内存回收的算法为volatile-lru或allkeys-lru,当占用内存超过maxmemory设置的上限时,最早被访问的会先被释放。
    • refcount:该属性常用于垃圾回收和对象共享
      • 用于垃圾回收,使用引用计数法实现,该属性值表示对象被多少个程序引用,当对象被创建时该属性值为1,当该值为0时对象占用的内存会被回收
      • 用于对象共享,比如Redis在初始化服务器时就会创建0到9999的字符串对象用于对象共享,每当使用set命令创建一个新字符串对象,如果要创建的字符串已经存在则将指向值的指针指向该字符串对象,并将该对象的refcount加1