ZeroMQ的学习和研究

深入解析Docker Overlay2磁盘空间占用问题及高效清理策略 本文深入解析了Docker Overlay2存储驱动导致磁盘空间占用的核心原因,包括镜像与容器残留、日志文件膨胀、应用层泄漏及驱动特性。提供了从全局检查到精准定位的完整排查方法,并给出了从常规清理到配置优化的多维度高效清理策略,帮助用户从根本上解决Docker磁盘空间问题。 阅读详情

ZeroMQ,史上最快的消息队列

—– ZMQ的学习和研究

一、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程序如下:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
/*
* Hello World server
* Binds REP socket to tcp://*:5555
* Expects "Hello" from client, replies with "World"
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket( $context , ZMQ::SOCKET_REP);
$responder -&gt;bind( "tcp://*:5555" );
while (true) {
// Wait for next request from client
$request = $responder -&gt;recv();
printf ( "Received request: [%s]\n" , $request );
 
// Do some 'work'
sleep (1);
 
// Send reply back to client
$responder -&gt;send( "World" );
}



Client程序如下:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
 
/*
 
  *  Hello World client
 
  *  Connects REQ socket to tcp://localhost:5555
 
  *  Sends "Hello" to server, expects "World" back
 
  * @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
 
  */
$context = new ZMQContext();
 
//  Socket to talk to server
 
echo "Connecting to hello world server...\n" ;
 
$requester = new ZMQSocket( $context , ZMQ::SOCKET_REQ);
 
$requester -&gt;connect( "tcp://localhost:5555" );
 
