消息传递的不同方式
消息传递:点对点与消息代理
向消费者通知新事件的常用方式是使用消息传递系统(messaging system
通过管道或数据库
像生产者和消费者之间的
同理,文件或数据库就足以连接生产者和消费者:生产者将其生成的每个事件写入数据存储,且每个消费者定期轮询数据存储,检查自上次运行以来新出现的事件。这实际上正是批处理在每天结束时处理当天数据时所做的事情。但当我们想要进行低延迟的连续处理时,如果数据存储不是为这种用途专门设计的,那么轮询开销就会很大。轮询的越频繁,能返回新事件的请求比例就越低,而额外开销也就越高。相比之下,最好能在新事件出现时直接通知消费者。数据库在传统上对这种通知机制支持的并不好,关系型数据库通常有 触发器(trigger
直接从生产者传递给消费者
许多消息传递系统使用生产者和消费者之间的直接网络通信,而不通过中间节点:
UDP 组播广泛应用于金融行业,例如股票市场,其中低时延非常重要。虽然UDP 本身是不可靠的,但应用层的协议可以恢复丢失的数据包(生产者必须记住它发送的数据包,以便能按需重新发送数据包) 。- 无代理的消息库,如
ZeroMQ 和nanomsg 采取类似的方法,通过TCP 或IP 多播实现发布/ 订阅消息传递。 StatsD 和Brubeck 使用不可靠的UDP 消息传递来收集网络中所有机器的指标并对其进行监控。 (在StatsD 协议中,只有接收到所有消息,才认为计数器指标是正确的;使用UDP 将使得指标处在一种最佳近似状态。- 如果消费者在网络上公开了服务,生产者可以直接发送
HTTP 或RPC 请求将消息推送给使用者。这就是webhooks 背后的想法,一种服务的回调URL 被注册到另一个服务中,并且每当事件发生时都会向该URL 发出请求。

尽管这些直接消息传递系统在设计它们的环境中运行良好,但是它们通常要求应用代码意识到消息丢失的可能性。它们的容错程度极为有限:即使协议检测到并重传在网络中丢失的数据包,它们通常也只是假设生产者和消费者始终在线。如果消费者处于脱机状态,则可能会丢失其不可达时发送的消息。一些协议允许生产者重试失败的消息传递,但当生产者崩溃时,它可能会丢失消息缓冲区及其本应发送的消息,这种方法可能就没用了。
消息代理/ 消息中间件
一种广泛使用的替代方法是通过消息代理(message broker
通过将数据集中在代理上,这些系统可以更容易地容忍来来去去的客户端(连接,断开连接和崩溃
排队的结果是,消费者通常是
消息代理与数据库对比
有些消息代理甚至可以使用
- 数据库通常保留数据直至显式删除,而大多数消息代理在消息成功递送给消费者时会自动删除消息。这样的消息代理不适合长期的数据存储。
- 由于它们很快就能删除消息,大多数消息代理都认为它们的工作集相当小—— 即队列很短。如果代理需要缓冲很多消息,比如因为消费者速度较慢(如果内存装不下消息,可能会溢出到磁盘
) ,每个消息需要更长的处理时间,整体吞吐量可能会恶化。 - 数据库通常支持二级索引和各种搜索数据的方式,而消息代理通常支持按照某种模式匹配主题,订阅其子集。机制并不一样,对于客户端选择想要了解的数据的一部分,这是两种基本的方式。
- 查询数据库时,结果通常基于某个时间点的数据快照;如果另一个客户端随后向数据库写入一些改变了查询结果的内容,则第一个客户端不会发现其先前结果现已过期(除非它重复查询或轮询变更
) 。相比之下,消息代理不支持任意查询,但是当数据发生变化时(即新消息可用时) ,它们会通知客户端。
这是关于消息代理的传统观点,它被封装在诸如