« 食堂排队系统 | 返回首页 | 分享文件服务 »

ZeroMQ 的模式

在需要并行化处理数据的时候,采用消息队列通讯的方式来协作,比采用共享状态的方式要好的多。Erlang ,Go 都使用这一手段来让并行任务之间协同工作。

最近读完了 ZeroMQGuide。写的很不错。前几年一直有做类似的工作,但是自己总结的不好。而 ZeroMQ 把消息通讯方面的模式总结的很不错。

ZeroMQ 并不是一个对 socket 的封装,不能用它去实现已有的网络协议。它有自己的模式,不同于更底层的点对点通讯模式。它有比 tcp 协议更高一级的协议。(当然 ZeroMQ 不一定基于 TCP 协议,它也可以用于进程间和进程内通讯。)它改变了通讯都基于一对一的连接这个假设。

ZeroMQ 把通讯的需求看成四类。其中一类是一对一结对通讯,用来支持传统的 TCP socket 模型,但并不推荐使用。常用的通讯模式只有三类。

  1. 请求回应模型。由请求端发起请求,并等待回应端回应请求。从请求端来看,一定是一对对收发配对的;反之,在回应端一定是发收对。请求端和回应端都可以是 1:N 的模型。通常把 1 认为是 server ,N 认为是 Client 。ZeroMQ 可以很好的支持路由功能(实现路由功能的组件叫作 Device),把 1:N 扩展为 N:M (只需要加入若干路由节点)。从这个模型看,更底层的端点地址是对上层隐藏的。每个请求都隐含有回应地址,而应用则不关心它。

  2. 发布订阅模型。这个模型里,发布端是单向只发送数据的,且不关心是否把全部的信息都发送给订阅端。如果发布端开始发布信息的时候,订阅端尚未连接上来,这些信息直接丢弃。不过一旦订阅端连接上来,中间会保证没有信息丢失。同样,订阅端则只负责接收,而不能反馈。如果发布端和订阅端需要交互(比如要确认订阅者是否已经连接上),则使用额外的 socket 采用请求回应模型满足这个需求。

  3. 管道模型。这个模型里,管道是单向的,从 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 放到磁盘上。


对于网络游戏,我觉得基于 ZeroMQ 来架构服务器非常合适。对于玩家 Client - Server 部分倒不必使用 ZeroMQ ,而可以写一个前端程序,比如前些年写过的一篇 blog 中提到的连接服务器依然适用。这个连接服务器对内的服务集群则可以用 ZeroMQ 的协议通讯。

Comments

请教一个问题

我理解的是zeromq编程面向的是模式,屏蔽通信通道。
实际使用中,对象和对象通信的时往往是多种模式共存,所以看官方例子,一端 通信代理实现时,往往需要使用3-7个socket很正常。有点点浪费资源的感觉。
如果他只提供统一的通信通道,模式不加限制,有时用起来似乎更方便?比如把socket定义的模式相关信息塞到通信包中,自己处理。

方便就方便在不受限制。

@cloud
这是0mq作者用纯c写的另一套框架
应该更符和云兄的胃口
http://nanomsg.org/index.html

@云风, 你好.
我想知道你最后讲的"这个连接服务器对内的服务集群则可以用 ZeroMQ 的协议通讯。"

是否有个比较具体的方案, 比如你将组合哪几个zmq的模型去实现.

我想的, zmq的模型能够用在这种场景下的大概只有pub/sub, push/pull, 这两种上都是单向的, 而连接服务器与后端的服务集群应是双向的吧? 服务集群这时候怎么把处理结果返回给连接服务器呢?

blade兄,0mq 的书叫什么名字?可否发个链接

0mq 的书已经出来了,epub 和pdf版本都有,大家可以去看看,mq的架构还是有点意思的,用好不容易

@xuefli

zmq_msg_t 就是 mq 中的 m . 不用它还用 mq 干啥呢?