for ( $request_nbr = 0; $request_nbr != 10; $request_nbr ++) {
 
     printf ( "Sending request %d...\n" , $request_nbr );
 
     $requester -&gt;send( "Hello" );
 
     $reply = $requester -&gt;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协议,但是,这绝不是他所擅长的。

ZMQ的Publish-subscribe模式

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

图2:ZMQ的Publish-subscribe

示例代码如下 :

Publisher:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
/*
* Weather update server
* Binds PUB socket to tcp://*:5556
* Publishes random weather updates
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
// Prepare our context and publisher
$context = new ZMQContext();
$publisher = $context -&gt;getSocket(ZMQ::SOCKET_PUB);
$publisher -&gt;bind( "tcp://*:5556" );
 
while (true) {
// Get values that will fool the boss
$zipcode = mt_rand(0, 100000);
$temperature = mt_rand(-80, 135);
$relhumidity = mt_rand(10, 60);
 
// Send message to all subscribers
$update = sprintf ( "%05d %d %d" , $zipcode , $temperature</code><code class="php plain">, </code><code class="php variable">$relhumidity );
$publisher</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$update );
}</pre>
Subscriber
<pre>&lt;?php
/*
* Weather update client
* Connects SUB socket to tcp: //localhost:5556
* Collects weather updates and finds avg temp in zipcode
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
$context = new ZMQContext();
 
// Socket to talk to server
echo "Collecting updates from weather server…" , PHP_EOL;
$subscriber = new ZMQSocket( $context , ZMQ::SOCKET_SUB);
$subscriber -&gt;connect( "tcp://localhost:5556" );
 
// Subscribe to zipcode, default is NYC, 10001
$filter = $_SERVER [ 'argc' ] &gt; 1 ? $_SERVER [ 'argv' ][1] : "10001" ;
$subscriber -&gt;setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, $filter );
 
// Process 100 updates
$total_temp = 0;
for ( $update_nbr = 0; $update_nbr &lt; 100; $update_nbr ++) {
$string = $subscriber -&gt;recv();
sscanf ( $string , "%d %d %d" , $zipcode</code><code class="php plain">, </code><code class="php variable">$temperature , $relhumidity );
$total_temp += $temperature ;
}
printf ( "Average temperature for zipcode '%s' was %dF\n" ,
$filter</code><code class="php plain">, (int) (</code><code class="php variable">$total_temp / $update_nbr ));



这段代码讲的是,服务器端生成随机数zipcode、temperature、relhumidity分别代表城市代码、温度值和湿度值。然后不断的广播信息,而客户端通过设置过滤参数,接受特定城市代码的信息,收集完了以后,做一个平均值。

a) 与Hello World不同的是,Socket的类型变成SOCKET_PUB和SOCKET_SUB类型。

b) 客户端需要subscriber-&gt;setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE,filter);设置一个过滤值,相当于设定一个订阅频道,否则什么信息也收不到。

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

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

ZMQ的PipeLine模型

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

图3:ZMQ的PipeLine模型

Parallel task ventilator in PHP




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
/*
* Task ventilator
* Binds PUSH socket to tcp://localhost:5557
* Sends batch of tasks to workers via that socket
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
$context = new ZMQContext();
 
// Socket to send messages on
$sender = new ZMQSocket( $context , ZMQ::SOCKET_PUSH);
$sender -&gt;bind( "tcp://*:5557" );
 
echo "Press Enter when the workers are ready: " ;
$fp = fopen ( 'php://stdin' , 'r' );
$line = fgets ( $fp , 512);
fclose( $fp );
echo "Sending tasks to workers…" , PHP_EOL;
 
// The first message is "0" and signals start of batch
$sender -&gt;send(0);
 
// Send 100 tasks
$total_msec = 0; // Total expected cost in msecs
for ( $task_nbr = 0; $task_nbr &lt; 100; $task_nbr ++) {
// Random workload from 1 to 100msecs
$workload = mt_rand(1, 100);
$total_msec += $workload ;
$sender</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$workload );
 
}
printf ( "Total expected cost: %d msec\n" , $total_msec );
sleep (1); // Give 0MQ time to deliver



Parallel task worker in PHP




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
/*
* Task worker
* Connects PULL socket to tcp://localhost:5557
* Collects workloads from ventilator via that socket
* Connects PUSH socket to tcp://localhost:5558
* Sends results to sink via that socket
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
$context = new ZMQContext();
 
// Socket to receive messages on
$receiver = new ZMQSocket( $context , ZMQ::SOCKET_PULL);
$receiver -&gt;connect( "tcp://localhost:5557" );
 
// Socket to send messages to
$sender = new ZMQSocket( $context , ZMQ::SOCKET_PUSH);
$sender -&gt;connect( "tcp://localhost:5558" );
 
// Process tasks forever
while (true) {
$string = $receiver -&gt;recv();
 
// Simple progress indicator for the viewer
echo $string , PHP_EOL;
 
// Do the work
usleep( $string * 1000);
 
// Send results to sink
$sender -&gt;send( "" );
}



Parallel task sink in PHP




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
/*
* Task sink
* Binds PULL socket to tcp://localhost:5558
* Collects results from workers via that socket
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
// Prepare our context and socket
$context = new ZMQContext();
$receiver = new ZMQSocket( $context , ZMQ::SOCKET_PULL);
$receiver -&gt;bind( "tcp://*:5558" );
 
// Wait for start of batch
$string = $receiver -&gt;recv();
 
// Start our clock now
$tstart = microtime(true);
 
// Process 100 confirmations
$total_msec = 0; // Total calculated cost in msecs
for ( $task_nbr = 0; $task_nbr &lt; 100; $task_nbr ++) {
$string = $receiver -&gt;recv();
if ( $task_nbr % 10 == 0) {
echo ":" ;
} else {
echo "." ;
}
}
 
$tend = microtime(true);
 
$total_msec = ( $tend - $tstart ) * 1000;
echo PHP_EOL;
printf ( "Total elapsed time: %d msec" , $total_msec );
echo PHP_EOL;



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

五、其他扩展模式

通常,一个节点,即可以作为Server,同时也能作为Client,通过PipeLine模型中的Worker,他向上连接着任务分发,向下连接着结果搜集的Sink机器。因此,我们可以借助这种特性,丰富的扩展原有的三种模式。例如,一个代理Publisher,作为一个内网的 Subscriber接受信息,同时将信息,转发到外网,其结构图如图4所示。

图4:ZMQ的扩展模式

六、多个服务器

ZMQ和Socket的区别在于,前者支持N:M的连接,而后者则只是1:1的连接,那么一个Client连接多个Server的情况是怎样的呢,我们通过图5来说明。

图5:ZMQ的N:1的连接情况

我们假设Client有R1,R2,R3,R4四个任务,我们只需要一个ZMQ的Socket,就可以连接四个服务,他能够自动均衡的分配任务。如图5所示,R1,R4自动分配到了节点A,R2到了B,R3到了C。如果我们是N:M的情况呢?这个扩展起来,也不难,如图6所示。

图6:N:M的连接

我们通过一个中间结点(Broker)来进行负载均衡的功能。我们通过代码了解,其中的Client和我们的Hello World的Client端是一样的,而Server端的不同是,他不需要监听端口,而是需要连接Broker的端口,接受需要处理的信息。所以,我们重点阅读Broker的代码:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
/*
* Simple request-reply broker
* @author Ian Barber &lt;ian(dot)barber(at)gmail(dot)com&gt;
*/
 
// Prepare our context and sockets
$context = new ZMQContext();
$frontend = new ZMQSocket( $context , ZMQ::SOCKET_ROUTER);
$backend = new ZMQSocket( $context , ZMQ::SOCKET_DEALER);
$frontend -&gt;bind( "tcp://*:5559" );
$backend -&gt;bind( "tcp://*:5560" );
 
// Initialize poll set
$poll = new ZMQPoll();
$poll</code><code class="php plain">-&amp;gt;add(</code><code class="php variable">$frontend , ZMQ::POLL_IN);
$poll</code><code class="php plain">-&amp;gt;add(</code><code class="php variable">$backend , ZMQ::POLL_IN);
$readable = $writeable = array ();
 
// Switch messages between sockets
while (true) {
$events = $poll</code><code class="php plain">-&amp;gt;poll(</code><code class="php variable">$readable , $writeable );
 
foreach ( $readable as $socket ) {
if ( $socket === $frontend ) {
// Process all parts of the message
while (true) {
$message = $socket -&gt;recv();
// Multipart detection
$more = $socket -&gt;getSockOpt(ZMQ::SOCKOPT_RCVMORE);
$backend</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$message , $more ? ZMQ::MODE_SNDMORE : null);
if (! $more ) {
break ; // Last message part
}
}
}
else if ( $socket === $backend ) {
$message = $socket -&gt;recv();
// Multipart detection
$more = $socket -&gt;getSockOpt(ZMQ::SOCKOPT_RCVMORE);
$frontend</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$message , $more ? ZMQ::MODE_SNDMORE : null);
if (! $more ) {
break ; // Last message part
}
}
}
}



