Redis基本数据结构

Redis有5种基本的数据结构,分别是

String: 字符串

Hash: 散列

List: 列表

Set: 集合

Sorted Set: 有序集合

我们会在Redis专栏的文章中去了解它们的底层原理以及基本使用方法,我们章先对String扩展讨论

明确:Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。不同类型的数据结构的差异就在于 value 的结构不一样。但是这个key使用的结构,都是字符串类型。

String

String redis存储 redis的string存储原理_String redis存储


String 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M,String类型的数据底层为sds(简单动态字符串)和直接存储实现,但其编码方式可以是int、raw或者embstr,区别在于内存结构的不同

直接存储的数据

1.int编码

value保存的是整数值,并且这个正式可以用long类型来表示,那么其就会直接保存在redisObject的ptr属性里,并将编码设置为int,下图为存储value的数据结构

String redis存储 redis的string存储原理_Redis_02

SDS(简单动态字符串)

熟悉Redis的都知道,Redis是使用C语言开发,所以在Redis中,定义了一个字符串格式,也就是我们现在要说的SDS(动态字符串)

sdshdr是存储SDS字符串的一个结构源码

//定义了一个char 指针
typedef char *sds;

//lsb 代表有效位的意思
//__attribute__ ((__packed__)) 代表struct 采用手动对齐的方式。
struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

简略图如下

String redis存储 redis的string存储原理_Redis_03

上面的结构图与源码解释:

alloc:buf[] 分配的长度

len:字符串的长度

flag:

// 五种header类型,flags取值为0~4
#define SDS_TYPE_5  0
#define SDS_TYPE_8  1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

buf[]字节数组,实际存放字符串的位置

大家观察一下,源码中变化的时len和alloc,sds结构一共有五种Header定义,目的是为了满足不同大小的字符串可以使用不同的herder,达到节省内存的目的

它和java的String类型还不一样,java的字符串对象一经定义不能修改,但是SDS是可以修改的字符串,我们来看看它的原理,它主要类似于java的ArrayList,它采用预分配空间的方式来避免字符串频繁改变导致的内存分配回收,分配原则:当字符串的长度小于1MB时,分配给该字符串的空间为该字符串长度的两倍,大于1MB时,分配给该字符串的空间为该字符串长度+1MB

SDS是以len字段来判断是否到达字符串末尾,并不是以**\0**来判断字符串结尾位置,也就是说 sds是二进制安全的,可以存放任何二进制数据

清空SDS是将len设为0,并不回收该key所对应的空间

查询该字符串长度直接返回len即可,时间复杂度为O(1)

下面来说说SDS的两种编码模式

raw

字符串保存的大于32字节的字符串值,简单动态字符串(SDS)结构,并将编码设置为raw,此时内存结构与SDS结构一致,内存分配次数为两次,创建redisObject对象和sdshdr结构

embstr编码

字符串保存的小于等于32字节的字符串值,简单的动态字符串(SDS结构),但是内存结构做了优化,用于保存变动频繁的字符串;内存分配也只需要一次就可完成,分配一块连续的空间即可

int编码和embstr编码如果做追加字符串等操作,满足条件下会被转换为raw编码;embstr编码的对象是只读的,一旦修改会先转码到raw。

加油,这就是我们今天讲的内容啦,谢谢大家的支持,能给个赞赞赞赞赞嘛,你们的鼓励就是我的动力哟

String redis存储 redis的string存储原理_字符串_04


完成:TO: 2021/4/02 20:12