消息队列调研
消息队列
近几年有关”Message Queue”的项目层出不穷,知名的就有十几种,这主要是因为后摩尔定律时代,分布式处理逐渐成为主流,业界需要一套标准来解决分布式计算环境中节点之间的消息通信。几年的竞争下来,Apache基金会旗下的符合AMQP/1.0标准的RabbitMQ已经得到了广泛的认可,成为领先的MQ项目。
消息队列提供一个异步通信协议,这意味着该消息的发送者和接收者不需要在同一时间与消息队列进行交互。消息被放入队列保存,直到接收方处理他们。消息队列对于一条消息中传输的数据大小有显示或隐式的限制,这样队列中才能保持良好的的消息数量。
在需要并行化处理数据的时候,采用消息队列通讯的方式来协作,比采用共享状态的方式要好的多。Erlang ,Go 都使用这一手段来让并行任务之间协同工作。
选择消息系统根据业务需要需要考虑以下几个方面:
是否持久化
吞吐能力
高可用
分布式扩展能力
兼容现有协议
易于维护
避免单点故障
负载均衡
其他,如消息丢失和重复的处理
RabbitMQ
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。RabbitMQ实现了一个经纪人(Broker)构架,这意味着消息在发送给客户端时先在中心队列排队,对路由(Routing)、负载均衡(Load balance)或者数据持久化都有很好的支持。
不支持持久化。
ZeroMQ
ZeroMQ是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ的明确目标是“成为标准网络协议栈的一部分,之后进入Linux内核”。现在还未看到它们的成功。但是,它无疑是极具前景的、并且是人们更加需要的“传统”BSD套接字之上的一层封装。ZMQ让编写高性能网络应用程序极为简单和有趣。
ZeroMQ 并不是一个对 socket 的封装,不能用它去实现已有的网络协议。它有自己的模式,不同于更底层的点对点通讯模式。它有比 tcp 协议更高一级的协议。(当然 ZeroMQ 不一定基于 TCP 协议,它也可以用于进程间和进程内通讯。)它改变了通讯都基于一对一的连接这个假设。
ZeroMQ 把通讯的需求看成四类。其中一类是一对一结对通讯,用来支持传统的 TCP socket 模型,但并不推荐使用。常用的通讯模式只有三类。
请求回应模型。由请求端发起请求,并等待回应端回应请求。从请求端来看,一定是一对对收发配对的;反之,在回应端一定是发收对。请求端和回应端都可以是 1:N 的模型。通常把 1 认为是 server ,N 认为是 Client 。ZeroMQ 可以很好的支持路由功能(实现路由功能的组件叫作 Device),把 1:N 扩展为 N:M (只需要加入若干路由节点)。从这个模型看,更底层的端点地址是对上层隐藏的。每个请求都隐含有回应地址,而应用则不关心它。
发布订阅模型。这个模型里,发布端是单向只发送数据的,且不关心是否把全部的信息都发送给订阅端。如果发布端开始发布信息的时候,订阅端尚未连接上来,这些信息直接丢弃。不过一旦订阅端连接上来,中间会保证没有信息丢失。同样,订阅端则只负责接收,而不能反馈。如果发布端和订阅端需要交互(比如要确认订阅者是否已经连接上),则使用额外的 socket 采用请求回应模型满足这个需求。
管道模型。这个模型里,管道是单向的,从 PUSH 端单向的向 PULL 端单向的推送数据流。
任何分布式,并行的需求,都可以用这三种模型组合起来解决问题。ZeroMQ 只专注和解决了消息通讯这一基本问题,干的非常漂亮。
基于定义好的模型,我们可以看到,api 可以实现的非常简单易用。我们不再需要 bind/listen/accept 来架设服务器,因为这个模型天然是 1:N 而不是 1:1 的,不需要为每个通道保留一个句柄。我们也不必在意 server 是否先启动(bind),而后才能让 client 工作起来(connect)。
这以上模型中,关注的是通讯双方的职责,而不是实现的方式:监听端口还是连接对方端口。对于复杂的多进程协同工作的系统,不必纠结于进程启动的次序。
使用 ZeroMQ 不必在意底层实现是使用短连接还是长连接方式。ZeroMQ 中的 Transient (短暂) 和 Durable (持久) socket 也并非区别于实现层是否保持了 tcp 连接。而是概念上的不同。对于 Durable socket ,其生命期可以长于一个进程的生命期,即使进程退出,再次启动后依旧可以维持继续之前的 socket 。当然,这并不是帮助你挽救你的程序因出错而崩溃的。它只是提出这个模式,让你根据设计需要可以实现。对于 ZeroMQ ,如有需求(若内存有限),甚至把数据传输的 buffer 放到磁盘上。
不支持持久化。
Redis
Redis是一个开源、支持网络、基于内存、键值对存储数据库,使用ANSI C编写。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。而且支持string, set, zset, list, hash等多种类型数据结构,并且原生支持原子性操作。
支持持久化。
Kafka
Kafka(由LinkedIn开发,使用Scala编写)是一种分布式的,基于发布/订阅的消息系统。主要设计目标如下:
以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间复杂度的访问性能。
高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒100K条以上消息的传输。
支持Kafka Server间的消息分区,及分布式消费,同时保证每个Partition内的消息顺序传输。
同时支持离线数据处理和实时数据处理。
Scale out:支持在线水平扩展。
支持持久化。
ActiveMQ
Apache ActiveMQ是Apache软件基金会所研发的开放源码消息中间件;由于ActiveMQ是一个纯Java程式,因此只需要操作系统支援Java虚拟机,ActiveMQ便可执行。
ActiveMQ特色:
支援Java消息服务 (JMS) 1.1 版本
Spring Framework
集群 (Clustering)
支援的编程语言包括:C、C++、C#、Delphi、Erlang、Adobe Flash、Haskell、Java、JavaScript、Perl、PHP、Pike、Python和Ruby
协定支援包括:OpenWire、REST、STOMP、WS-Notification、XMPP以及AMQP
支持持久化。