Broker监听了两个端口,接受从多个Client端发送过来的数据,并将数据,转发给Server。在Broker中,我们监听了两个端口,使用了两个Socket,那么对于多个Socket的情况,我们是不需要通过轮询的方式去处理数据的,在之前,我们可以使用libevent实现,异步的信息处理和传输。而现在,我们只需要使用ZMQ的$poll->poll以实现多个Socket的异步处理。

七、进程间的通信

ZMQ不仅能通过TCP完成节点间的通信,也可以通过Socket文件完成进程间的通信。如图7所示,我们fork三个PHP进程,将进程1的数据,通过Socket文件发送到进程3。

图7:进程间的通信




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php
 
function step1() {
 
         $context = new ZMQContext();
 
         // Signal downstream to step 2
 
         $sender = new ZMQSocket( $context , ZMQ::SOCKET_PAIR);
 
         $sender -&gt;connect( "ipc://step2.ipc" );
 
         $sender -&gt;send( "hello ,i am step1" );
 
}
 
function step2() {
 
         $pid = pcntl_fork();
 
         if ( $pid == 0) {
 
                 step1();
 
                 exit ();
 
         }
 
         $context = new ZMQContext();
 
         //  Bind to ipc: endpoint, then start upstream thread
 
         $receiver = new ZMQSocket( $context , ZMQ::SOCKET_PAIR);
 
         $receiver -&gt;bind( "ipc://step2.ipc" );
 
         // Wait for signal  
 
         sleep(10);
 
         $strings = $receiver -&gt;recv();
 
         echo "step2 receiver is $strings" . PHP_EOL;
 
         sleep(10);
 
         // Signal downstream to step 3
 
         $sender = new ZMQSocket( $context , ZMQ::SOCKET_PAIR);
 
         $sender -&gt;connect( "ipc://step3.ipc" );
 
         $sender</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$strings );
 
}
 
