redis常用的五种数据结构

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

redis常用的五种数据结构

一、String

redis的字符串是由sds(简单动态字符串)实现的。redis3.2后,主要由4个属性构成:
struct sdshdr {
	T len;//记录buf数组中已使用的长度
	T free;//记录buf数组中未使用的长度
	byte flag;//特殊位标志
	char buf[];//字节数组,用来保存字符串
}
特殊位标志可以理解为是否使用:sds5、sds8、sds16、sds32、sds64其中一种类型的sds结构体。

与C语言字符串的差别:
1.c语言字符串本身不记录字符串长度。为了获取字符串长度,只能从头到尾遍历字符串,知道遇见\0结束符为止。sds字符串保存了字符串的长度,所以在获取字符串长度上sds字符串的效率要快。
2.二进制安全。c语言的字符串以\0判断字符串是否结束,这种设计在保存图片、音频等二进制数据时会出错。
3.空间预分配。当sds的api对一个sds进行修改时,并且需要对sds进行空间扩容时。redis不仅会为sds分配修改必须的空间,而且还会为sds分配额外的空间。分配的原则如下:

	1.如果对sds修改后,sds的长度小于1mb。那么redis会分配与已使用长度同样大小的未使用长度。此时,sds的已使用空间与未使用空间保持一样大小。
	2.如果对sds修改后,sds的长度大于等于1mb。那么redis会分配1mb的未使用空间。
	3.字符串最大扩容到512mb。

二、List

redis3.2版本前,使用压缩列表ziplist、双向链表linklist作为底层实现。

1.列表中的元素大于512个时,会由ziplist转换成linklist。
2.列表中某个元素的长度大于64个字节,会由ziplist转换成linklist。

redis3.2版本后,使用quicklist作为底层实现
quicklist是ziplist和linklist的混合体。多个ziplist之间使用双向指针串接起来。

三、Hash

hash的底层实现相当于java中的hashmap。在redis中,hash有两种底层实现。

同时满足以下条件时使用ziplist:
	1.hash对象里面所有的键值对长度小于64字节
	2.hash对象里面保存的键值对数量小于512个

hash表的扩容与缩容
负载因子=保存结点的数量/hash表的长度
什么时候扩容和缩容:

1.在没有执行bgsave或bgrewriteaof命令时,负载因子大于等于1时进行扩容。
2.正在执行bgsave或bgrewriteaof命令时,负载因子大于等于5时进行扩容。
3.负载因子小于0.1时,进行缩容。

扩容缩容的规则:

扩容:库容后的数组长度是已使用长度的2倍。每次库容都重新复制一个新的原始长度两倍的数组。将数据迁移到新的数组后,销毁原来的数组。
缩容:缩容后的规则与扩容相反。

渐进式rehash
渐进式rehash一次迁移一个桶上所有的数据,设计上采用分而治之的思想。将原本集中式的操作分散到每个添加、删除、查找和更新操作上。

四、Set

set对象的底层实现是intset和hashtable。
当集合对象保存的元素都是整数,并且个数不超过512个时,使用intset,否则使用hashtable。

typedef struct intset{
	uint32_t encoding;//编码方式
	uint32_t lenght;//集合包含的元素数量
	int8_t contents[];//保存元素的数组
}

1.contents数组是整数集合。数组中的成员从小到大依次排列,且不允许重复。
2.当新插入元素的类型比整数集合现有类型元素的类型大时,整数集合必须要先升级,然后才能将新元素添加进来。这个过程分以下三步:

1.根据新元素类型,拓展conten[]数组的大小。
2.将content数组中现有的所有元素都转换成新元素的类型,并且维持底层数组的有序性。
3.将新元素添加到底层数组里面。

set-hashtable
set-hashtable的底层实现类似于java中hashmap和hashset的实现,hashset的底层是由hashmap来实现的。原理是使用hashmap的key作为值,hashmap的value为null。

五、Zset

Zset的底层实现是ziplist或者skiplist
当有Zset保存的元素个数小于128个,且所有元素成员长度都小于64字节时,使用ziplist。否则,使用skiplist。
zset-ziplist
ziplist和普通双向链表的区别:
一个普通的双向链表,链表中每一项都占用独立的一块内存,各元素之间用地址指针连接起来。这种方式会带来大量的内存碎片,而且地址指针也会占用额外的内存。而ziplist却是将每个元素都放在连续的内存空间内。他其实不是一个链表,而更像是个数组。
skiplist
待续

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值