Cloud先生
不用zmq_msg_t和固定长度的缓冲,你怎么接收不同长度的数据包了、怎么合并处理业务上的分包的合并了,如果使用zeromq在公网上,会有更多的安全因素要考虑?谈那么多理论没用,至少在请求应答模式上,对于hwclient.c/hwserver.c我试过很多方式

我就是想把业务逻辑化解成很多分布的运行实例,相同的业务网逻辑可以多份部署在同一台机器或者不同的机器,业务和使用zeromq实现的支撑系统,相互不侵入,不关心部署的物理地址,不关心在哪台设备运行,不关心实例之间交互采用的通讯协议,也不单一依赖一种通讯协议,业务逻辑串行的组织,下面并行的运行,多爽

@xuefli

zeroMQ 首先是一个 MQ. zero 指它无独立服务器.

你先把 0mq 是什么,解决什么问题搞清楚.

然后研究一下 api 怎么用.

至少 0mq 不是用来取代 socket api 的.

Cloud,我用错了?
如果用同一个链路发送不同大小类型的包,如果不使用zmq_msg_t,你都不知道要分配多大的内存来接收zmq_recv的数据包。当然你可以固定假设最大长度,最大只接收这么多,其他的丢弃。protobuff原来的协议和原来一贯的写法都是数据包带头部(总长度、类型、事务号、校验码。。。),我是借用Multi-part Message 来实现带消息控制头的数据包,当然可以当在单包中

@xuefli

是你用错了.

Muti-part Message 不需要包长度.

任何时候都不需要包长度.

zeromq 我在mac lion上试验一把,官方的案例hwclient.c/hwserver.c 把发的包改成:包长度+包内容(就是Muti-part Message方式),用zmq_send/zmq_recv和zmq_msg_send/zmq_msg_recv,带ZMQ_SNDMORE/ZMQ_REVMORE都有问题,把ZMQ_REVMORE去掉就OK,zeromq还有很多要完善的,bug report我都找不到提交的地方,只要直接从man中找到的email地址发邮件给他们,样例代码和文档都不太好用。我原来用zeroc ice,这个开源系统这方面比zeromq做的好,至少我们已经用zero ice做过一些项目

Device存在单点,所以这部分也是很麻烦的

@伯诚

创建一个 inproc 的 socket, 把不同线程的 message 发到同一线程,再 send 出去.

云风大侠,貌似zeromq的socket_t对象并不是线程安全的,有什么办法可以解决recv和send操作在不同的线程中?

任何分布式,并行的需求,都可以用这三种模型组合起来解决问题。

终于知道“结构化网络编程”的意思了。

放心, 这不是 zeromq 的 feature

如果你碰到这个问题, 可以试着 fix 一下.

看资料有提到zeroMQ存在一个问题:在大量消息时会偶尔丢失消息。这个问题我没有验证过,不知道云风是否验证过?

所有的通信设施在使用和维护上都是复杂的, MQ系列也不例外.

忍不住想留两句,消息队列作为协作,在windows系统中就是如此,SendMessage更是协作的鼻祖!

ZeroMQ配合Protocol Buffer真是完美。

如果是单边路由的情况呢,就如QQ客户端可以主动连接腾讯服务器,但腾讯服务器不但主动连接QQ所有的局域网,必须由客户端发起才可以建立连接,这种情况下能使用ZeroMQ吗?很多大公司都会划分多个子网,往往会出现这种情况

以前用过TIBCO的消息通讯包,里面的消息通讯机制几乎已经全部cover了博文里提到的所有的机制。

第一次知道ZeroMQ,好好学习一下。

ZeroMQ 的 Guide的link已经变了:
http://zguide.zeromq.org/page:all

RabbitMQ也有类似的机制。

学习了

看了这篇文章才想起来前几天有人在twitter上也推荐这个,当时没看下去,惭愧

最近好像经常看到zeromq出现,
那篇文章真的好长呀.

第一次前排,占位。

Post a comment

非这个主题相关的留言请到:留言本