// Start upstream thread then bind to icp: endpoint
 
$pid = pcntl_fork();
 
if ( $pid == 0) {
 
         step2();
 
         exit ();
 
}
 
$context = new ZMQContext();
 
$receiver = new ZMQSocket( $context , ZMQ::SOCKET_PAIR);
 
$receiver -&gt;bind( "ipc://step3.ipc" );
 
// Wait for signal
 
$sr = $receiver -&gt;recv();
 
echo "the result is {$sr}" .PHP_EOL;



在运行中,我们可以看到多了两个文件,如图8所示。

图8:运行过程中生成的文件

八、利用ZeroMQ实现一个配置推送中心

当我们将WEB代码部署到集群上的时候,如果需要实时的将最新的配置信息,主动的推送到各个机器节点。在此过程中,我们一定要保证,各个节点收到的信息的一致性和正确性,如果使用HTTP,由于他的无状态性,我们无法保证信息的一致性,当然,你可以使用HTTP来实现,只是更复杂,为什么不用 ZMQ?他能让你更简单的实现这些功能。

我们使用ZMQ的信息订阅模式。在那个模式中,我们注意到,对于后来的加入节点,始终会丢失在他加入之前,已经发送的信息(Slow joiner)。我们可以开启另外一个ZMQ的通信通道,用于报告当前节点的情况(节点的身份、准备状态等),其结构如图9所示。

图9:扩展ZMQ的订阅者模式

我们通过$context->getSocket(ZMQ::SOCKET_REQ);设置一个新的Request-Reply连接,来用于 Subscriber向Publisher报告自己的身份信息,而Publisher则等待所有的Subscriber都连接上的时候,再选择 Publish自己的信息。

Subscriber端的程序如下:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
 
$hostname = $_SERVER [ 'argc' ] &gt; 1 ? $_SERVER [ 'argv' ][1] : "s1" ;
 
$context = new ZMQContext(2);
 
$sub = new ZMQSocket( $context ,ZMQ::SOCKET_SUB);
 
$sub -&gt;connect( "tcp://localhost:5561" );
 
//$subscriber-&amp;gt;setSockOpt(ZMQ::SOCKOPT_IDENTITY, $hostname);
 
$sub -&gt;setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "" );
 
$client = $context -&gt;getSocket(ZMQ::SOCKET_REQ);
 
$client -&gt;connect( "tcp://localhost:5562" );
 
while (1) {
 
//$client-&gt;connect("tcp://localhost:5562");
 
$client</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$hostname );
 
$version = $client -&gt;recv();
 
echo $version . "\r\n" ;
 
if (! empty ( $version )) {
 
$recive = $sub -&gt;recv();
 
$vars = json_decode( $recive );
 
var_dump( $vars );
 
}
 
}



Publisher端的程序如下:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
 
$CONFIG [ "TAOKE_BTS" ][ "ENABLE" ] = true;
 
$CONFIG [ "QP_BTS" ][ "ENABLE" ] = true;
 
$CONFIG [ "QP_BTS" ][ "TK_TEST" ] = 13;
 
$string = json_encode( $CONFIG );
 
$clients = array ( "s2" , "s1" , "s3" );
 
$context = new ZMQContext(10);
 
//Socket talk to clients
 
$publisher = new ZMQSocket( $context ,ZMQ::SOCKET_PUB);
 
