浅析Redis常见数据类型 | 青训营

66 阅读10分钟

Redis是一个功能强大的内存数据存储系统,适用于多种场景和需求。合理使用和配置Redis可以提高应用程序的性能、可扩展性和稳定性。下面我将介绍一下Redis的基本数据类型,这个也是面试环节中比较重要的一部分。

字符串(String)

最基本的数据类型,可以存储任意类型的数据,例如文本、数字等。字符串数据类型的底层实现主要有两种方式:简单动态字符串(Simple Dynamic String,SDS)和压缩列表(Ziplist)。

  1. 简单动态字符串(SDS):SDS是Redis自己实现的一种字符串数据结构,它是一个带有一些附加功能的动态数组。SDS的结构包含字符串长度、已分配内存长度和字符数组。SDS的长度可以动态调整,当字符串长度增长或缩短时,SDS会自动进行内存的分配和释放。SDS还支持O(1)时间复杂度的字符串拼接、截取以及修改操作,因此在很多情况下,SDS比C语言的传统字符串更加高效。
  2. 压缩列表(Ziplist):压缩列表是一种紧凑且压缩的数据结构,用于存储较小的字符串或整数列表。压缩列表将连续的字符串或整数存储在一块连续的内存区域中,通过压缩和优化存储空间来节省内存。压缩列表在Redis中常用于列表和哈希等数据类型的底层实现。压缩列表的结构包含一个头部、多个节点以及一个尾部,每个节点可以存储一个字符串或一个整数。压缩列表支持O(1)时间复杂度的插入、删除和查找操作,适用于存储较小的数据。

在实际使用中,Redis会根据字符串的长度和内容来选择适合的底层实现方式。当字符串较短且没有特殊字符时,Redis会选择压缩列表作为底层实现,以节省内存空间。而对于较长或包含特殊字符的字符串,Redis会选择SDS作为底层实现,以提供更高的灵活性和性能。

列表(List)

有序的字符串元素集合,可以在列表的两端进行插入和删除操作,常用于实现队列和栈等数据结构。列表(List)数据类型的底层实现使用的是双向链表(Doubly Linked List)和压缩列表(Ziplist)两种方式。

  1. 双向链表(Doubly Linked List):双向链表是一种经典的数据结构,它由多个节点组成,每个节点包含一个值以及指向前一个节点和后一个节点的指针。在Redis中,当列表较长或包含较长的元素时,Redis会使用双向链表作为底层实现。双向链表支持在任意位置插入、删除和查找元素的操作,因此可以高效地支持列表的各种操作,如从头部或尾部插入和删除元素、按索引获取元素等。双向链表的缺点是占用较多的内存空间,因为每个节点需要额外的指针来维护链表的结构。
  2. 压缩列表(Ziplist):压缩列表是Redis自己实现的一种紧凑且压缩的数据结构,用于存储较小的字符串或整数列表。在Redis中,当列表较短且每个元素的长度较小时,Redis会选择压缩列表作为底层实现,以节省内存空间。压缩列表将连续的元素存储在一块连续的内存区域中,通过压缩和优化存储空间来节省内存。压缩列表支持在头部或尾部的O(1)时间复杂度插入和删除元素,但是在中间插入和删除元素的时间复杂度为O(N),其中N为列表的长度。压缩列表还支持按索引获取元素的操作,但是时间复杂度为O(N)。

Redis会根据列表的长度和元素的大小来选择适合的底层实现方式。当列表较长或包含较长的元素时,Redis会选择双向链表作为底层实现,以提供更高的灵活性和性能。而对于较短或较小的列表,Redis会选择压缩列表作为底层实现,以节省内存空间。需要注意的是,列表中的每个元素可以是任意类型的数据,包括字符串、整数、甚至其他复杂的数据结构。

哈希(Hash)

键值对的无序散列集合,适合存储对象的属性和值,常用于表示实体对象。在Redis中,哈希(Hash)数据类型的底层实现主要有两种方式:字典(Dictionary)和压缩列表(Ziplist)。

  1. 字典(Dictionary):字典是哈希数据类型的常见底层实现方式,在Redis中也称为哈希表。字典使用哈希表作为底层数据结构,它是一种使用散列函数将键映射到值的数据结构。字典的结构由多个哈希桶(Hash Bucket)组成,每个哈希桶中可以存储多个键值对。在字典中,通过计算键的哈希值,可以快速定位到对应的哈希桶,然后在桶内进行查找、插入或删除操作。字典的查找、插入和删除操作的平均时间复杂度为O(1),具有高效的性能。字典适用于存储键值对数量较多的哈希数据。
  2. 压缩列表(Ziplist):在一些特定场景下,当哈希数据的大小较小且键和值都是较小的字符串或整数时,Redis会选择压缩列表作为哈希的底层实现。压缩列表是一种紧凑且压缩的数据结构,用于存储较小的字符串或整数。压缩列表将连续的键值对存储在一块连续的内存区域中,通过压缩和优化存储空间来节省内存。压缩列表的结构包含一个头部、多个节点以及一个尾部,每个节点可以存储一个键值对。压缩列表支持O(1)时间复杂度的插入、删除和查找操作,适用于存储较小的键值对。

