一、ZeroMQ 的背景介绍
引用官方的说法: “ZMQ (以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ 的明确目标是“成为标准网络协议栈的一部分,之后进入 Linux 内核”。现在还未看到它们的成功。但是,它无疑是极具前景的、并且是人们更加需要的“传统”BSD 套接字之上的一层封装。ZMQ 让编写高性能网络应用程序极为简单和有趣。”
近几年有关”Message Queue”的项目层出不穷,知名的就有十几种,这主要是因为后摩尔定律时代,分布式处理逐渐成为主流,业界需要一套标准来解决分布式计算环境中节点之间的消息通信。几年的竞争下来,Apache 基金会旗下的符合 AMQP/1.0标准的 RabbitMQ 已经得到了广泛的认可,成为领先的 MQ 项目。
与 RabbitMQ 相比,ZMQ 并不像是一个传统意义上的消息队列服务器,事实上,它也根本不是一个服务器,它更像是一个底层的网络通讯库,在 Socket API 之上做了一层封装,将网络通讯、进程通讯和线程通讯抽象为统一的 API 接口。
二、ZMQ 是什么?
阅读了 ZMQ 的 Guide 文档后,我的理解是,这是个类似于 Socket 的一系列接口,他跟 Socket 的区别是:普通的 socket 是端到端的(1:1的关系),而 ZMQ 却是可以N:M 的关系,人们对 BSD 套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而 ZMQ 屏蔽了这些细节,让你的网络编程更为简单。ZMQ 用于 node 与 node 间的通信,node 可以是主机或者是进程。
三、本文的目的
在集群对外提供服务的过程中,我们有很多的配置,需要根据需要随时更新,那么这个信息如果推动到各个节点?并且保证信息的一致性和可靠性?本文在介绍 ZMQ 基本理论的基础上,试图使用 ZMQ 实现一个配置分发中心。从一个节点,将信息无误的分发到各个服务器节点上,并保证信息正确性和一致性。
四、ZMQ 的三个基本模型
ZMQ 提供了三个基本的通信模型,分别是“Request-Reply “,”Publisher-Subscriber“,”Parallel Pipeline”,我们从这三种模式一窥 ZMQ 的究竟
ZMQ 的 hello world!
由 Client 发起请求,并等待 Server 回应请求。请求端发送一个简单的 hello,服务端则回应一个 world。请求端和服务端都可以是 1:N 的模型。通常把 1 认为是 Server ,N 认为是 Client 。ZMQ 可以很好的支持路由功能(实现路由功能的组件叫作 Device),把 1:N 扩展为N:M (只需要加入若干路由节点)。如图 1 所示:
图1:ZMQ 的 Request-Reply 通信
服务端的 php 程序如下:
<?php
/*
* Hello World server
* Binds REP socket to tcp://*:5555
* Expects "Hello" from client, replies with "World"
* @author Ian Barber <ian (dot) barber (at) gmail (dot) com>
*/
$context = new ZMQContext (1);
// Socket to talk to clients
$responder = new ZMQSocket ($context, ZMQ::SOCKET_REP);
$responder->bind ("tcp://*:5555");
while(true) {
// Wait for next request from client
$request = $responder->recv ();
printf ("Received request: [%s]\n", $request);
// Do some 'work'
sleep (1);
// Send reply back to client
$responder->send ("World");
}
Client 程序如下:
<?php
/*
* Hello World client
* Connects REQ socket to tcp://localhost:5555
* Sends "Hello" to server, expects "World" back
* @author Ian Barber <ian (dot) barber (at) gmail (dot) com>
*/
$context = new ZMQContext ();
// Socket to talk to server
echo "Connecting to hello world server...\n";
$requester = new ZMQSocket ($context, ZMQ::SOCKET_REQ);
$requester->connect ("tcp://localhost:5555");
for($request_nbr = 0; $request_nbr != 10; $request_nbr++) {
printf ("Sending request %d...\n", $request_nbr);
$requester->send ("Hello");
$reply = $requester->recv ();
printf ("Received reply %d: [%s]\n", $request_nbr, $reply);
}
从以上的过程,我们可以了解到使用 ZMQ 写基本的程序的方法,需要注意的是:
a) 服务端和客户端无论谁先启动,效果是相同的,这点不同于 Socket。
b) 在服务端收到信息以前,程序是阻塞的,会一直等待客户端连接上来。
c) 服务端收到信息以后,会 send 一个“World”给客户端。值得注意的是一定是 client 连接上来以后,send 消息给 Server,然后 Server 再 rev 然后响应 client,这种一问一答式的。如果 Server 先 send,client 先 rev 是会报错的。
d) ZMQ 通信通信单元是消息,他除了知道 Bytes 的大小,他并不关心的消息格式。因此,你可以使用任何你觉得好用的数据格式。Xml、Protocol Buffers、Thrift、json 等等。
e) 虽然可以使用 ZMQ 实现 HTTP 协议,但是,这绝不是他所擅长的。