PHP并发多进程处理利器Gearman使用介绍


Posted in PHP onMay 16, 2016

工作中我们有时候会遇到比如需要同时发布数据到多个个服务器上,或者同时处理多个任务。可以使用PHP的curl_multi的方式并发处理请求,但是由于网络和数据以及各个服务器等等的一些情况导致这种并发处理的响应时间很慢,因为在并发请求的过程中还包括记录日志,处理数据等逻辑,等待处理结果并返回,所以也不能友好的满足后台操作的体验。

现在有另外一种方案,利Gearman来实现并发的需求。通过Client将请求发送到Gearman的Jobs,在每个Work中来再来进行curl_multi和数据处理和日志等一些操作,同时用supervisor 来监控Gearman以及Works的进程,这样可以实现一个并行的多进程和负载均衡的方案。

Gearman可以做什么:

异步处理:图片处理,订单处理,批量邮件/通知之类的
要求高CPU或内存的处理:大容量的数据处理,MapReduce运算,日志聚集,视频编码
分布式和并行的处理
定时处理:增量更新,数据复制
限制速率的FIFO处理
分布式的系统监控任务

Gearman工作原理:
使用Gearman的应用通常有三部分组成:一个Client、一个Worker、一个 任务服务器。 Client的作用是提出一个 Job 任务 交给 Job Server 任务服务器。Job Server 会去寻找一个 合适的 Worker 来完成这项任务。Worker 执行由 Client 发送过来的 Job,并且将结果通过 Job Server 返回给 Client。Gearman 提供了 Client 和 Worker 的 API,利用这些API 应用可以同 Gearman Job Server来进行通信。Gearman 内部 Client 和 Worker 之间的通信都是通过 TCP 连接来进行的。

PHP并发多进程处理利器Gearman使用介绍

Gearman可以将工作的负载分担到不同的机器中。

PHP并发多进程处理利器Gearman使用介绍

安装:

rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/x86_64/epel-release-6-5.noarch.rpm

yum install -y gearmand

启动:
gearmand -d

安装PHP Gearman扩展
我都是用pcel来安装的,你也可以下载源码包来编译安装,但是记得要先安装libgearman和re2c,不然扩展编译安装会出错。

pecl install gearman #不成功并提示版本问题可以试试 pecl install gearman-1.0.3,默认好像是1.1.2
编译安装也很简单

wget -c http://pecl.php.net/get/gearman-1.1.1.tgz

tar zxvf gearman-1.1.1.tgz

phpize

./configure

make && make install

echo "extension=gearman.so" >> /etc/php.ini

PHP接口函数
Gearman提供很多完善的扩展函数,包括GearmanClient,GearmanJob,GearmanTask,GearmanWorker,具体可以查看PHP官方手册.
这是官方提供的Example其中的一个,相当与一个并发的分发任务处理的例子

<?php

$client = new GearmanClient();
$client->addServer();

// initialize the results of our 3 "query results" here
$userInfo = $friends = $posts = null;

// This sets up what gearman will callback to as tasks are returned to us.
// The $context helps us know which function is being returned so we can
// handle it correctly.
$client->setCompleteCallback(function(GearmanTask $task, $context) use (&$userInfo, &$friends, &$posts) {
switch ($context)
{
case 'lookup_user':
$userInfo = $task->data();
break;
case 'baconate':
$friends = $task->data();
break;
case 'get_latest_posts_by':
$posts = $task->data();
break;
}
});

// Here we queue up multiple tasks to be execute in *as much* parallelism as gearmand can give us
$client->addTask('lookup_user', 'joe@joe.com', 'lookup_user');
$client->addTask('baconate', 'joe@joe.com', 'baconate');
$client->addTask('get_latest_posts_by', 'joe@joe.com', 'get_latest_posts_by');

echo "Fetching...\n";
$start = microtime(true);
$client->runTasks();
$totaltime = number_format(microtime(true) - $start, 2);

echo "Got user info in: $totaltime seconds:\n";
var_dump($userInfo, $friends, $posts);

gearman_work.php

<?php

$worker = new GearmanWorker();
$worker->addServer();

$worker->addFunction('lookup_user', function(GearmanJob $job) {
// normally you'd so some very safe type checking and query binding to a database here.
// ...and we're gonna fake that.
sleep(3);
return 'The user requested (' . $job->workload() . ') is 7 feet tall and awesome';
});

$worker->addFunction('baconate', function(GearmanJob $job) {
sleep(3);
return 'The user (' . $job->workload() . ') is 1 degree away from Kevin Bacon';
});

$worker->addFunction('get_latest_posts_by', function(GearmanJob $job) {
sleep(3);
return 'The user (' . $job->workload() . ') has no posts, sorry!';
});

while ($worker->work());

我在3个终端中都执行了gearman_work.php

