列表(list)相当于是 数组 或者 顺序表list 内部编码方式并非是一个简单的数组,而是更接近于“双端队列”(deque)列表中的元素是有序的(元素位置),允许插入重复元素
常见命令
1)lpush lpushx rpush rpushx
lpush key element [element ...] —— 头插
返回 list 的长度 O(1)
lpushx key element [element ...]
当 key 存在是返回 list 的长度,否则直接返回 O(1) —— 头插
rpush key element [element ...] —— 尾插
返回 list 的长度 O(1)
rpush key element [element ...] —— 尾插
当 key 存在是返回 list 的长度,否则直接返回 O(1)
若果 key 已经存在,并且 key 对应的 value 类型不是 list,此时会报错
2)lrange
获取从 start 到 end 区间内的所有元素(左闭右闭)
lrange key start end (支持负数)
返回指点区间内的元素 O(N)
此处 数字 只是标识返回元素的顺序(结果集),和下标无关
当给出非法下标时,Redis 会尽可能的取到给定区间内的元素(鲁棒性)
3)lpop rpop
lpop key [count] —— 头删
返回指定区间内的元素或者 nil O(count)
rpop key [count] —— 尾删
返回指定区间内的元素或者 nil O(count)
Redis 中的 list 是一个双端队列,从两头插入/删除是非常高效的 O(1)
rpush + lpop ——> 队列
rpush + rpop ——> 栈
4)lindex
lindex key index
返回指定下表的元素 ,非法下标则返回 nil O(N)
正数表示从左数,负数反之,起始点为 0
5)linsert
linsert key <before | after> pivot element
返回插入后的 list 的长度 O(N)
pivot 基准值(从左往右) element 要插入的元素
6)len
len key
返回 list 的长度 O(1)
7)lrem
lrem key count element
返回删除的元素个数 O(1)
count 要删除的元素的个数 element 要删除的元素的值
8)ltrim
ltrim key count element
返回 ok O(N)
保留 start 和 stop 区间内的元素(区间外的被直接删除)
9)lset
lset key index element
返回 OK,若下表越界返回 nil O(1)
10)blpop brpop
blpop key [key ...] timeout —— 尾删
返回取出的元素或者 nil O(1)
brpop key [key ...] timeout —— 尾删
返回取出的元素或者 nil O(1)
返回结果相当于是一个pair(二元组)
一方面表示当前数据来自哪个 key
一方面表示取到的数据是什么
生产者—消费者模型 —— BlockingQueue
使用队列作为中间的“交易场所”(broker)
1.线程安全
2.队列为空,尝试出队列,产生阻塞,直到队列不空,阻塞解除
队列为满,尝试入队列,产生阻塞,直到队列不满,阻塞解除
Redis 的 list 也相当于 阻塞队列
线程安全 —— 单线程模型 阻塞 —— 只支持“队列为空”,不考虑“队列满”
显示设置阻塞时间,此处不会对 Redis 服务器造成太大影响
可以同时去尝试获取多个键,一旦有一个键对应的列表中可以弹出元素,命令立即返回
命令如果设置了多个键,会从左向右进行遍历,一旦有一个键对应的列表中可以弹出元素,命令立即返回
如果多个客户端同时对一个键进行 blpop ,最先执行的客户端会获得元素
编码方式
quecklist
相当于是 链表 和 压缩列表 的结合
整体还是一个列表,链表的每个节点,是一个压缩列表
每个压缩列表都不太大,同时再把多个压缩列表通过链表结构连起来
ziplist(压缩列表)
把数据按照更紧凑的形式进行表示。
节省空间,但是数个数多了,操作效率会下降
linkedlist(链表)
应用场景
消息队列
使用 lpush + brpop 组合实现 生产者-消费者 模型,在通过多个客户端保证负载均衡和高可用性
如果列表为空,生产出的下个元素只有一个消费者可以“抢到”元素
分频道的消息队列
如果频道为空,生产出的下个元素只有一个消费者可以“抢到”元素
多个频道,可以在某种数据发生异常时,不会对其他数据造影响(解耦合)
微博 TimeLine
每个用户都有属于自己的 TimeLine(微博列表)
当需要分页展示文章列表时,可以使用 list (list不仅有序,还支持按照索引范围获取元素)
1.)当前一页中的有多少数据是不确定的,可能会导致下面的循环比较大,从而出发多次 hgetall(多次网络请求)
pipeline (流水线\管道)把多个 Redis 命令合并成一次 网络请求进行通信,降低服务器与客户端的通信次数
2)分裂获取文章时,lrange 在列表两端表现比较好,获取列表中间的元素表现比较差,可以将列表进行拆分