php+zeromq实践

zeromq为扩展库,不需要单独安装zeromq

1.配置

a.windows

首先查看php的版本是64位的还是32位的,顺便看看是线程安全的还是非线程安全的(一般windows下都是线程安全的),看的方法是在phpinfo查看(不知道怎么看phpinfo的需要百度一下基础知识了),如下图

phpinfo

 

红框里标注的就是了,比如我电脑上的php版本为32位的,是线程安全的

  1. 知道了版本以后就可以去网站上下载对应的php_zmq了,官网给的下载地址是打不开的,可以去这儿下载http://pecl.php.net/package/zmq,比如我的电脑就下载红框里的版本就可以了

     

  2. 下载好之后解压,将libzmq.dll,libsodium.dll两个文件拷到php的根目录下(注意是两个dell文件,一个也不能少)

 

然后将php_zmq.dll拷贝到刚才那个目录下的ext文件夹,这是php默认放扩展的地方,如果你改变了就需要放到你改变后的地方

 

然后在php.ini中添加extension=php_zmq.dll

 

然后其实并不需要重启电脑重启apache之类的,到这一步就可以用了

b.linux

安装ZeroMQ

1)下载ZeroMQ

执行命令:

wget http://download.zeromq.org/zeromq-4.0.4.tar.gz

2)解压ZeroMQ

$ tar zvxf zeromq-4.0.4.tar.gz
$ mv zeromq-4.0.4 zeromq
$ cd zeromq

3)编译安装

 

 

