在.NET上使用ZeroMQ
前言
最近在设计一个Web系统(公司在建项目,故保密不能详述),要满足高并发,高访问量、高可靠性的需求,又会涉及到多种业务外部系统,甚至业务可能是可“热插拔”的形式,同时又要最求成本最低。
考虑到总总因素,排除了使用Oracle数据库,以及其他各种商业组件的方案;同时又由于公司项目很多,缺乏人手来自己开发一些组件,故除了业务系统是自己开发外,其他基本上采用了清一色的开源软件。 由于业务比较复杂,同时大量使用了各种开源系统,会使用到C++, Java, Erlang, C#, PHP等众多语言。故设计用系统总线(Bus)来作为消息的介质,协调整体的运行,而这条总线的性能和特性也将关系到系统的命运。
RabbitMQ or ZeroMQ?
经过比较选型,从多语言的支持的角度,最后筛选得到RabbitMQ和ZeroMQ两个选择。
RabbitMQ是采用Erlang开发的,支持完善的AMQP协议;ZeroMQ使用C语言开发,重点在于效率;两者均有多语言支持,其中ZeroMQ支持得较多。
比较看, RabbitMQ支持的AMQP协议,较为完整和复杂;而ZeroMQ的接口极为简单。速度上,还未对亲自对两者做压力测试。从网上的资料看,RabbitMQ较慢,几十个并发以内,延时为几十毫秒,但当客户端达到1000个并发的时候,速度就无法容忍了(参考);ZeroMQ上则据称可以达到13毫米延时和高达每秒4.1兆次传递(参考, 国内需要翻墙才能访问)。如果队列较多的话,RabbitMQ很容易把内存耗尽,而ZeroMQ则把队列内容保存在发送端。
故最终还是决定选择了ZeroMQ,然后在上面加一层我自己的封装,作为Web系统的消息总线。
在.NET上使用ZeroMQ
ZeroMQ的.NET封装很简单,基本上是来自C-API的,但有所简化。使用上,由于习惯了在C#里面用强类型约束,API上的int类型让我感觉封装得"非常不.NET"。
首先要明确下ZeroMQ的几个概念:
1. Exchange & Queue:Exchange 是系统数据交换的基础,Queue是消息通道,当Exchange与Queue绑定后,向Exchange提交消息,就会流到其绑定的Queue(s)中。
2. 接收端创建一个Queue后,就能从里面获取内容。
3.Zmq_server: 这个是ZeroMQ消息的核心程序,负责调度消息,是ZeroMQ系统的"CPU"。
由于是轻量级的,在.NET下使用ZeroMQ也非常简单:
1. libclrzmq.dll 是封装过的.NET客户端,引用之。运行的时候记得把zeromq的bin下的其他dll也复制过去。
2. 运行zmq_server.exe服务:
zmq_server --port 5555
其中,5555是服务的端口。也可以用--config来指定配置文件,这里不详述。
3. 消息发送与接收:
发送端:
Zmq q = new Zmq();
q.Open("127.0.0.1:5555");
int ex = q.CreateExchange("EX1", null, Zmq.SCOPE_LOCAL, Zmq.STYLE_LOAD_BALANCING);
Zmq.Bind("EX1","Q1", null, null);
Zmq.Send(ex, new byte[]{1,2,3,5}, false);
接收端:
Zmq q = new Zmq();
q.Open("127.0.0.1:5555");
int ex = q.CreateQueue("Q1", Zmq.SCOPE_GLOBAL, "127.0.0.1:5556",Zmq.NO_LIMIT,Zmq.NO_LIMIT, Zmq.NO_SWAP);
int outType;
byte[] data;
Zmq.Receive( out data, out outType, true);//阻塞方式接收
上面代码中,STYLE_LOAD_BALANCING表示数据被一个接收端接收到后就结束,若改为STYLE_DATA_DISTRIBUTION则表示数据将会发送到每个接收端上。
此外,根据官方的文档:
SCOPE_LOCAL:
Local scope means that the object (exchange or queue) is visible only within the engine that created it.
SCOPE_PROCESS:
Process scope means that the object is visible to all the engines within the process registered with the same dispatcher object.
SCOPE_GLOBAL:
Global scope means that the object is visible to all the 0MQ processes registered with the same zmq_server.
注意事项,上述程序的接收端需要先启动,然后再启动发送端,否则发送端在BindQ1的时候将找不到队列而出错。

The 在.NET上使用ZeroMQ by Neio Notes, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
国内能写,能用zero mq 的,好样的。
祝你成为架构师
@GoodLuck: 谢谢支持。
很多东西都还在摸索学习。
why not qpid?
@asuran:
The Apache Qpid is a very good option, too. Actually, in the implementation of this project, I used RabbitMQ(AMPQ), 0MQ, but also the Thrift. Each has its own advantage.
I chose the RabbitMQ just because it was witten in Erlang, which is a very impressive language and may be very welcome in the future.
你好,现在我用的是0mq的1.0.1版本,照您提供的例子,在单机上运行没问题。但是在网络上用时,接收端就会出现C++ Runtime Error。请您不吝赐教。
可喜,有很多人开始关注0MQ了。
谁能比较一下0MQ与OpenMQ吗,优势和缺点等等
请问zeromq有没有php的类库?
C库都有,PHP类库还不容易啊?为啥不自己写一个呢?
不错,玩的就是技术,就是为你在WIN 下面搞 感觉不爽
不知道对rabbitmq的速度有没有亲自的测试..
我准备研究研究它的使用.
现在最新版本是:zeromq-2.0.10,里边没有zmq_server.exe服务呀,怎么使用的?