Disque 是 Redis 之父 Salvatore Sanfilippo 新开源的一个分布式内存消息代理。它适应于“Redis 作为作业队列”的场景,但采用了一种专用、独立、可扩展且具有容错功能的设计,兼具 Redis 的简洁和高性能,并且用 C 语言实现为一个非阻塞网络服务器。有一点需要提请读者注意,在 Disque 项目文档及本文中,“消息(Message)”和“作业(Job)”可互换。
Disque 是一个独立于 Redis 的新项目,但它重用了 Redis 网络源代码、节点消息总线、库和客户端协议的一大部分。由于 Disque 使用了与 Redis 相同的协议,所以可以直接使用 Redis 客户端连接 Disque 集群,只是需要注意,Disque 的默认端口是 7711,而不是 6379。
作为消息代理,Disque 充当了需要进行消息交换的进程之间的一个中间层,生产者向其中添加供消费者使用的消息。这种生产者 - 消费者队列模型非常常见,其主要不同体现在一些细节方面:
- Disque 是一个同步复制作业队列,在默认情况下,新增任务会复制到 W 个节点上,W-1 个节点发生故障也不会影响消息的传递。
- Disque 支持至少一次和至多一次传递语义,前者是设计和实现重点,而后者可以通过将重试时间设为 0 来实现。每个消息的传递语义都是单独设置的,因此,在同一个消息队列中,语义不同的消息可以共存。
- 按照设计,Disque 的至少一次传递是近似一次传递,它会尽力避免消息的多次传递。
- Disque 集群的所有节点都有同样的角色,也就是“多主节点(multi-master)”。生产者和消费者可以连接到不同的队列或节点,节点会根据负载和客户端请求自动交换消息。
- Disque 支持可选的异步命令。在这种模式下,生产者在向一个复制因子不为 1 的队列中添加一个作业后,可以不必等待复制完成就可以转而执行其它操作,节点会在后台完成复制。
- 在超过指定的消息重试时间后,Disque 会自动将未收到响应的消息重新放入队列。
- 在 Disque 中,消费者使用显式应答来标识消息已经传递完成。
- Disque 只提供尽力而为排序。队列根据消息创建时间对消息进行排序,而创建时间是通过本地节点的时钟获取的。因此,在同一个节点上创建的消息通常是按创建顺序传递的,但 Disque 并不提供严格的 FIFO 语义保证。比如,在消息重新排队或者因为负载均衡而移至其它节点时,消息的传递顺序就无法保证了。所以,Salvatore 指出,从技术上讲,Disque 严格来说并不是一个队列,而更应该称为消息代理。
- Disque 通过四个参数提供了细粒度的作业控制,分别是复制因子(指定消息的副本数)、延迟时间(将消息放入队列前的最小等待时间)、重试时间(设置消息何时重新排队)、过期时间(设置何时删除消息)。
需要注意的是,Disque 项目尚处于 Alpha 预览测试阶段,代码和算法未经充分测试,还不适合用于生产环境。在接下来的几个月里,其实现和 API 很可能会发生重大变化。此外,它还有如下限制:
- 其中还包含许多没有用到的 Redis 代码;
- 它并非源于 Salvatore 的项目需求,而是源于他看到人们将 Redis 用作队列,但他不是这方面的专家;
- 同 Redis 一样,它是单线程的,但鉴于它所操作的数据结构并不复杂,将来可以考虑改为多线程;
- Disque 进程中的作业数量受可用内存限制;
- Disque 没有进行性能优化。
总之,该项目尚处于研究测试阶段。感兴趣的读者可以查看该项目的 GitHub 页面,了解更多信息。
感谢郭蕾对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。
评论