$ ./configure
......
checking for gcc... no
checking for cc... no
checking for cl.exe... no
configure: error: in `/home/chuser/zeromq':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details

 

提示缺少C编译器,先安装GCC。

$ sudo yum install gcc

安装OK!再次执行

$ ./configure
......
checking whether the C++ compiler works... no
configure: error: Unable to find a working C++ compiler

提示缺少C++编译器,先安装G++。

$ sudo yum install gcc-c++ 

安装OK!再次执行

$ ./configure
$ make
$ sudo make install

ZeroMQ安装成功!

安装php扩展

首先下载 
Git clone git://github.com/mkoppanen/PHP-zmq.git 
其次,进入php-zmq目录,还是执行三部曲 

1

2

3

4

phpize 

./configure --with-php-config=/usr/local/php/bin/php-config

make 

make install

搞定以后,会在php/extensions/no-debug-non-zts-20160303/目录下生产zmq.so文件

接下来需要做的是在php.ini配置文件中添加 

1

extension=zmq.so

备注: 查照PHP手册上面说的,version is 5.4.x,需要在php.d目录下,创建zmq.ini配置文件 

要看清楚自己的版本,我目前使用的是7.1.8,所以不需要这么做。

重启php-fpm

service php-fpm restart 
当然这个前提是,你得将php-fpm服务注册到系统中,若没有注册,就需要执行php-fpm进程干掉,然后重新启动。

遇到的问题

问题1

遇到zmq被重复加载,入下图: 

是在php.ini配置文件中,引入了zmq.so扩展,然后在php.d目录下,又添加了zmq配置,于是随便干掉一个就okey了。而手册上面说,仅仅是5.4.x版本需要这么搞。

问题2

在安装php-zmq的时候,执行./configure,报错:“checking libzmq installation... configure: error: Unable to find libzmq installation”,说找不到libzmq ,也就是找不到我上面安装的zeromq。

因为我安装在/usr/local/zmq4.2.1目录,他不可能会遍历文件去查找。所以我们可以通过./configure --help查看如何制定zeromq安装目录。

于是重新编译

1

./configure  --with-zmq=/usr/local/zeromq4.2.1 --with-php-config=/usr/local/php/bin/php-config

最后安装ok

2.php实践

1、Request-Reply (请求应答模式)

该模式的简介:server监听tcp的某个端口(下面案例中,绑定了8082端口),等待client 发起请求,并做相应的处理。如下图

server.php 文件

1

2

3

4

5

6

7

8

9

$ip        '127.0.0.1';

$context   new \ZMQContext(1);

$server    new \ZMQSocket($context, \ZMQ::SOCKET_REP);//第二个参数指定通信模型

$server->bind("tcp://" $ip ':8082');

while(true){

      $res  $server->recv();//监听用户的请求

      echo 'a request comes ,and the content is '.$res

      $server->send("Request-Reply 通信 by dq_test");

}

client.php文件

1

2

3

4

5

6

7

8

9

10

11

$ip       '127.0.0.1';

$context  new \ZMQContext(1);

$client   new \ZMQSocket($context, \ZMQ::SOCKET_REQ);

$client->connect("tcp://" $ip ':8082');

$msg      array('name' => 'dq''lang' =>'php');

echo "准备发送请求

";

$rs $client->send(json_encode($msg));//发送请求

echo "已经发送,等待反馈\n";

$res      $client->recv(); //获取请求返回值

echo "当前请求的返回值:".$res."\n";

首先,得启动sever.php脚本,如下图

启动前后,通过lsof查看8082端口占用情况。

现在开始测试client.php

注意

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

 

2、Publisher-Subscriber(发布订阅模式)

该模式的简介:有一个节点发布消息,其他所有节点可以接受消息,有点类似天气预报或是广播哦。如下图

消息发布者 publish.php代码如下

1

2

3

4

5

6

7

8

9

$ip        '127.0.0.1';

$context   new \ZMQContext(1);

$publish   new \ZMQSocket($context, \ZMQ::SOCKET_PUB);//第二个参数指定通信模型

$publish->bind("tcp://" $ip ':8083');

 

while(true) {

    $publish->send("dq Request-Reply 通信 by dq_test");

    sleep(1);

}

消息订阅者 subscribe.php代码如下

1

2

3

4

5

6

7

8

9

10

11

12

$ip        '127.0.0.1';

$context   new \ZMQContext(1);

$subscribe new \ZMQSocket($context, \ZMQ::SOCKET_SUB);//第二个参数指定通信模型

$subscribe->connect("tcp://" $ip ':8083');

//设置频道  ,发布者可能有多个频道

 

$filter 'dq'//接受消息的频道,必须设置,否则获取不到消息

$subscribe->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, $filter);

while(true) {

   $rs $subscribe->recv();

   echo $rs."\n";

}

执行上面程序

添加订阅者

1

/usr/local/php/bin/php subscribe.php &

启动发布程序

1

/usr/local/php/bin/php publish.php

执行效果如下图:

效率分析

其发布任务的效率还是不错的,发布10w个任务,每秒发布的个数分别如下:

个订阅者的个数每秒发布任务的个数
0167万
176.9万
276.9万
352.6万

具体如下图:

 

注意

    1、发布端(publish.php)需要一直处在运行状态,所有在上面程序中使用了while(true)死循环。若发布端(publish.php)中断,订阅者(subscribe.php)将会堵塞。

    2、如果中途有订阅者(subscribe.php)退出,并不影响他继续的广播,当订阅者(subscribe.php)再次连接上来的时候,仍然可以收到消息。 

3、Parallel Pipeline(并行管道模式)

该模式的简介:该模式给人的感觉就是总-分-总,一个地方进行分发任务到各个节点,等节点完成后,汇总到一个地方进行统计。懒得画图,借用一下官方的图,如下

任务的发布者 serverPusher.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

<?php

$context new ZMQContext();

 

//  Socket to send messages on

$sender new ZMQSocket($context, ZMQ::SOCKET_PUSH);

$sender->bind("tcp://*:8034");

 

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->send(0);

 

//  Send 100 tasks

$total_msec = 0;     //  Total expected cost in msecs

for ($task_nbr = 0; $task_nbr < 100000; $task_nbr++) {

    //  Random workload from 1 to 100msecs

    $sender->send($task_nbr);

 

}

 

printf ("Total expected cost: %d msec\n"$total_msec);

sleep (1);              //  Give 0MQ time to deliver

任务的接受者 worker.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

<?php

 

$context new ZMQContext();

$index = 0;

//  Socket to receive messages on

$receiver new ZMQSocket($context, ZMQ::SOCKET_PULL);

$receiver->connect("tcp://localhost:8034");

 

//  Socket to send messages to

$sender new ZMQSocket($context, ZMQ::SOCKET_PUSH);

$sender->connect("tcp://localhost:8035");

 

//  Process tasks forever

while (true) {

    $string $receiver->recv();

    $index +=1;

    //  Simple progress indicator for the viewer

    echo '任务id:'.$string;

    echo ';已经处理了'.$index.'个任务', PHP_EOL;

    //  Do the work

    usleep($string * 1000);

 

   //  Send results to sink

    $sender->send("good");

}

任务的汇总者 serverSummary.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

<?php

$context new ZMQContext();

$receiver new ZMQSocket($context, ZMQ::SOCKET_PULL);

$receiver->bind("tcp://*:8035");

 

//  Wait for start of batch

$string $receiver->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 < 100; $task_nbr++) {

    $string $receiver->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;

这种模式声称是负载均衡,其实是平均分配而已。如下,101个任务,分发给3个woker

可以看出任务id对3进行求余,余1分配给第一个人woker,余0分配给第二个woker,余2分配给第三个woker。如果仅仅是这样也就算了,啃爹的还不仅仅是这些,比如我们现在要分发1000个任务,如下图1、2、3在任务分发前启动,4在任务分发后启动,中途中断3后,隔几秒再启动,然后中断2,最后中断1。

由上图,可以看出,当4启动以后,并不会被分发任务,也就是说当woker没有在任务分发前启动,是不会被分发任务的。其次,3中断后,原本该分发给3的任务,并不会分配给1和2,从而导致部分任务丢失。也就是说,在任务分发的时候,若有woker中断,会导致任务丢失。当有两个woker的时候,这种丢失看得更明显如下图:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值