$publisher -&gt;bind( "tcp://*:5561" );
 
//Socket to publish message
 
$server = new ZMQSocket( $context ,ZMQ::SOCKET_REP);
 
$server -&gt;bind( "tcp://*:5562" );
 
while ( count ( $clients )!=0) {
 
       $client_name = $server -&gt;recv();
 
         echo "{$client_name} is connect!\r\n" ;
 
if (in_array( $client_name , $clients )) { //coming one client
 
         $key = array_search ( $client_name , $clients );
 
         unset( $clients</code><code class="php plain">[</code><code class="php variable">$key ]);
 
         echo "$client_name has come in!\r\n" ;
 
         $server -&gt;send( "Version is 2.0" );
 
} else {
 
         $server -&gt;send( "You are a stranger!" );
 
}
 
}
 
$publisher</code><code class="php plain">-&amp;gt;send(</code><code class="php variable">$string );
 
?&gt;



每个节点通过5562端口,使用Rep模式和Publisher连接,通过这个连接告之Publisher自己的机器名,而Publisher端通过白名单的方式,维护一个机器列表,当机器列表中所有的机器连接上来以后,通过5561端口,将最新的配置信息发送出去。

后续的处理,Subscriber可以选择将配置信息写入到APC缓存,程序将始终从缓存中读取部分配置信息,Subscriber并将更新后的状态信息,实时的通过5562报告给Publisher。

虽然,在本示例中不会出现,但是,如果需要发布的信息量过大,在接受信息的过程中,Subscriber端突然中断网络(或者是程序崩溃),那么当他在连接上来的时候,有部分信息就会丢失?ZMQ考虑到这个问题,通过subscriber-&gt;setSockOpt(ZMQ::SOCKOPT_IDENTITY,hostname);设置一个id,当这个id的Subscriber重新连接上来的时候,他可以从上次中断的地方,继续接受信息,当然,节点的中断,不会影响其他的节点继续的接受信息。

那么ZMQ是怎么实现断线重连后,继续发送信息呢 ?他会将断开的Subscriber应该接受到的信息发到内存中,等待他重新上线后,将缓存的信息,继续发送给他。当然,内存必然是有限的,过多就会出现内存溢出。ZMQ通过

SetSockOpt(ZMQ::SOCKOPT_SWAP, 250000)设置Swap空间的大小,来防止out of memory and crash。最终,我们的程序运行结果,如图10所示。

图10:配置中心的运行结果

当然,这只是一个大体的思路,如果应用到实际的成产环境中,还需要考虑更多的问题,包含稳定性,容错等等。然而,ZMQ由于高并发,以及稳定性和易用性,前景不错,他的目标是进入Linux内核,我们期待那一天的到来。

参考资料 :

http://www.infoq.com/cn/news/2010/09/introduction-zero-mq Infoq对zeromq的简介

http://zguide.zeromq.org/page:all ZeroMQ的guide文档

蛋白组学/磷酸化蛋白组学分析笔记-2 如何校正蛋白丰度?磷酸化组学质谱下机处理。 阅读详情

相关推荐

PCL1.12.1+VTK9.1+Qt5.14.2实战:解决QVTKOpenGLNativeWidget点云渲染窗口初始化报错问题

本文针对PCL1.12.1、VTK9.1与Qt5.14.2集成开发中,QVTKOpenGLNativeWidget点云渲染窗口初始化时出现的报错与黑屏问题,提供了深度分析与两种实战解决方案。核心在于理解VTK版本升级导致的渲染窗口类型不匹配,并指导开发者通过显式创建vtkGenericOpenGLRenderWindow或利用窗口ID嵌入,正确初始化并绑定可视化组件,从而稳定实现点云渲染。

weixin_29284657的博客 222

【Java】消息队列——ZeroMQ(ZMQ、0MQ)概述和使用演示

