Lists是一组有序、可重复的元素集合。
LPUSH lists "a" "b" => "(integer) 2"
RPUSH lists "c" "d" => "(integer) 4"
LPUSH
/RPUSH
分别在队首(左侧)和队尾(右侧)插入指定元素。如果key不存在,Redis会创建一个空的list并插入元素。操作的返回值是插入操作后list的长度。
Redis2.4开始支持多个元素批量插入。
LRANGE lists 0 -1
=> 1) "b"
=> 2) "a"
=> 3) "c"
=> 4) "d"
LRANGE
会返回指定区间内的元素。区间以0开始,-1代表队尾。区间超过最大范围并不会报错。
LLEN lists => "(integer) 4"
LLEN
返回当前元素个数。
LPUSHX notExists "�a" => "(integer) 0"
RPUSHX notExists "�a" => "(integer) 0"
LPUSHX
/RPUSHX
与LPUSH
/RPUSH
的差别是,只有当key存在时,才会执行插入操作。
LSET lists 0 "f" => "OK"
LRANGE lists 0 -1
=> 1) "f"
=> 2) "a"
=> 3) "c"
=> 4) "d"
LSET
将指定位置的元素替换为新值。LSET
的算法复杂度为O(N),与Lists的数据结构有关。超出index范围会报错。
LINSERT lists before "a" "x" => "(integer) 5"
LINSERT lists after "a" "y" => "(integer) 6"
LRANGE lists 0 -1
=> 1) "f"
=> 2) "x"
=> 3) "a"
=> 4) "y"
=> 5) "c"
=> 6) "d"
LINSERT
可以在指定元素的前/后插入新元素。如果list中不存在指定值,返回-1。
LPOP lists => "f"
RPOP lists => "d"
LRANGE lists 0 -1
=> 1) "x"
=> 2) "a"
=> 3) "y"
=> 4) "c"
LPOP
/RPOP
会返回并移除队首/队尾的第一个元素。key不存在或list为空返回nil。
BLPOP
/BRPOP
是LPOP
/RPOP
的blocking版本。BLPOP
与BRPOP
的区别只是POP元素的位置不同,后面以BLPOP
为例展示用法以及优先级。
非阻塞
LRANGE list1 0 -1 => "(empty list or set)"
LRANGE list2 0 -1
=> 1) "a"
LRANGE list3 0 -1 => "(empty list or set)"
BLPOP list1 list2 list3 0
=> 1) "list2"
=> 2) "a"
BLPOP
的命令格式是BLPOP key [key ...] timeout
。timeout代表blocking的超时时间。BLPOP
命令会按顺序检查list1、list2、list3的值是否为空,返回第一个非空的key名与POP的值。
阻塞
LRANGE list1 0 -1 => "(empty list or set)"
LRANGE list2 0 -1 => "(empty list or set)"
LRANGE list3 0 -1 => "(empty list or set)"
BLPOP list1 list2 list3 10
=> "(nil)"
=> "(10.06s)"
client1
BLPOP list1 list2 list3 0
=> 1) "list3"
=> 2) "a"
=> (67.94s)
client2
LPUSH list3 "a"
第一次BLPOP
操作,10秒内没有获取到值,返回nil。
第二次BLPOP
操作,client1阻塞在BLPOP操作上,client2往list3中插入元素后,client1获得返回值。
哪个key、client、element优先?
当一个client尝试在多个key上执行BLPOP
操作,且不是所有key都为空,将会返回从左到右第一个非空的key。
当多个client阻塞在同一个key上,阻塞最久的client会优先获取值。另一种情况:
Client A: BLPOP foo 0 Client B: LPUSH foo a b c
Redis2.4返回"a",Redis2.6之后返回"c"。
LRANGE lists 0 -1
=> 1) "x"
=> 2) "a"
=> 3) "y"
=> 4) "c"
=> 5) "a"
=> 6) "x"
LREM lists -1 "x" => "(integer) 1"
LREM lists 2 "a" => "(integer) 2"
LREM lists 0 "y" => "(integer) 1"
LRANGE lists 0 -1
=> 1) "x"
=> 2) "c"
LREM
命令的格式是LREM key count value
。countyou三种取值:
-
-1 "x"
从队尾开始,删除1个"x"元素。 -
2 "a"
从队首开始,删除2个"a"元素。 -
0 "y"
删除所有的"y"元素。
LINDEX lists 1 => "c"
LINDEX
获取指定index位置的元素。LINDEX
也是一个O(N)的操作。
LRANGE lists 0 -1
=> 1) "x"
=> 2) "c"
=> 3) "q"
=> 4) "w"
=> 5) "e"
LTRIM lists 0 2 => "OK"
LRANGE lists 0 -1
=> 1) "x"
=> 2) "c"
=> 3) "q"
LTRIM
会按照start和end参数截断lists,只保留0到2的元素。
LRANGE list1 0 -1
=> 1) "c"
=> 2) "b"
=> 3) "a"
LRANGE list2 0 -1
=> 1) "z"
=> 2) "y"
=> 3) "x"
RPOPLPUSH list1 list2
=> "a"
LRANGE list1 0 -1
=> 1) "c"
=> 2) "b"
LRANGE list2 0 -1
=> 1) "a"
=> 2) "z"
=> 3) "y"
=> 4) "x"
RPOPLPUSH
会对list1做RPOP,然后使用list1 POP的值对list2做LPUSH操作。
模式-可靠队列
常用方式:生产者使用LPUSH
向队列中插入元素,消费者通过RPOP
或BRPOP
从队列中获取元素并处理。
问题:如果消费者获取到元素后马上就crash了,并没有进行业务操作,会造成消息丢失。
解决方案:两个队列,生产者使用LPUSH
向list1插入元素,消费者通过RPOPLPUSH
将list1最右元素POP,插入到list2队列中,list2队列是处理中队列。消费端业务代码执行完成后通过LREM
移出list2队列。可以单独设置一个监控client,负责处理长时间停留在list2队列中的元素。
模式-环形队列
RPOPLPUSH list1 list1
RPOPLPUSH
可以在N次操作后遍历一个长度为N的队列,且遍历后元素还存在于队列中。
应用场景:list1队列中保存着需要进行健康检查的地址列表。有三个client会从list1中获取地址,检查是否正常提供服务。使用RPOPLPUSH
可以确保:
1、多client,循环获取队列中的元素,每个client获取的元素不重复。
2、良好的扩展性,可以直接加入新client或地址。
BRPOPLPUSH
是RPOPLPUSH
的blocking版本。