本章节将学习如何使用Redis来构建任务队列,实现类似RabbitMQ之类的消息队列的功能。
先进先出队列
依然使用之前虚构的例子,现在来实现通过电子邮件来订阅商品交易市场中已售出的商品的相关信息。因为对外发电子邮件可能会有非常高的延迟,甚至可能会出现发送失败的情况,所以将使用任务队列来记录邮件的收信人以及发送邮件的原因,并构建一个可以在邮件发送服务器运行变得缓慢的时候,以并行方式一次发送多封邮件的工作进程。我们要编写的队列将以“先到先服务”的方式发送邮件,并且无论发送是否成功,程序都会把结果记录到日志中。
邮件队列采用List构成,存储JSON格式的字符串,数据结构如下:
- key
- queue:email
- list value
- “{“seller_id”:1,”item_id”:”Item_M”,”price”:97,”buyer_id”:27,”time”:1482399576744}”
- ××××××
|
|
上面已经实现了简单的队列,下面再看下如果要执行的任务不止一种,该怎么办?
多个可执行任务
将采用注册回调函数的方式来实现执行指定的任务,队列中存储的格式为[FUNCTION_NAME,[ARG1,ARG2,ARG3…]],书上的例子是python写的,动态语言实现这样的功能非常方便,但是用Java来写的话,就有点恶心了,还是简单来实现下吧。数据格式如下:
- key
- queue:task
- list value
- “[SendEmailTask,[1,Item_M,97,99]]”
- ××××××
|
|
任务优先级
假如多个任务之间存在优先级,上面一个例子实现了发送邮件任务,现在有另外任务需要发送消息,发送邮件的优先级比发送消息高。这个问题也很容易解决。BLPOP天然支持,因为BLPOP可以接收多个队列,当给定多个key参数时,按参数key的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。只需要稍微修改下上述处理任务的方法即可:
延迟任务
本节尝试构造一个具有延迟执行任务的队列,将所有需要在未来执行的任务都添加到有序集合中,并将任务的执行时间设置分值,另外再使用一个进程来查找有序集合中是否存在可以立即被执行的任务,如果有的话,就从有序集合中移除那个任务,并将任务重新添加到适当的任务队列中,来实现延迟特性。
有序集合队列存储的每个被延迟执行的任务是一个包含4个值的JSON串,分别为:唯一标识符、处理任务的队列的名字、处理任务的回调函数的名字、传给回调函数的参数。格式如下:
- key
- delayed:
- list value
- “{“task_id”:aa-bb-cc,”queue_name”:”queue:email”,”function_name”:”SendEmailTask”,”args”:[“1”, “Item_M”, “97”, “99”]}”
- ××××××
|
|
Redis构建队列的学习就到此结束,示例代码可能无法直接使用到实际项目中,但是其实现思路以及对Redis数据结构的使用还是值得学习的。