数据类型及其业务场景

字符串(String

字符串类型是最基本的数据类型, value 最多可以容纳的数据长度是 512M
  • 存储任意类型的数据,包括数字、文本等。适用于缓存、计数器、分布式锁等场景。共享 Session信息

哈希(Hash

哈希类型是键值对的集合,适用于存储对象的多个属性。

Redis 为了解决哈希冲突,采用了 链式寻址法 ,也就是采用链表的方式来保存同一个 hash 桶中的多个元素。
  • 常用于存储用户信息、商品信息等。减少内存消耗,最大程度利用缓存资源,可以结合VO类来说
对于 Redis 这种需要高效处理海量数据的系统来说,采用链表来解决哈希冲突并通过 rehash 来减少链 表过长的方式相对来说更加高效和灵活,因为其不会产生很长的冲突链表,因为扩容操作使其的桶槽位 较多,如果采用红黑树来优化的话,第一要维护平衡要时间,第二存储颜色和左右节点要空间。对于缓 存来说,追求时间又空间宝贵,所以不用红黑树

Hash扩容

如果出现大量的 key 的冲突导致链表过长的情况下,为了保持高效, Redis 会对哈希表做 rehash操作,也就通过增加哈希桶来减少冲突。为了 rehash 更高效, Redis 还默认使用了两个全局哈希表,一个用于当前使用,称为主哈希表,一个用于扩容,称为备用哈希表  
在哈希表扩容时, Redis 首先会创建一个新的哈希表,该哈希表的大小是原有哈希表的 两倍 ,然后将原有哈希表中的键值对逐一迁移到新的哈希表中。由于迁移过程是逐步进行的,因此在迁移过程中, 可以对新哈希表进行写入操作,也可以对旧哈希表进行读取操作 ,从而保证了 Redis 服务的正常运行。
需要注意的是,哈希表扩容时可能会出现哈希表的大小调整不及时,导致 哈希表过度填充 的问题,从而导致哈希表性能的下降。因此,在实际应用中,需要根据具体场景对Redis 的哈希表大小进行调整,以保证Redis 服务的高性能和高可用性。

列表(List

列表类型是一个 有序的 字符串列表,可以从两端添加或删除元素,支持快速的插入和删除操作。列表的最大长度为 2^32 - 1 ,由 双向链表 压缩列表 实现,
Redis 3.2 版本之后, List 数据类型底层数据结构就只由 quicklist 实现了,替代了双向链表和 压缩列表
struct quicklist{
quicklistNode *head; // 头部节点
quicklistNode *tail; // 尾部节点
unsigned long count; // 所有节点中元素的总数
unsigned long len; // 所有节点中元素的总数
int fill: 16; // ziplist 节点的最大大小
unsigned int compress: 16; // 节点压缩深度,表示节点是否使用 LZF 算法压缩
}
  •  适用于最新消息、队列等场景。

压缩列表

压缩列表( ziplist )是 Redis 内部用于实现 List Zset 数据结构的一种特殊数据结构,它是一段 续的内存 ,用来存储 一组连续的数据 Redis 是使用 C 语言开发的,因此没有直接提供 Java 版本的压缩列表。

 压缩列表相比于双向链表或数组,在某些情况下具有更小的内存占用和更快的查找速度

  1. 连续内存空间:压缩列表采用连续的内存空间来存储所有元素,而双向链表需要维护节点间的指针,数组需要分配一块连续的内存空间。相比之下,压缩列表不需要指针或额外的空间来存储链接信息,减少内存开销。
  2. 节省指针开销:在双向链表中,每个节点需要存储指向前一个节点和后一个节点的指针,这会增加额外的内存开销。而压缩列表直接使用连续内存空间,不需要维护指针,节省了指针开销。
  3. 较少的内存碎片:链表或数组在频繁的插入和删除操作后,可能会出现大量的内存碎片,导致内存利用率较低。而压缩列表在插入和删除操作时,可以通过 内存重用 紧凑表示 等优化策略,减少内存碎片问题。
  4. 较少的内存碎片:链表或数组在频繁的插入和删除操作后,可能会出现大量的内存碎片,导致内存利用率较低。而压缩列表在插入和删除操作时,可以通过内存重用和紧凑表示等优化策略,减少内存碎片问题。

 

缺点: 无法直接访问中间位置的元素、插入或删除操作可能会引起整个压缩列表的重分配等,此外压缩列表在插入或删除元素时,可能需要进行内存重分配和元素移动的操作 ,特别是在元素的中间位置插入或删除操作时,会导致整个压缩列表的重建。而数组在插入和删除元素时,只需要移动其他元素的位置,开销相对较小。

压缩列表和数组的区别

  1. 内存占用:压缩列表通过紧凑地存储元素和使用特定的编码方式,可以在一块连续的内存空间中存储多个元素,从而减少内存开销。而数组需要分配一段连续的内存空间来存储元素,无法灵活地压缩内存,可能会造成内存浪费。
  2. 动态扩容:压缩列表的内存空间是连续的,它可以通过调整 zlbytes 字段的大小来动态扩容。而数组在容量不足时,需要重新分配更大的内存空间,并将原来的数据复制到新的内存空间中,这会导致一次较大的内存分配和数据复制的开销。
  3. 元素大小变化:压缩列表中的元素可以动态调整它们的编码方式来适应大小的变化。对于小的整数值或短的字符串,可以使用紧凑的编码方式,占用更少的内存。而数组中的元素大小是固定的,无法根据具体的元素大小进行优化。
  4. 插入和删除的开销:压缩列表在插入或删除元素时,可能需要进行内存重分配和元素移动的操作特别是在元素的中间位置插入或删除操作时,会导致整个压缩列表的重建。而数组在插入和删除元素时,只需要移动其他元素的位置,开销相对较小。
  5. 随机访问的效率:数组可以通过索引直接访问特定位置的元素,时间复杂度为 O(1),而压缩列表需要遍历整个列表才能找到特定位置的元素,时间复杂度为 O(n)。因此,对于需要频繁进行随机访问的场景,数组更适合。

Quicklist

Quicklist 是一种特殊的列表,它通过将多个压缩列表相互连接起来来实现大规模存储。具体来说,它是由多个压缩列表和少量双向链表组成的,其中每个压缩列表都作为一个小的块来存储一定数量的元素。如果需要添加或删除元素,Quicklist 也可以在不破坏整个列表的情况下对某个块进行修改。

  1. 高效Quicklist 可以在添加和删除元素时快速定位到目标块,由于它采用了跳表的数据结构来定位块中特定位置的元素,因此可以快速进行随机访问,而不需要遍历整个列表。同时,Quicklist 也避免了由双向链表或压缩列表所带来的各种性能问题。
  2. 紧凑Quicklist 可以通过动态调整块的大小来适应不同大小的数据集,因此可以非常紧凑地存储大量数据。
  3. 可压缩:压缩列表是 Quicklist 的一个基础组件。它们可以节省内存,特别是对于存储短字符串、整数或者短二进制数据的元素非常有效。同时,Quicklist 还可以在压缩列表中存储指向双向链表的指针,以实现元素的快速插入和删除操作。

集合(Set

集合类型是一个 无序唯一 的字符串集合,支持添加、删除和查找元素。 同时还支持多个集合取交集、并 集、差集 。底层数据结构是由 哈希表或整数集合 实现的
  • 如果集合中的元素都是整数且元素个数小于 512 (默认值,set-maxintset-entries配置)个,Redis 会使用整数集合作为 Set 类型的底层数据结构;
  • 如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为 Set 类型的底层数据结构。

适用于:

  • 点赞功能:点了就加进来,取消就删除。Set 类型可以保证一个用户只能点一个赞
  • 共同关注功能:Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号

 整数集合

我们使用 Java HashSet<Integer> 来实现整数集合。该类提供了快速的添加、删除和查找操作,并且会自动处理重复值的情况。我们可以通过调用 add() remove() contains() 方法来执行相应的操作。 size() 方法返回整数集合中的元素数量。

有序集合(Sorted Set / Zset

有序集合类型是一个 有序的、不重复的 字符串集合,每个元素都会关联一个分数用于排序。
Zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score (分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序结合的元素值,一个是排序值。Zset 类型的底层数据结构是由压缩列表 跳表 实现的:
  • 有序集合保存的元素数量小于128 / 有序集合保存的所有元素的长度小于 64字节——>压缩列表
  • 反之采用跳表

压缩列表

压缩列表本质上就是个数组,只不过增加了上面几个黄色的属性,有利于快速的寻找列表的首、尾的节

跳表
跳表在链表的基础上增加了多级索引,通过多级索引位置的转跳实现了快速查找元素。说的那么厉害实际上就是隔位取节点通过 二分查找 的思想一次遍历过滤几个节点,很明显 ,这个只能基于 有序 的特性下,时间复杂度为 logN

为什么用跳表而不用红黑树或者二又树呢?

  • 跳表实现比红黑树简单,易懂
  • 范围查找效率更高

Bitmap

位图类型是一种紧凑、高效的数据结构,本身是用 String 类型作为底层数据结构实现的一种统计二值状态的数据类型
  • 用于对大量的二进制数据进行存储和操作。适用于两种状态的统计业务布隆过滤器等场景。
随着 Redis 版本的更新,后面又支持了四种数据类型: BitMap 2.2 版新增)、 HyperLogLog 2.8 版新增)、 GEO 3.2 版新增)、 Stream 5.0 版新增)

HyperLogLog

一种用于「统计基数」的数据集合类型,基数统计就是指统计一个集合中不重复的元素个数。但要注意,HyperLogLog 是统计规则是基于概率完成的,不是非常准确,标准误算率是 0.81%
  • 简单来说 HyperLogLog 提供不精确的去重计数 

适用于百万级网页 UV 计数,也就是看一个网站有多少人访问  

GEO

Redis GEO Redis 3.2 版本新增的数据类型,直接使用了 Sorted Set 集合类型

GEO 类型使用 GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换,这其中的两个关键机制就是「对二维地图做区间划分」和「对区间进行编码」。一组经纬度落在某个区间后,就用区间的编码值来表示,并把编码值作为 Sorted Set 元素的权重分数。
这样一来,我们就可以把经纬度保存到 Sorted Set 中,利用 Sorted Set 提供的 按权重进行有序范围查找” 的特性,实现 LBS 服务中频繁使用的 搜索附近 的需求。

主要用于存储地理位置信息,并对存储的信息进行操作。

Stream

Redis 专门为消息队列设计的数据类型。
Redis 5.0 Stream 没出来之前,消息队列的实现方式都有着各自的缺陷,例如:
  • 发布订阅模式,不能持久化也就无法可靠的保存消息,并且对于离线重连的客户端不能读取历史消息的缺陷;
  • List 实现消息队列的方式不能重复消费,一个消息消费完就会被删除,而且生产者需要自行实现全局唯一 ID
基于以上问题, Redis 5.0 便推出了 Stream 类型也是此版本最重要的功能,用于完美地实现消息队列,它支持消息的持久化、支持自动生成全局唯一 ID 、支持 ack 确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠。
  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值