Redis对象与持久化

    xiaoxiao2022-07-14  143

    原文章地址

    Redis对象与持久化

    Redis使用5种对象来实现键值对数据库:字符串,列表,哈希,集合,有序集合对象。使用这么多对象方便了在不同情景下的使用。

    对象的类型与编码

    typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层数据结构的指针 void *ptr; //引用计数 int refcount; //空转时长 unsigned lru:22; } robj;

    type即上述提到的五种对象类型,encoding属性记录了所使用的编码,也就是该对象使用了什么数据结构,使用引用计数实现内存回收机制,当计数为0时会释放该对象,空转时长记录最后一次命令访问此对象的时间。

    type表示是什么对象

    类型常量对象名称REDIS_STRING字符串对象REDIS_LIST列表对象REDIS_HASH哈希对象REDIS_SET集合对象REDIS_ZSET有序集合对象

    编码:

    类型编码对象Stringint整数值实现Stringembstrsds实现 <=32 字节Stringrawsds实现 > 32字节Listziplist压缩列表实现Listlinkedlist双端链表实现Setintset整数集合使用Sethashtable字典实现Hashziplist压缩列表实现Hashhashtable字典使用Sorted setziplist压缩列表实现Sorted setskiplist跳跃表和字典

    对象

    字符串对象

    字符串的编码可以是int,raw,embstr。

    int表示整数raw用以存储较长的字符串,需要两次分配内存空间,也需要两次释放内存空间embstr用来表示较短的(<=32KB)的字符串,embstr分配内存空间只需要一次,释放也只需要一次

    编码的转换:

    当执行命令使这个对象存的不再是整数,就会转换为raw对于embstr,没有更改的操作,如果需要修改,会将其转换为raw

    int型的string:

    raw型的string:

    embstr型的string:

    列表对象

    列表的编码可以是ziplist,linkedlist。使用压缩列表主要是为了节省空间,只适用于较短的数据。

    编码转换:

    列表对象保存的素有字符串元素都小于64字节列表中的元素个数小于512个

    满足上述两个条件使用ziplist,否则使用linkedlist。不过这个条件是可以修改的。 ziplist型的列表:

    linkedlsit型的列表:

    哈希对象

    哈希对象的编码可以是ziplist或hashtable。

    使用ziplist时:

    添加哈希对象时先将键添加到压缩列表的尾部,再将值添加到尾部。键值总是挨在一起,键在前值在后先添加的总是在前,后添加的总是在后

    使用hashtable:

    每一个键都是字符串对象,对象中保存了键值对的键每一个值都是一个字符串对象,对象中保存了键值对的值

    编码转换:

    哈希对象保存的所有键值对的字符串对象都小于64KB哈希对象中的键值对的数量小于512

    满足上述两个条件时使用ziplist,当然条件可以更改。

    ziplist的哈希:

    hashtable型的哈希:

    集合对象

    集合对象的编码是intset或者hashtable。

    编码转换:

    所有元素都是整数集合中元素的数量小于512个 满足上述两个条件使用intset,第二项条件的参数可以更改。

    intset型的集合:

    hashtable型的集合(值为空):

    有序集合对象

    有序集合对象的编码可以是ziplist或者skiplist。

    使用压缩列表时,集合内的元素按照分值排序。

    skiplist编码的有序集合对象使用zset结构作为底层实现:

    typedef struct zset{ zskiplist *zsl; dict *dict; } zset;

    使用zskiplist和dict是为了均衡有序和查找的效率,如果只是用dict那么在范围查找时需要每次排序,如果使用zskiplist查找时间复杂度会是O(logN)。使用两种数据结构可以时它们的时间复杂度都是O(1),典型的空间换时间。

    编码转换:

    有序集合对象元素的数量小于128个所有元素的长度小于64字节 满足上诉两个条件使用ziplist,可以更改条件的参数

    ziplist型的有序集合:

    skiplist型的有序集合:

    类型检查与命令多态

    有一些命令对于所以对象都适用,这就是命令多态,实现命令多态依赖于类型判断,即判断当前是什么类型。

    内存回收

    使用引用计数法:当创建一个对象时,给该对象的refcount赋值为1,当该对象被一个新程序引用时refcount+=1,当不再被一个程序引用时refcount-=1,当refcount==0时释放此对象。

    对象共享

    对象共享会极大的节约空间,Redis在初始化服务器的时候会创建10000个字符串对象:0-9999来共享。

    对象的空转时长

    lru属性:记录该对象最后一次被命令程序访问的时间,这个属性会被用于内存回收。

    持久化

    由于Redis是内存数据库,因此为了防止服务器进程退出而数据消失,需要对数据库进行持久化。

    持久化的方式有两种:RDB,AOF。

    RDB

    创建

    有两个命令可用于生产RDB文件,一个是SAVE,BGSAVE。

    SAVE会阻塞服务器进程直到创建完成,在此期间服务器不会处理任何命令请求。BGSAVE不会阻塞,执行BGSAVE命令时会创建一个子进程来完成持久化。都不会包含过期键

    载入

    Redis服务器启动时会自动加载RDB文件,不过如果开启了AOF功能,会优先使用AOF还原数据库状态。

    AOF

    AOF通过保存Redis执行的写命令来记录数据库状态。

    创建

    将执行的命令添加到一个缓冲区中,再将缓冲区的内容写入到文件中。

    载入

    创建一个伪客户端,执行AOF中的命令,直到执行完所有的命令。

    AOF重写

    AOF文件会随着执行写命令的增加而增加,过于臃肿,因此可以对其重写:合并命令,删除对过期键的命令。在执行BGREWRITEAOF时,会创建一个缓冲区,其中写入了在重写期间执行的命令,在重写完成之后再追加到重写的AOF文件之后保证一致性。

    最新回复(0)