ryan@ryan-lamp:~$ ps aux | grep gearman* | grep -v grep
gearman 1504 0.0 0.1 60536 1264 ? Ssl 11:06 0:00 /usr/sbin/gearmand --pid-file=/var/run/gearman/gearmand.pid --user=gearman --daemon --log-file=/var/log/gearman-job-server/gearman.log --listen=127.0.0.1
ryan 2992 0.0 0.8 43340 9036 pts/0 S+ 14:05 0:00 php /var/www/gearmand_work.php
ryan 3713 0.0 0.8 43340 9036 pts/1 S+ 14:05 0:00 php /var/www/gearmand_work.php
ryan 3715 0.0 0.8 43340 9036 pts/2 S+ 14:05 0:00 php /var/www/gearmand_work.php

来查看下执行gearman_work.php的结果shell

Fetching...

Got user info in: 3.03 seconds:

string(59) "The user requested (joe@joe.com) is 7 feet tall and awesome"

string(56) "The user (joe@joe.com) is 1 degree away from Kevin Bacon"

string(43) "The user (joe@joe.com) has no posts, sorry!"

看到上面的3.03 seconds,说明client请求过去的任务被并行分发执行了。
在实际的生产环境中,为了监测gearmand和work的进程没有被意外退出,我们可以借助Supervisor这个工具.

PHP 相关文章推荐
留言板翻页的实现详解
Oct 09 PHP
apache+php+mysql安装配置方法小结
Aug 01 PHP
PHP curl 并发最佳实践代码分享
Sep 05 PHP
phpadmin如何导入导出大数据文件及php.ini参数修改
Feb 18 PHP
主流PHP框架的优缺点对比分析
Dec 25 PHP
PHP嵌套输出缓冲代码实例
May 12 PHP
PHP的伪随机数与真随机数详解
May 27 PHP
php自动识别文字编码并转换为目标编码的方法
Aug 08 PHP
详解WordPress开发中的get_post与get_posts函数使用
Jan 04 PHP
Yii实现的多级联动下拉菜单
Jul 13 PHP
PHP的RSA加密解密方法以及开发接口使用
Feb 11 PHP
PHP实现数组转JSon和JSon转数组的方法示例
Jun 14 PHP
php截取视频指定帧为图片
May 16 #PHP
PHP中常用的数组操作方法笔记整理
May 16 #PHP
PHP获取用户访问IP地址的5种方法
May 16 #PHP
php pdo oracle中文乱码的快速解决方法
May 16 #PHP
Yii2中OAuth扩展及QQ互联登录实现方法
May 16 #PHP
Yii2 assets清除缓存的方法
May 16 #PHP
php使用curl通过代理获取数据的实现方法
May 16 #PHP
You might like
中国收音机工业发展史
2021/03/02 无线电
手把手教你使用DedeCms V3的在线采集图文教程
2007/04/03 PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
2013/07/15 PHP
php+redis在实际项目中HTTP 500: Internal Server Error故障排除
2017/02/05 PHP
Yii2设置默认控制器的两种方法
2017/05/19 PHP
强制设为首页代码
2006/06/19 Javascript
javascript跨域刷新实现代码
2011/01/01 Javascript
Javascript执行效率全面总结
2013/11/04 Javascript
JS实现的自定义右键菜单实例二则
2015/09/01 Javascript
Javascript编程中几种继承方式比较分析
2015/11/28 Javascript
JavaScript实现下拉菜单的显示和隐藏
2016/01/05 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
JavaScript实现页面无操作倒计时退出
2016/10/22 Javascript
AngularJS 中使用Swiper制作滚动图不能滑动的解决方法
2016/11/15 Javascript
Centos6.8下Node.js安装教程
2017/05/12 Javascript
easyui-datagrid开发实践(总结)
2017/08/02 Javascript
vue控制多行文字展开收起的实现示例
2019/10/11 Javascript
JS前端广告拦截实现原理解析
2020/02/17 Javascript
js实现轮播图特效
2020/05/28 Javascript
vue-router重写push方法,解决相同路径跳转报错问题
2020/08/07 Javascript
在vue中使用Base64转码的案例
2020/08/07 Javascript
python实现excel读写数据
2021/03/02 Python
Python数据预处理之数据规范化(归一化)示例
2019/01/08 Python
python Tcp协议发送和接收信息的例子
2019/07/22 Python
Python图像处理库PIL中图像格式转换的实现
2020/02/26 Python
达拉斯牛仔官方商店:Dallas Cowboys Pro Shop
2018/02/10 全球购物
美国电力供应商店/电气批发商:USESI
2018/10/12 全球购物
俄罗斯在线购买飞机票、火车票、巴士票网站:Tutu.ru
2020/03/16 全球购物
旅游与酒店管理的自我评价分享
2013/11/03 职场文书
转让协议书范本
2014/04/15 职场文书
新手上路标语
2014/06/20 职场文书
十月围城观后感
2015/06/08 职场文书
Python实现学生管理系统(面向对象版)
2021/06/24 Python
Redis读写分离搭建的完整步骤
2021/09/14 Redis
MySQL表类型 存储引擎 的选择
2021/11/11 MySQL
世界十大狙击步枪排行榜
2022/03/20 杂记