在实际使用中,Redis会根据哈希数据的大小和键值对的长度来选择适合的底层实现方式。当哈希数据较大或键值对较长时,Redis会选择字典作为底层实现,以提供更高的灵活性和性能。而对于较小或较短的哈希数据,Redis会选择压缩列表作为底层实现,以节省内存空间。需要注意的是,哈希数据类型在Redis中是无序的,即键值对的存储顺序并不影响它们的查找和访问。

集合(Set)

无序的唯一元素集合,支持集合间的交集、并集、差集等操作。 在Redis中,集合(Set)数据类型的底层实现主要有两种方式:哈希表(Hash Table)和整数集合(Intset)。

  1. 哈希表(Hash Table):哈希表是集合数据类型的常见底层实现方式之一。在Redis中,集合的底层实际上是一个哈希表,其中的每个元素都被存储为哈希表的键,而哈希表中的值被设置为一个常量。哈希表使用散列函数将元素映射到不同的哈希桶中,每个哈希桶中可以存储多个元素。哈希表的结构允许快速的插入、删除和查找操作,平均时间复杂度为O(1)。哈希表适用于存储任意类型的元素,并且可以处理大型集合。
  2. 整数集合(Intset):整数集合是一种特殊的集合底层实现方式,用于存储只包含整数元素的集合。整数集合是一个紧凑的数据结构,它采用有序的方式存储整数元素。整数集合的内部结构使用了不同长度的整数编码方式,以节省内存空间。整数集合支持快速的插入、删除和查找操作,时间复杂度为O(1)。整数集合适用于存储大量整数元素的集合,并且可以提供较低的内存消耗。

在实际使用中,Redis会根据集合中元素的类型和数量来选择适合的底层实现方式。如果集合包含非整数元素或者元素数量较大,则Redis会选择哈希表作为底层实现。而如果集合只包含整数元素且数量较小,则Redis会选择整数集合作为底层实现,以提供更高的性能和节省内存空间。需要注意的是,集合数据类型在Redis中是无序的,即元素的存储顺序并不影响它们的查找和访问。

有序集合(Sorted Set)

与集合类似,每个元素都关联一个分数(score),可以根据分数进行排序,常用于排行榜、优先级队列等。 在Redis中,有序集合(Sorted Set)数据类型的底层实现主要有两种方式:跳跃表(Skip List)和压缩列表(Ziplist)的结合。

  1. 跳跃表(Skip List):跳跃表是一种有序的数据结构,可以高效地支持插入、删除和查找操作,同时保持元素的有序性。跳跃表通过多层索引的方式加速查找操作,每一层的索引节点包含指向下一层的节点指针,从而实现了快速的跳跃查找。在Redis中,跳跃表被用作有序集合的底层实现。跳跃表在插入、删除和查找操作的平均时间复杂度为O(log N),其中N为有序集合的元素数量。跳跃表适用于存储元素数量较多、有序性要求较高的有序集合。
  2. 压缩列表(Ziplist)和有序整数集合(Sorted Integer Set)的结合:在某些特定场景下,当有序集合的元素数量较少且元素为整数类型时,Redis会选择将有序集合的底层实现方式结合使用压缩列表和有序整数集合。压缩列表和有序整数集合相结合可以节省内存空间。压缩列表用于存储元素成员,而有序整数集合则用于存储元素的分值(score)。这种底层实现方式可以在某些场景下提供较低的内存消耗。

根据有序集合的元素数量、元素类型以及对有序性和内存消耗的要求,Redis会选择适合的底层实现方式。跳跃表适用于有序集合元素数量较多、需要高效的插入、删除和查找操作的场景。而压缩列表和有序整数集合的结合适用于有序集合元素数量较少且元素为整数类型的场景,以节省内存空间。需要注意的是,有序集合中的元素可以是任意类型的数据,包括字符串、整数等。