1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Redis 笔记(04)— list类型(作为消息队列使用 在列表头部添加元素 尾部删除元

Redis 笔记(04)— list类型(作为消息队列使用 在列表头部添加元素 尾部删除元

时间:2023-06-13 08:06:44

相关推荐

Redis 笔记(04)— list类型(作为消息队列使用 在列表头部添加元素 尾部删除元

Redis的列表是链表而不是数组。这意味着list的插入和删除操作非常快,时间复杂度为O(1),但是索引定位很慢,时间复杂度为O(n)

当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。

Redis的列表结构常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进Redis的列表,另一个线程从这个列表中轮询数据进行处理。

Redis在列表元素较少的情况下会使用一块连续的内存来存储列表,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist

因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prevnext。所以Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

1. list 类型相关命令

2. 使用示例

127.0.0.1:6379> lpush list 1(integer) 1127.0.0.1:6379> lpush list 2(integer) 2127.0.0.1:6379> lpush list 3(integer) 3127.0.0.1:6379> lpush list 4(integer) 4127.0.0.1:6379> lpush list 5(integer) 5127.0.0.1:6379> lrange list 0 -11) "5"2) "4"3) "3"4) "2"5) "1"127.0.0.1:6379> lpop list"5"127.0.0.1:6379> rpop list"1"127.0.0.1:6379> lrange list 0 -11) "4"2) "3"3) "2"

127.0.0.1:6379> rpush list 1(integer) 4127.0.0.1:6379> rpush list -1(integer) 5127.0.0.1:6379> rpush list -2(integer) 6127.0.0.1:6379> lrange list 0 -11) "4"2) "3"3) "2"4) "1"5) "-1"6) "-2"127.0.0.1:6379> lset list 0 00OK127.0.0.1:6379> lrange list 0 -11) "00"2) "3"3) "2"4) "1"5) "-1"6) "-2"127.0.0.1:6379> llen list(integer) 6

lindex需要对链表进行遍历,性能随着参数index增大而变差。

127.0.0.1:6379> lindex -2(error) ERR wrong number of arguments for 'lindex' command127.0.0.1:6379> lindex list -2"-1"127.0.0.1:6379> lindex list 0"00"

ltrim和字面上的含义不太一样,个人觉得它叫lretain(保留) 更合适一些,因为ltrim跟的两个参数start_indexend_index定义了一个区间,在这个区间内的值,ltrim要保留,区间之外统统砍掉。我们可以通过ltrim来实现一个定长的链表,这一点非常有用。

index可以为负数,index=-1表示倒数第一个元素,同样index=-2表示倒数第二个元素。

127.0.0.1:6379> ltrim list 1 4OK127.0.0.1:6379> lrange list 0 -11) "3"2) "2"3) "1"4) "-1"127.0.0.1:6379> blpop list 31) "list"2) "3"127.0.0.1:6379> brpop list 21) "list"2) "-1"127.0.0.1:6379>

3. 消息队列

Redislist(列表) 数据结构常用来作为异步消息队列使用,使用rpush/lpush操作入队列,使用lpoprpop来出队列。

lpushrpop命令可以实现队列功能,只需要生产者将任务使用lpush命令加入到某个键中,而消费者使用rpop命令将任务从对应的键中取出来即可。

brpop命令和rpop命令相似,区别在于brpop是阻塞式的,当队列中没有任务时,brpop命令会一直阻塞住连接,直到队列中有任务。

brpop命令格式

brpop key seconds

seconds为 0 表示不限制等待时间,即永远阻塞下去。

3.1 队列空情况

客户端是通过队列的pop操作来获取消息,然后进行处理。处理完了再接着获取消息,再进行处理。如此循环往复,这便是作为队列消费者的客户端的生命周期。

如果队列空了,客户端就会陷入pop的死循环,不停地pop,没有数据,接着再pop,又没有数据。这就是浪费生命的空轮询。空轮询不但拉高了客户端的CPURedisQPS也会被拉高。

通常我们使用sleep来解决这个问题,让线程睡一会,睡个 1s 钟就可以了。不但客户端的CPU能降下来,RedisQPS也降下来了。

time.sleep(1) # python 睡 1s

3.2 阻塞队列

用上面睡眠的办法可以解决问题。但是有个小问题,那就是睡眠会导致消息的延迟增大。更好的解决方法是使用blpop/brpop,这两个指令的前缀字符b代表的是blocking,也就是阻塞读。

阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。消息的延迟几乎为零。用blpop/brpop替代前面的lpop/rpop可以完美解决队列延迟问题。

3.3 空闲连接自动断开

如果线程一直阻塞在哪里,Redis的客户端连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减少闲置资源占用。这个时候blpop/brpop会抛出异常来。

所以编写客户端消费者的时候要小心,注意捕获异常,还要重试。

代码参考:

玩转 Redis:简单消息队列

玩转 Redis — 延时消息队列

Redis 笔记(04)— list类型(作为消息队列使用 在列表头部添加元素 尾部删除元素 查看列表长度 遍历指定列表区间元素 获取指定区间列表元素 阻塞式获取列表元素)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。