前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis 基本数据结构二:列表

Redis 基本数据结构二:列表

作者头像
CoderJed
发布2019-03-15 11:36:00
3870
发布2019-03-15 11:36:00
举报
文章被收录于专栏:Jed的技术阶梯Jed的技术阶梯

1. 列表简介

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

列表的特点:

  • 有序
  • 可以重复
  • 右边进左边出或者左边进右边出,则列表可以充当队列
  • 左边进左边出或者右边进右边出,则列表可以充当栈

2. 常用命令

  • 添加元素
代码语言:javascript
复制
# 右边插入元素
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"
  • 查找元素
代码语言:javascript
复制
# 查找下标范围内的元素
# 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
  • 删除元素
代码语言:javascript
复制
- 左侧弹出
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"
  • 修改元素
代码语言:javascript
复制
# 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"
  • 阻塞式弹出 如果列表不存在或者列表为空,那么弹出操作会在设置的时间后返回结果,如果设置时间为0,那么除非成功弹出元素,否则一直阻塞。
代码语言:javascript
复制
# 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. 内部编码

  • ziplist ziplist 是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空隙。这样设计的优点是可以节约内存,并且查询元素的速度会更快,但是插入元素的性能不好,原理同 Java 的 ArrayList。
  • linkedlist linkedlist 相当于 Java 的 LinkedList,优点是插入性能好,只需要修改两个指针即可,缺点是占内存,因为存储了额外的指针等信息,同时查询性能也不好,需要从头到尾遍历。
  • quicklist redis-3.2版本提供了 quicklist 实现方式,结合了 ziplist 和 linkedlist 的优点,原理如下图所示:

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

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

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

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

相关的参数:

  1. quicklist 中每个 ziplist 的大小
代码语言:javascript
复制
list-max-ziplist-size -2

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

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

  • -5:每个 ziplist 最大为 64kb,不建议使用
  • -4:每个 ziplist 最大为 32kb,不建议使用
  • -3:每个 ziplist 最大为 16kb,不建议使用
  • -2:默认值,每个 ziplist 最大为 8kb,性能最好
  • -1:每个 ziplist 最大为 4kb,性能最好
  1. 压缩深度
代码语言:javascript
复制
list-compress-depth 0

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.03.08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 列表简介
  • 2. 常用命令
  • 3. 内部编码
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档