doc: 阅读redis lists文档

This commit is contained in:
asahi
2025-09-06 15:45:17 +08:00
parent 20578b535e
commit a9057466a8

View File

@@ -50,6 +50,12 @@
- [Redis List Impl](#redis-list-impl)
- [`LPUSH, RPUSH`](#lpush-rpush)
- [`LRANGE`](#lrange)
- [`LPOP, RPOP`](#lpop-rpop)
- [Common use cases for lists](#common-use-cases-for-lists)
- [Capped lists - `latest n`](#capped-lists---latest-n)
- [Blocking operations on lists](#blocking-operations-on-lists)
- [BRPOP](#brpop)
- [Automatic Creation and removal of keys](#automatic-creation-and-removal-of-keys)
# redis
@@ -700,3 +706,148 @@ LPUSH和RPUSH接收的参数都是可变的在单次调用中可以向list中
2) "bike:1"
3) "bike:2"
```
#### `LPOP, RPOP`
lists支持pop元素从list中移除元素并且获取元素的值。lists支持从list的左端和右端pop元素使用示例如下所示
```redis-cli
> RPUSH bikes:repairs bike:1 bike:2 bike:3
(integer) 3
> RPOP bikes:repairs
"bike:3"
> LPOP bikes:repairs
"bike:1"
> RPOP bikes:repairs
"bike:2"
> RPOP bikes:repairs
(nil)
```
#### Common use cases for lists
redis lists拥有如下有代表性的用例场景
- 记录用户最新上传的推文
- 用于进程间的通信使用consumer-producer pattern其中生产者向lists中推送内容而消费者消费lists中的内容
#### Capped lists - `latest n`
在许多用例场景下会使用lists来存储latest items例如`social network updates, logs`等。
redis允许将lists作为`拥有容量上限的集合使用`,可以通过`LTRIM`命令来实现`only remembering the latest N items and discarding all the oldest items`。
`LTRIM`命令和`LRANGE`类似,但是`LRANGE`用于获取获取list中指定范围内的元素`LTRIM`会将选中的范围作为`new list value`所有位于选中范围之外的元素都会从list中被移除。
`LTRIM`的使用示例如下所示:
```redis-cli
> RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5
(integer) 5
> LTRIM bikes:repairs 0 2
OK
> LRANGE bikes:repairs 0 -1
1) "bike:1"
2) "bike:2"
3) "bike:3"
```
`LTRIM 0 2`会令redis保留index位于`[0, 2]`范围内的3个元素并且移除其他的元素。将`push操作`和`LTRIM`操作组合,可以实现`add a new element and discard elements exceeding a limt`的操作。
例如,使用`LRANGE -3 -1`可用于实现`仅保留最近添加的三个元素`的场景
```redis-cli
> RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5
(integer) 5
> LTRIM bikes:repairs -3 -1
OK
> LRANGE bikes:repairs 0 -1
1) "bike:3"
2) "bike:4"
3) "bike:5"
```
#### Blocking operations on lists
lists的`blocking operation`特性令其适合用于实现queues并广泛用于进程间通信系统。
在通过redis lists实现进程间通信系统时如果某些时刻list为空并不存在任何元素那么此时消费者client在调用`pop`操作时只会返回为空。通常来讲consumer会等待一定的时间并且重新尝试调用pop该操作被称为`polling`,其通常被认为是一种不好的实现:
- 其会强制redis/client来处理无用的命令(`当list为空时pop请求只会返回为空而不会任何的实际处理`)
- 会增加`delay to processing of items`因为worker在接收到redis server返回的null时其会等待一定的时间。为了令delay更小可以在调用POP操作之间等待更短的时间但是其可能方法前一个问题(`当pop调用之间的时间间隔更小时redis server可能会处理更多的无用命令`)
故而redis实现支持`BRPOP`和`BLPOP`命令其命令在list为空时会阻塞`上述命令造成的阻塞会在list中被添加新元素时返回如果直到设置的超时到达后该操作也会返回`。
`BRPOP`的使用示例如下所示:
```redis-cli
> RPUSH bikes:repairs bike:1 bike:2
(integer) 2
> BRPOP bikes:repairs 1
1) "bikes:repairs"
2) "bike:2"
> BRPOP bikes:repairs 1
1) "bikes:repairs"
2) "bike:1"
> BRPOP bikes:repairs 1
(nil)
(2.01s)
````
上述示例中,`BRPOP bikes:repairs 1`代表`wait for elements in the list bikes:repairs`,但是`当list中元素为空时最多等待1s。`
当为`BRPOP`指定timeout为0时代表会永久等待elements。并且`可以为BRPOP`命令指定多个lists其会`等待所有的list并且当任何一个list中接收到元素时当前BRPOP命令会立刻返回`。
示例如下:
```redis-client
# client 1 等待 event-queue:1, event-queue:2, event-queue:3三个list
client 1> brpop event-queue:1 event-queue:2 event-queue:3 1000
# client 2 向event-queue:2 中追加元素
client 2> rpush event-queue:2 baka
(integer) 1
# client 1 立刻返回,返回结果如下
1) "event-queue:2"
2) "baka"
(19.55s)
```
##### BRPOP
- 对于`BRPOP`命令造成的阻塞,其处理是按照顺序的:`the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth`
- `BRPOP`命令的返回结果其结构和`RPOP`命令不同:`BRPOP`返回的是一个包含两个元素的array`arrary[0]`为list对应的key`array[1]`为弹出的元素因为BRPOP可以等待多个list
- 如果超时后list中仍然没有可获取的元素那么将会返回null
#### Automatic Creation and removal of keys
在先前示例中向list中添加元素时并没有预先创建空的list或是在list中没有元素时将list手动移除。
在redis中`list的创建和删除都是redis的职责`
- 当list中不再包含元素时redis会自动删除list对应的key
- 当想要对不存在的key中添加元素时redis会自动创建一个empty list
故而,可以整理除如下准则:
- 当将元素添加到一个聚合数据类型时如果target key不存在那么在添加元素前一个empty aggregate data type将会被自动创建
- 当从aggregate data type中移除元素时如果移除后该aggregate data type中为空那么key将会被自动销毁`stream data type`除外)
- 调用一个read-only command例如`LLEN`或write command用于移除元素对一个`empty key`做操作时,其返回结果和针对`an key holding an empty aggregate type of type the command expects to find`的操作一直
上述三个准则的示例如下:
准则1示例如下所示当new_bikes不存在时通过`LPUSH`命令向其中添加元素一个empty list在添加前会自动创建
```redis-cli
> DEL new_bikes
(integer) 0
> LPUSH new_bikes bike:1 bike:2 bike:3
(integer) 3
```
准则2示例如下所示当pop出所有的元素后key将会被自动销毁通过`EXISTS`命令返回的结果为0
```redis-cli
> LPUSH bikes:repairs bike:1 bike:2 bike:3
(integer) 3
> EXISTS bikes:repairs
(integer) 1
> LPOP bikes:repairs
"bike:3"
> LPOP bikes:repairs
"bike:2"
> LPOP bikes:repairs
"bike:1"
> EXISTS bikes:repairs
(integer) 0
```
准则3的示例如下所示当key不存在时对该key进行`read-only`操作和`remove element`操作所返回的结果,和对`empty aggregated data type`操作所返回的结果一致:
```redis-cli
> DEL bikes:repairs
(integer) 0
> LLEN bikes:repairs
(integer) 0
> LPOP bikes:repairs
(nil)
```