动态字符串SDS
举例,一个包含字符串"name"的sds结构如下,这里并不需要像c语言一样读取到\0,因为header描述里有len,直接按这个都就可以了。
sds还具体动态扩容的功能,如果新字符串<1m,则新空间x2+1,如果>1m,扩容后卫1m+字符串长度+1,内存预分配。
sds优点
IntSet
只存整数 ,长度可变、有序。
Dict
键值型的映射关系的保存,正是由Dict来实现的,Dict主要由哈希表、哈希节点、字典三部分来组成。
Dict中的HashTable就是数组结合单向链表的实现,当集合中元素较多时,必然导致哈希冲突增多,链表过长,则查询效率降低。
通过检查负载因子来判断是否会触发哈希表扩容,也会对负载因子检查,看是否需要哈希表收缩。
重要的概念rehash
不管是扩容还是收缩,必会创建新的哈希表,size会发生变化,这时候必须对哈希表中的每一个key重新计算索引,插入新的哈希表,这个过程称为rehash。这里就很像hashmap的扩容。
redis的渐进式rehash
Dict的rehash并不是一次完成的,如果Dict中包含了数百万的entry,要在一次rehash完成,是很有可能导致主线程阻塞的。因此这里的rehash应该是分多次、渐进式的完成。
总结:
ziplist
entry的长度不固定,是可变的
这里存储的并不是前后节点的指针,因为记录两个指针需要16个字节,但存储前一节点的长度只需要的1或5个字节。
QuickList
ZipList存海量数据存不下时,就使用QuickList,每一个节点都链接着一个ZipList。
总结:
SkipList
如果list存储的数据非常的多,那么我们去找一个中间元素需要遍历很多次,通过跳表可以解决这个问题
总结:
redisObject
任何键和值都封装为这个玩意
string
list
redis中的列表,可存储重复元素,可实现分布式的栈、队列等,以阻塞队列,list有一些命令B开头的可以实现阻塞队列。
常用api
- lpush 左压入一个元素
- rpush 右压入一个元素
- lpop 左弹出一个元素
- rpop 右弹出一个碳素
- lrange 0 -1 遍历list,支持逆序索引,-1,-2,-3等。
- lindex 根据索引去获取元素
- ltrim a,b a和b之外的被删除掉
实现栈:
lpush结合lpop
实现队列:
lpush结合rpop
底层:
首先思考一个问题,为什么list底层不采用双向链表去实现,这里因为我们的内存资源是非常宝贵的,如果采用双向链表的话会产生内存碎片问题。
在QuickList的基础上包了一层Object头
set
常见api如下