文章目录
1、数据结构
1.1 简单动态字符串
SDS 特点:
- 空间预分配:当对一个 SDS 类型的字符串进行修改,并且需要对 SDS 进行空间扩展的时候,程序不仅会分配这次修改所需的内存空间,还会为 SDS 分配额外的多余的空间。
- 如果对 SDS 进行修改后,SDS 的大小小于 1MB,则程序除了分配该 SDS 字符串所需的内存空间,还会分配和 len 属性同样大小的未使用的空间;
- 如果对 SDS 进行修改后,SDS 的大小大于等于 1MB,那么最多分配 1MB 的额外内存空间。
通过内存预分配策略,Redis 可以减少连续执行字符串增长所需的内存重分配次数。
- 惰性空间释放:当调用 SDS 的 API 来缩短 SDS 保存的字符串时,程序并不会立即使用内存重分配来回收这部分缩短后多出来的内存空间,而是记录在 free 属性中,等待下次使用。
通过惰性空间释放策略,SDS 避免了缩短字符串时所需的内存重分配操作。当然,也不用担心惰性空间释放策略会造成内存浪费,在我们真正需要时,可以调用 SDS 也提供了相应的 API 来真正释放 SDS 的未使用空间。
1.2 链表
链表提供了高效的节点重排能力,以及顺序性地访问方式,是列表这个数据类型的底层实现之一。Redis 的链表是双向的、无环的、带头指针和尾指针的链表,程序获取头结点和尾节点的时间复杂度为 O(1)。
1.3 字典
Redis 中的字典的底层实现是哈希表的方式,该哈希表解决哈希冲突的方式是使用链地址法。字典中每个键都是唯一的,程序可以在字典中根据键查找相应的值,并进行相应的增删改查操作。
1.4 跳跃表
跳跃表(skiplist)是一种有序的数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的。【有一种说法是,跳跃表是一种多级索引的方式】
跳跃表支持平均 O(logN)、最坏 O(N) 复杂度的节点查找。在大部分情况下,跳跃表的效率可以媲美平衡树,并且因为跳跃表的实现比平衡树更简单,所以有不少程序都使用跳跃表来代替平衡树。
Redis 使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员(member)是比较长的字符串时,Redis 就会使用跳跃表来作为有序集合键的底层实现。和链表、字典等数据结构被广泛地应用在 Redis 内部不同,Redis 只在两个地方使用到了跳跃表,一是实现有序集合键,另一个是在集群节点中用作内部数据结构,此外,跳跃表在 Redis 中没有其它用途。
Redis 的跳跃表由 redis.h/zskiplistNode 和 redis.h/zskiplist 两个结构定义,其中 zskiplistNode 结构用于表示跳跃表节点,而 zskiplist 结构则用于保存跳跃表节点的相关信息,比如节点数量,以及指向表头节点和表尾节点的指针等等。
1.5 整数集合
整数集合(intset)是集合键(Set 类型的数据)的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现。整数集合的底层实现是数组,这个数组以有序、无重复的方式保存集合元素。
1.6 压缩列表
压缩列表(ziplist)是 Redis 为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)的数据结构。
2、数据类型
https://blog.csdn.net/weixin_50823456/article/details/120798290
2.1 String
String 是 Redis 最基本的类型,一个key对应一个value。底层是由 SDS 数据结构来实现的。Redis 中字符串 value 最多可以是 512M。
【原因:SDS 的结构体中记录长度的 len 属性是 int 类型,C 语言中 int 类型占 4 字节,即 32 位,因为 Redis 字符串是以字节为单位进行存储的,而每个字节的大小是 8 位。232 = (512 * 1024 * 1024 * 8),因此最大可以存储 512MB】
2.2 List
单键多值列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表 / 压缩列表。对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
2.3 Hash
键值对集合。Hash 是一个 String 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。类似 Java 里面的 Map<String, Object>。用户 ID 为查找的 key,存储的 value 用户对象包含姓名,年龄,生日等信息。Hash 的底层实现是字典或压缩列表。
2.4 Set
Set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 Set 是可以自动去重的,并且 Set 提供了判断某个成员是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的,而且也可以对多个集合进行交、并、差运算。Set 的底层实现是字典或整数集合。
2.5 ZSet
ZSet 与普通集合 set 非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。因为元素是有序的,,所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。ZSet 的底层实现是跳跃表或压缩列表。
2.6 BitMap
Bitmap 本身不是一种数据类型, 实际上它就是字符串 , 但是它可以对字符串的位进行操作。Bitmaps 单独提供了一套命令, 所以在 Redis 中使用 Bitmap 和使用字符串的方法不太相同。 可以把 Bitmap 看成一个以比特位为单位的数组, 数组的每个单元只能存储 0 和 1, 数组的下标在 Bitmap 中叫做偏移量。
2.7 HyperLogLog
HyperLogLog 是用来做基数统计的算法(UV),HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
缺点是:HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误差率为 0.81%,HyperLogLog 常见的应用常景是统计网站的 UV(User View)。
2.8 Geospatial
Redis 3.2 中增加了对 GEO 类型的支持。GEO,Geographic,地理信息的缩写。该类型就是元素的 2 维坐标,在地图上就是经纬度。Redis 基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作。主要用于存储地理位置信息,常用于定位附近的任,打车距离的计算等。