【LSP】REDIS教学基础篇——REDIS基础数

张小枫   ·   发表于 1个月前   ·   编程代码

Redis是C语音编写的基于内存的数据结构存储系统。它可以当作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings),
列表(lists), 字典(dictht),集合(sets), 有序集合(sorted sets)。通常我们在项目中可以用它来做缓存、记录签到数据、分布式锁等等。
要使用Redis首先我们来了解一下它的五种基础数据结构。


1.字符串(strings)
Redis拥有两种字符串表述方式,其一是C语言传统的字符串表述方式,常用Redis代码中字符串常量等一些无需对字符串进行修改的地方。

第二种是自己封装了一种名为简单动态字符串(simple dynamic string)简称SDS的抽象类型,这个才是我们存储字符串时所使用的对象,等同于java中的StringBuilder。

SDS的结构如下:

复制代码
struct sdshdr{
//记录字符数组中已经使用的字节数量 即是字符串的长度
int len;
//记录字符数组中未使用的字节数
int free;
//字符数组 用于保存字符串
char buf[];
}
复制代码
结构如下图所示:


至于Redis为什么要使用这样的结构,其实和java使用StringBuilder的思维是大相径庭。为了方便修改和提升性能。比如C的字符串获取字符串长度时要遍历整个字符数组。
其时间复杂度是O(n),而SDS则可以直接获取len,时间复杂度为O(1)。修改字符串N次字符串并且字符串和以前的长度不一致时,C普通字符串长度必然需要执行N次内存重分配。
而SDS存在预扩容,所以最多需要执行N次内存分配。
注:与扩容其本质和list类似,在需要的长度大于现在数组的长度时,会触发字符串扩容,当数据小于1M时,字符数组每次扩容都是其原来容量的2倍。1M后每次扩容新增1M容量。

2.列表
Redis中的列表相当于java中的LinkedList,它是一个双向链表,插入和删除都拥有极好的性能,时间复杂度为O(1),但是随机查找比较慢,时间复杂度为O(n)。虽然可以将列表
当成一个LinkedList,但是在Redis内部列表并不是一个简单的双向链表的实现。在列表保存元素个数小于512个且每个元素长度小于64字节的时候为了节省内存其底层实现是一块
连续内存来存储,称之为ziplist压缩列表。当不满足之前的两个条件时则改用quicklist快速列表来存储原元素。

ziplist压缩列表:
压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构。一个压缩列表可以包含任意多个节点,每个节点保存一个字节数组或者一个整数值。

复制代码
struct ziplist{
int32 zlbytes;
int32 zltail_offset;
int16 zllemhth;
T[] entries;
int8 zlend;
}
复制代码
其结构如下图所示:



节点结构如下:

struct entry{
int previous_entry_length;//前一个原数的字节长度
int encoding;//元数类型编码
optional byte[] content;//元素内容
}

这里有一个点要注意,如果entryX+1和起身后的节点的长度都都在250~253个字节之间的话,如果entryX长度变成了254个字节。那么entryX+1中的previous_entry_length将扩容成5个字节,

这将导致entryX+1的整体长度也会大于254个字节,引起entryX+2个字节中的previous_entry_length也发生扩容,使得entryX+2的整体长度也超过254。并对后面的节点造成连锁影响这个就叫连锁更新。

将会对性能造成一定的影响。

quicklist快速列表:

快速列表是ziplist和linkedlist的混合体。它将linkedlist按段切分,每一段使用ziplist让内存紧凑,多个ziplist之间使用双向指针串接起来。为了进一步节省空间。Redis还会对ziplist进行压缩,

使用LZF算法压缩。可以选择压缩的深度,默认的压缩深度是0既不压缩。有时候为了节省空间,但是又不想因为压缩而影响取出和放入的性能,可以选着压缩深度为1或者2。

既首尾的第一个或者首尾的第一个和第二个不压缩。

0 Reply   |  Until 1个月前 | 1227 View
LoginCan Publish Content