一日一技:隐患——redis-py的blpop可能因为网络波动致使收不到信息

一日一技:隐患——redis-py的blpop可能因为网络波动致使收不到信息

一日一技:隐患——redis-py的blpop可能因为网络波动致使收不到信息

摄影:产品经理
厨师:kingname
咱们在使用Redis作消息队列的时候,经常使用列表这个数据结构,并写出以下的代码:redis

import redis
import time

client = redis.Redis()
while True:
    data = client.lpop('key')
    if not data:
        time.sleep(5 * 60)
        continue
    parse(data)

这个意思是说,若是Redis的名为 key的列表里面有数据,那么就不停取出来,并把取出的数据传入 parse函数进行处理。若是列表里面没有数据,那么就等待5分钟再次检查。markdown

这种方式,若是列表始终为空,那么将会每5分钟检查一次。网络

但使用这种方式有一个问题,例如刚刚检查完列表发现是空的,程序开始等待5分钟。可是检查完成的1秒之后,新信息抵达列表。此时信息没法被马上消费,必须要等满5分钟才行。数据结构

为了解决实时性的问题,使用了列表的阻塞式弹出命令 blpop,因而代码变为:ide

import redis

client = redis.Redis()
while True:
    data = client.blpop('key')
parse(data[1])

若是列表里面没有数据,程序就会卡在 data=client.blpop('key')这一行,直到列表里面有了新的数据,再马上弹出送进后面的逻辑。函数

这种方法在测试的时候完美运行,因而就放到了生成环境使用。测试

一个周末过去了,周一上班时,同事反馈写到Redis里面的信息不能被正常消费了。code

可是我发现程序正常运行,并无出现任何异常。blog

因而我找 redis-py的做者 AndyMcCurdy询问缘由,他给个人回复以下图所示。队列

一日一技:隐患——redis-py的blpop可能因为网络波动致使收不到信息

意思是说,在使用 blpop的时候,若是中途由于网络波动或者某些其余缘由致使链接池失效,那么就永远接收不到信息了,虽然 redis-py有链接状态检查的功能,可是因为程序是阻塞的, redis-py的链接状态检查功能不能正常使用。

为了解决这个问题,就须要 blpop的超时功能。让 blpop每几分钟就断开,检查一下网络,再从新连上。

因而代码变为:

import redis

client = redis.Redis()
while True:
    data = client.blpop('key', timeout=5 * 60)
    if not data:
        continue
    parse(data[1])

设置超时时间为5分钟,若是5分钟内列表没有收到信息(不管是真的列表一直没有数据,仍是链接池断开了),都会返回 None,此时只须要从新执行 blpop,在执行的瞬间会检查链接的状态,若是链接池有问题,那么它会从新链接。

若是5分钟内有数据,那么 blpop就会马上把数据弹出来。

经过添加超时时间,解决了数据实时性和网络链接丢失的问题。

相关文章
相关标签/搜索