ZeroMQ是一个开源的通信库,它通过sockets API来提供一个简单的消息传递模式。ZeroMQ内部实现了一种高效的网络消息传递机制,可以在多线程或多进程的环境中高效地进行消息传递,同时具有低延迟和高吞吐量的特点。高性能:ZeroMQ可以通过更少的数据传输实现更多的并发请求和响应,减少了网络负载,并提高了网络传输的效率。简单易用:ZeroMQ的API接口非常简单,易于使用和部署。跨平台:ZeroMQ可用于Windows、Linux、Mac OS X等多种操作系统和编程环境。

欢迎。 7368

手把手教你用ZLMediaKit搭建WebRTC直播:本地推流与播放实战

本文详细介绍了如何使用ZLMediaKit搭建WebRTC直播系统,涵盖从环境准备、编译部署、SSL证书配置到本地推流与播放的完整实战流程。通过一步步的指导,帮助开发者快速掌握基于ZLMediaKit的WebRTC推拉流技术,构建低延迟的实时音视频应用。

weixin_28842367的博客 348

ZeroMQ从入门到掌握

一、ZeroMQ简述 ZeroMQ是一种基于消息队列的多线程网络库,其对套接字类型、连接处理、帧、甚至路由的底层细节进行抽象,提供跨越多种传输协议的套接字。常用的通讯模式有三类: 请求回应模型 由请求端发起请求,并等待回应端回应请求。从请求端来看一定是一对对收发配对的;反之,在回应端一定是发收对。请求端和回应端都可以是 1:N 的模型。通常把 1 认为是 server ,N 认为是 Client 。ZeroMQ 可以很好的支持路由功能(实现路由功能的组件叫作 Device),把 1:N 扩展为 N:

Jiangtagong的博客 3653

【汽车故障诊断2】从标准到实战:解码DTC格式背后的诊断逻辑

本文深入解析汽车诊断故障码(DTC)的格式与逻辑,对比了OBD-II标准(如ISO 15031-6)的5字符格式与UDS协议(ISO 14229-1)下更丰富的3字节格式。文章从国际标准出发,结合实战案例,阐述了DTC如何作为汽车电子系统的“体检报告”,帮助工程师和维修技师精准定位故障,并详细解读了UDS 19服务如何读取和管理DTC状态。

berry的博客 713

零基础使用Manim画傅里叶变换

0x01 准备工作 确保你的电脑中安装的有:Python(3.6以上版本,推荐3.8)、FFmpeg(在PATH环境变量中)、LaTex发行版,如果这些都有了,就可以跳过这步。 下面是安装指南: Python:Win10用户直接在微软商店搜索Python3.8安装,也可以自行百度安装方法,在开始菜单右键打开PowerShell,或者Win+R输入PowerShell打开,输入Pyhton --version,显示3.8以上。 FFmpeg:可以直接百度下载,或者用我打包好的(下载链接)。下载好后,将ff

TagBug的博客 3191

ZeroMQ教程入门学习攻略

本人在zeromq使用过程中主要参考了如下博客。 1,概要和快速入门 https://www.cnblogs.com/chenny7/p/6245236.html 2,使用举例 https://blog.youkuaiyun.com/brimsullowr/article/details/82770444 3,架构分析 https://www.cnblogs.com/rainbowzc/p/335...

jigetage的专栏 6690

程序化广告行业(2/89):从程序化广告深挖数据处理技巧

大家好!我一直希望能和大家在技术学习的道路上携手共进,这也是我写这一系列博客的初衷。上次我们一起学习了Python基础的数据处理知识,这次咱们借助一本程序化广告手册,深入挖掘数据处理的更多技巧。这本手册涵盖了程序化广告从概念到技术实现的诸多方面,而其中处处都涉及到数据处理,相信会给我们带来不少收获

yyy173611的博客 4572

基于zmq_poll实现双向非阻塞通信(双向异步聊天)

最近在使用ZMQ来做进程间通信,想起之前有看到,好奇能否基于ZMQ实现相同的功能,于是就查了一下相关的资料,写了一个简单的demo验证了一下。期间还因为zmq_poll不能直接监控标准输入,因此还查找了一下C++实现非阻塞输入的方法,相关代码直接引用了大佬的实现《好记性不如烂笔头,浅记一下。废话不多说,直接贴代码。

