Zeromq基本模型

Zeromq基本模型

 

http://www.searchtb.com/2012/08/zeromq-primer.html

http://www.kuqin.com/algorithm/20120813/328769.html

1.Request-reply模式

 

说明:步调一致的同步请求应答模式,发送request之后必须等待reply才能继续发送request;

Client端 一般先send request 后 receive reply;

server端 一般先 receive request后 send reply。

该模式的简单使用例程 流程如下:

Start Start

 

 

Client send the request

Server receive the request

Client receive the answer

Server send the answer

 

 

 

 

 

 

 

End End

 

 

 

a) 服务端和客户端无论谁先启动,效果是相同的,这点不同于Socket。

b) 在服务端收到信息以前,程序是阻塞的,会一直等待客户端连接上来。

c) 服务端收到信息以后,会send一个“World”给客户端。值得注意的是一定是client连接上来以后,send消息给Server,然后Server再rev然后响应client,这种一问一答式的。如果Server先send,client先rev是会报错的。

 

// Hello World server

// Binds REP socket to tcp://*:5555

// Expects "Hello" from client, replies with "World"

//

#include

#include

#include

#include

 

int main (void)

{

void *context = zmq_ctx_new ();

 

// Socket to talk to clients

void *responder = zmq_socket (context, ZMQ_REP);

zmq_bind (responder, "tcp://*:5555");

 

while (true) {

// Wait for next request from client,

//do the zmq_msg_recv before zmq_msg_send

zmq_msg_t request;

zmq_msg_init (&request);

//Receiving "Hello" from client through the responder

zmq_msg_recv (&request, responder, 0);

zmq_msg_close (&request);

 

// Do some 'work'

sleep (1);

 

// Send reply back to client

zmq_msg_t reply;

zmq_msg_init_size (&reply, 5);

memcpy (zmq_msg_data (&reply), "World", 5);

// Send "world" to the client through responder

zmq_msg_send (&reply, responder, 0);

zmq_msg_close (&reply);

}

// We never get here but if we did, this would be how we end

zmq_close (responder);

zmq_ctx_destroy (context);

return 0;

}

 

 

//

// Hello World client

// Connects REQ socket to tcp://localhost:5555

// Sends "Hello" to server, expects "World" back

//

#include

#include

#include

#include

int main (void)

{

void *context = zmq_ctx_new ();

 

// Socket to talk to server

printf ("Connecting to hello world server…\n");

void *requester = zmq_socket (context, ZMQ_REQ);

zmq_connect (requester, "tcp://localhost:5555");

 

//only send one rquest an one reply in each process

zmq_msg_t request;

zmq_msg_init_size (&request, 5);

memcpy (zmq_msg_data (&request), "Hello", 5);

printf ("Sending Hello %d…\n", request_nbr);

zmq_msg_send (&request, requester, 0);

zmq_msg_close (&request);

 

zmq_msg_t reply;

zmq_msg_init (&reply);

zmq_msg_recv (&reply, requester, 0);

printf ("Received World %d\n", request_nbr);

zmq_msg_close (&reply);

 

zmq_close (requester);

zmq_ctx_destroy (context);

return 0;

}

 

 

 

 

 

 

 

 

2.Publish-subscribe模式

我们可以想象一下天气预报的订阅模式,由一个节点提供信息源,由其他的节点,接受信息源的信息.

 

 

 

说明:pub-sub是一种异步模型;

publisher向所有的subscriber push所有消息;

subscriber可以订阅多种消息,可以收到任何匹配的消息,可以过滤消息,可以向多个publisher订阅消息。

如果一个publisher没有相关的subscriber,则它只会简单的丢弃消息。

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

 

 

 

 

 

 

 

 

 

 

 

 

// // Weather update server // Binds PUB socket to tcp://*:5556 // Publishes random weather updates // #include "zhelpers.h"

int main (void) { // Prepare our context and publisher void *context = zmq_ctx_new (); void *publisher = zmq_socket (context, ZMQ_PUB); zmq_bind (publisher, "tcp://*:5556"); zmq_bind (publisher, "ipc://weather.ipc");

// Initialize random number generator srandom ((unsigned) time (NULL)); while (true) { // Get values that will fool the boss int zipcode, temperature, relhumidity; zipcode = randof (100000); temperature = randof (215) - 80; relhumidity = randof (50) + 10;

// Send message to all subscribers char update [20]; sprintf (update, "d %d %d", zipcode, temperature, relhumidity); s_send (publisher, update); } zmq_close (publisher); zmq_ctx_destroy (context); return 0; }

// Weather update client // Connects SUB socket to tcp://localhost:5556 // Collects weather updates and finds avg temp in zipcode #include "zhelpers.h"

int main (int argc, char *argv []) { void *context = zmq_ctx_new ();

// Socket to talk to server printf ("Collecting updates from weather server…\n"); void *subscriber = zmq_socket (context, ZMQ_SUB); zmq_connect (subscriber, "tcp://localhost:5556");

// Subscribe to zipcode, default is NYC, 10001 char *filter = (argc > 1)? argv [1]: "10001 "; zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, filter, strlen (filter)); char *string = s_recv (subscriber);

int zipcode, temperature, relhumidity; sscanf (string, "%d %d %d",&zipcode, &temperature, &relhumidity);
printf ("the imformation for zipcode '%s' was %d %d %d \n", filter,zipcode,temperature,relhumidity);

zmq_close (subscriber); zmq_ctx_destroy (context); return 0; }

a) 客户端需要zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, filter, strlen (filter));设置一个过滤值,相当于设定一个订阅频道,否则什么信息也收不到。

b) 服务器端一直不断的广播中,如果中途有Subscriber端退出,并不影响他继续的广播,当Subscriber再连接上来的时候,收到的就是后来发送的新的信息了。这对比较晚加入的,或者是中途离开的订阅者,必然会丢失掉一部分信息.

c) 但是,如果Publisher中途离开,所有的Subscriber会hold住,等待Publisher再上线的时候,会继续接受信息。

3.Pipeline push-pull模式

想象一下这样的场景,如果需要统计各个机器的日志,我们需要将统计任务分发到各个节点机器上,最后收集统计结果,做一个汇总。PipeLine比较适合于这种场景.

 

 

 

说明:这个模型里,管道是单向的,从 PUSH 端单向的向 PULL 端单向的推送数据流;

Ventilator将任务分配给worker实现任务的并行处理;

Push-pull模式是单向的,很适合消费者能力不足的情况,可以提供多个消费者。一条消息如果被A消费,B将不会再消费这条消息。

 

可以看到,task ventilator使用的是SOCKET_PUSH,将任务分发到Worker节点上。而Worker节点上,使用SOCKET_PULL从上游接受任务,并使用SOCKET_PUSH将结果汇集到Slink。值得注意的是,任务的分发的时候也同样有一个负载均衡的路由功能,worker可以随时自由加入,task ventilator可以均衡将任务分发出去

posted @ 2012-12-26 19:42  追心  阅读(562)  评论(0编辑  收藏  举报