centos7安装redis6.25结合docker镜像配置方法(附redis.conf文件)
list底层的数据结构:
linkedList 链表
zipList 压缩列表
quickList 快链表
在3,2版本之前,列表是通过双向链表或压缩链表来实现的。他们之间可以互相转换,在3.2版本之后又新加入了新的数据结构:QuickList,也就是双向链表和压缩列表的结合。
数据结构中常用的带头节点的双向链表,并且带有指向头节点的头指针和指向最后一个节点的尾指针,双向链表保证从任意一个位置可以向前或者向后进行遍历,但要注意头节点的前指针为null,尾节点的后指针为空,这也就说明了redis中的LinkedList数据结构是一个无环链表,不支持逆序遍历
第二点就是说,操作命令中的lpush
(left push) 、lpop
(left pop )等命令中的left代表从队头进行操作,right代表从队尾进行操作。
结构中的 len
字段记录了整个链表的长度。
由于链表本身的特性,对链表进行增删操作所需的时间非常少,时间复杂度仅为O(1);但如果是需要凭借索引寻找链表中某个值,时间花销就显得有些高,时间复杂度为O(n)
dup
函数用于对某个链节点进行复制操作
free
函数用于对某个链节点进行释放操作,也就是删除
match
函数用于判断某个链节点的值和输入的值是否相等。
zlbytes
:整个压缩列表所占用的字节数,本身是4个字节即32位,因此压缩链表的最大长度为(2^32-1)个字节zltail_offset
:压缩列表尾部的元素到起始地址的偏移量,可以直接找到表尾元素,即支持逆序遍历zlength
:表中元素的个数,占2字节,如果列表中的元素个数超过(2^16-1)个,那么需要遍历整个列表才能得到元素的个数entry
:列表中存储的元素,可能是整数,也可能是字节数组,具体结果见下图zlend
:元素的结束标志,占一个字节,是一个常量OXFFentry保存中列表中的元素,可能是整数,也可能是字节数组。其结构体有三个字段:
pre_length
:上一个元素的长度,方便逆序遍历的时候直接找到上个节点的起始位置。当前一个元素的长度小于254
个字节的时候,用一个字节表示;当前一个元素的长度大于等于254
个字节的时候,用5个字节表示,此时前一个字节存储固定值254
。
encoding
: 长度为两个 bit 。 它的值可以是 00 、 01 、 10 和 11 。00 、 01 和 10
表示 content 部分保存着字符数组,11
表示 content 部分保存着整数。
content
:保存真正的元素。
转换条件:
创建一个列表是,默认使用的数据结构是zipList,但在满足以下条件的时候,zipList会自动转化为双向链表:
总结
当存储的元素很少的时候,通常采用zipList作为基础数据结构,而当数据元素较多时则采用LinkedList。
从数据结构本身的特点而言:LinkedList在插入和删除元素方面具有很大的优势。但其需要额外存储两个指针,存储开销比较大,而且每个元素都是单独的内存空间,地址不连续,容易造成内存碎片。
而压缩列表存储在一块连续的内存空间中,但是增加删除元素开销较大,在内存扩容执行realloc操作的时候需要进行大量的拷贝操作
redis3.2之后,增加了新的数据结构:QuickList。它结合了LinkedList和zipList的优点。它将LinkedList的每个节点都用zipList的方式来存储。LinkedList节点之间依然采用双向链表连接起来,只不过一个节点上不是仅仅保存一个元素,而是多个,这些元素全部以压缩列表的方式存储在节点上。
QuickList结构体中的字段:
head
:指向链表中的头节点tail
:指向链表中的最后一个节点count
:QuickList存储元素的个数nodes
:QuickList链表节点的个数compressDepth
:采用的压缩算法的深度。为了进一步节约空间,redis还会对zipList进行lzf压缩,这是一种无损压缩算法。 QuickList中每个节点的数据结构:
插入头部lpush key value1 [value2....]
如果key不存在 则先创建再插入
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> lpush list 2
(integer) 2
127.0.0.1:6379> lpush list 3
(integer) 3
插入头部lpushx key value1 [value2....]
如果key不存在 则不做任何操作
127.0.0.1:6379> lpushx queue 1 2 3
(integer) 0
127.0.0.1:6379> exists quequ
(integer) 0
127.0.0.1:6379> lpushx queue 1 2 3
(integer) 0
127.0.0.1:6379> exists quequ
(integer) 0
插入尾部 rpush
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> rpush list 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "4"
查看队列的指定范围 lrange start end
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
移除列表头的第一个元素:lpop key
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "4"
127.0.0.1:6379> lpop list
1) "3"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
3) "4"
移除列表尾 的第一个元素:rpop key
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
3) "4"
127.0.0.1:6379> rpop list
"4"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
通过下标获取队列中的某个值:lindex key index
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
127.0.0.1:6379> lindex list 1
"1"
127.0.0.1:6379> lindex list 0
"2"
获取队列长队 llen key
127.0.0.1:6379> lpush list 7 8 9 0 11
(integer) 7
127.0.0.1:6379> llen list
(integer) 7
移除指定的值:lrem key num value
从key队列中移除num个值为value的元素 默认先移除队头的
127.0.0.1:6379> lpush list 1 1 3 2 3 4 1 1
(integer) 8
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "1"
3) "4"
4) "3"
5) "2"
6) "3"
7) "1"
8) "1"
127.0.0.1:6379> lrem list 1 1
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "4"
3) "3"
4) "2"
5) "3"
6) "1"
7) "1"
127.0.0.1:6379> lrem list 2 1
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "4"
2) "3"
3) "2"
4) "3"
5) "1"
将列表按照指定位置截断:ltrim
127.0.0.1:6379> lpush list 1 2 3 4 5 6
(integer) 6
127.0.0.1:6379> ltrim list 3 4
OK
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
移除列表1的最后一个元素并添加到列表2 第一个位置:rpoplpush list1 list2
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
127.0.0.1:6379> rpoplpush list list1
"2"
127.0.0.1:6379> lrange list 0 -1
1) "3"
127.0.0.1:6379> lrange list1 0 -1
1) "2"
更新列表指定位置:lset key index value
1. 如果列表不存在,则报错
2.是在列表已有的索引范围内进行值的覆盖
127.0.0.1:6379> lrange list 0 -1
1) "l"
127.0.0.1:6379> lset list 1 2
(error) ERR index out of range
127.0.0.1:6379> lset list 0 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "2"
给某个元素的前/后插入值 :linsert key before/after privot value
当列表中有多个相同值时,会在对头的第一个值进行相应的插入操作
127.0.0.1:6379> lrange list 0 -1
1) "2"
127.0.0.1:6379> linsert list before 2 before
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "before"
2) "2"
127.0.0.1:6379> linsert list after 2 after
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "before"
2) "2"
3) "after"
#当列表中有多个相同值时,会在对头的第一个值进行相应的插入操作
127.0.0.1:6379> lpush list2 1 3 4 1 3 4
(integer) 6
127.0.0.1:6379> lrange list2 0 -1
1) "4"
2) "3"
3) "1"
4) "4"
5) "3"
6) "1"
127.0.0.1:6379> linsert list2 before 1 before
(integer) 7
127.0.0.1:6379> lrange list2 0 -1
1) "4"
2) "3"
3) "before"
4) "1"
5) "4"
6) "3"
7) "1"