qq_42724789的博客 661

基于Simulink进行多相电机EMI抑制的仿真建模

特点高可靠性:通过增加相数来提供冗余,增强系统的故障容忍度。低转矩脉动:改善了电机的动态性能,减少了转矩波动。复杂的EMI管理:更多的相数意味着更复杂的电磁环境,增加了EMI抑制的难度。挑战模型复杂性:涉及电气、机械和电磁场等多个领域的相互作用。实时性要求:控制系统需要能够快速响应以适应动态负载变化。多变量优化:包括滤波器设计、PWM调制策略等在内的多个参数需综合考虑以找到最优解。使用Simscape Electrical库来构建一个多相电机模型。

amy_mhd的博客 273

3 路由引入

在大型企业网络中,网络规模十分庞大,选用单一的路由协议无法满足网络的需求,因此多种路由协议共存的情况十分常见。或者出于业务逻辑或行政管理的考虑,会在不同的网络结构中设计和部署不同的路由协议,使路由的层次结构更加清晰可控。路由引入是具有方向性的,将路由信息从路由协议A引入到路由协议B(A-to-B),则路由协议B可获知A中的路由信息,但是此时,A还并不知晓B路由协议中的路由信息,除非配置B-to-A的路由引入。表3-1:各种路由协议的优先级。通过路由引入,可以实现路由信息在不同路由协议间传递。

lwljh134的博客 621

ZeroMQ的研究与学习

ZeroMQ的研究与学习 简介工作模式层级模型实现原理核心特点与其他MQ的简单比较 ZeroMQ的一百字概括 ZeroMQ看起来想一个可嵌入的网络库,但其作用就像是一个并发框架。它为你提供了各种传输工具,如进程内,进程间,TCP和组播中进行原子消息传递的套接字。你可以使用各种模式实现N对N的套接字连接,这些模式包括发布订阅,请求应答,扇出模式,管道模式。它

马万明的专栏 2531

最强游戏投屏串流搭档Sunshine+Moonlight配置方法

因祸得福的是,sunshine作为开源的self-host的服务端,不仅可以代替Novidia的服务端角色,还拓展了moonlight可以服务的主机,非novidia显卡的PC也可以通过这对搭档实现高质量的游戏窜流投屏了。回到moonlight,点击电脑图表,会给你一个Pincode,到Sunshine控制台,菜单点击Pin,输入moonlight给出的pin码。高质量的图像: Moonlight支持高清(HD)和甚至4K分辨率的投屏,同时还提供了对音频的传输支持,确保用户可以享受到高质量的视频和音频。

每日出拳老爷子的博客 1万+

[zz]ZeroMQ的学习和研究

转载自http://www.searchtb.com/2012/08/zeromq-primer.html 写的比较好,深入骨髓了: 一、ZeroMQ的背景介绍 引用官方的说法: “ZMQ(以下ZeroMQ简称ZMQ)是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸...

weixin_34106122的博客 210

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

ZeroMQ研究与应用分析及学习资料

1、ZeroMQ概述: ZeroMQ是一种基于消息队列的多线程网络库,其对套接字类型、连接处理、帧、甚至路由的底层细节进行抽象,提供跨越多种传输协议的套接字。ZeroMQ是网络通信中新的一层,介于应用层和传输层之间(按照TCP/IP划分),其是一个可伸缩层,可并行运行,分散在分布式系统间。 2、其详细可参考: http://www.cnblogs.com/rainbowzc/p/335759...

weixin_30773135的博客 151

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

ZeroMQ,史上最快的消息队列 —– ZMQ的学习和研究

一、ZeroMQ 的背景介绍   引用官方的说法: “ZMQ (以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ 的明确目标是“成为标准网络协议栈的一部分,之后进入 Linux 内核”。现在还未看到它们的成功。但是,

人生代码,代码人生。。。 1371

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: Netty代码分析
下一篇: ZeroMQ研究与应用分析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值