003.Redis 基本数据结构二:列表

2019-03-08  本文已影响0人  CoderJed

1. 列表简介

列表(list)类型是用来存储多个有序的字符串,如下图所示,a、b、c、d、e五个元素从左到右组成了一个有序的列表,列表中的每个字符串称为元素(element),一个列表最多可以存储2^32-1个元素。在Redis中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。

列表的特点:

2. 常用命令

# 右边插入元素
node02:6379> rpush list a b c
(integer) 3

# 从左到右查看所有元素
node02:6379> lrange list 0 -1
1) "a"
2) "b"
3) "c"

# 左边插入元素
node02:6379> lpush list 1 2 3
(integer) 6
node02:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "a"
5) "b"
6) "c"

# 在某个元素之前插入元素
# LINSERT key BEFORE|AFTER pivot value
# 在 a 之前插入 0
node02:6379> linsert list before a 0
(integer) 7
node02:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "0"
5) "a"
6) "b"
7) "c"
# 查找下标范围内的元素
# LRANGE key start stop
node02:6379> lrange list 0 3
1) "3"
2) "2"
3) "1"
4) "0"

# 查找指定下标的元素
node02:6379> lindex list 4
"a"

# 获取列表长度
node02:6379> llen list
(integer) 7
- 左侧弹出
node02:6379> lrange list 0 -1
1) "2"
2) "1"
3) "0"
4) "a"
5) "b"
6) "c"

# 右侧弹出
node02:6379> rpop list
"c"
node02:6379> lrange list 0 -1
1) "2"
2) "1"
3) "0"
4) "a"
5) "b"

# 按照元素值删除
# LREM key count value
# count = 0,删除全部指定的元素
# count < 0, 从右到左,删除|count|个指定元素
# count > 0, 从左到右,删除count个指定元素

node02:6379> rpush list2 a a a a a b b b b b a a b b a
(integer) 15
node02:6379> lrem list2 3 a
(integer) 3
node02:6379> lrange list2 0 -1
 1) "a"
 2) "a"
 3) "b"
 4) "b"
 5) "b"
 6) "b"
 7) "b"
 8) "a"
 9) "a"
10) "b"
11) "b"
12) "a"
node02:6379> lrem list2 -5 b
(integer) 5
node02:6379> lrange list2 0 -1
1) "a"
2) "a"
3) "b"
4) "b"
5) "a"
6) "a"
7) "a"
node02:6379> lrem list2 0 a
(integer) 5
node02:6379> lrange list2 0 -1
1) "b"
2) "b"

# 按照元素下标保留,其余删除
# LTRIM key start stop
node02:6379> rpush list3 0 1 2 3 4 5 6
(integer) 7
# 保留下标 1-3 的元素,其余删除
node02:6379> ltrim list3 1 3
OK
node02:6379> lrange list3 0 -1
1) "1"
2) "2"
3) "3"
# LSET key index value
node02:6379> lrange list3 0 -1
1) "1"
2) "2"
3) "3"
node02:6379> lset list3 0 hello
OK
node02:6379> lrange list3 0 -1
1) "hello"
2) "2"
3) "3"
# BRPOP key [key ...] timeout
node02:6379> exists list4
(integer) 0
node02:6379> brpop list4 0
# 阻塞....

# 在另一个客户端设置push一个值进去
node02:6379> rpush list4 tom
(integer) 1

# 弹出后返回结果,阻塞了105s
node02:6379> brpop list4 0
1) "list4"
2) "tom"
(105.86s)

# list5 不存在
node02:6379> exists list5
(integer) 0
# 阻塞 3s 后返回结果
node02:6379> brpop list5 3
(nil)
(3.10s)

# list5 中有元素
node02:6379> rpush list5 tom
(integer) 1
# 则立即弹出
node02:6379> brpop list5 5
1) "list5"
2) "tom"

# blpop 与 brpop 的用法相同

阻塞式弹出的注意事项:

3. 内部编码

quicklist 是一个 linkedlist,这个 linkedlist 是 ziplist 组成的双向链表。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,它将所有的元素紧挨着一起存储,分配的是一块连续的内存。

当数据量比较多的时候才会改成 quicklist 。因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev(前一个节点) 和 next(后一个节点)。

所以 redis 将链表和 ziplist 结合起来组成了 quicklist 也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

相关的参数:

  1. quicklist 中每个 ziplist 的大小
list-max-ziplist-size -2

这个值如果设置为正数,代表的是 quicklist 的每个 ziplist 中最多可以存储元素的个数。

如果设置负数,则代表用字节数而不是元素个数来限定每个 ziplist 的大小,具体信息如下:

  1. 压缩深度
list-compress-depth 0

quicklist 默认的压缩深度是 0,也就是不压缩。
压缩深度为 1 代表:quicklist 的首尾两个 ziplist 不压缩,其余的 ziplist 压缩。
压缩深度为 2 代表:quicklist 的首尾的前两个 ziplist 不压缩,其余的 ziplist 压缩。
以此类推。

压缩会使得内存占用变小,但是对 list 的读写请求的性能会下降,因为增加了解压缩的开销。因此这个值保持默认即可,如果确实想要节约内存,可以把压缩深度设置为 1。算是一种中和的取值。

上一篇 下一篇

猜你喜欢

热点阅读