1、什么是gearman
Gearman是一套可以一个work传递其他机器,或者调用其他机器功能的应用程序框架。它允许并行工作,负载平衡处理,并调度不同语言之间的职能。它可用于各种应用,从高可用性的网站数据库复制事件的运输。简单来说,Gearman是一个分布式的任务调度框架,它包括 a client,a worker ,a job server这三部分组成。
Gearman的执行过程:客户端通过客户端API(PHP,C,Perl等)创建一个任务发送到job server上,Job Server 通过客户端的function name 查找合适的worker,并分到该worker上,worker接收到任务后根据worker的规则执行,并返回数据到job Server,而Job Server则把数据返回给客户端,这样Gearman的执行过程就结束了。
用户可以根据不同的需求制定不同的worker来处理不同的任务,将这些worker存放到不同的服务器上,Job Server会根据不同的客户端发送来的任务的function name寻找worker来执行,从而达到为业务服务器减轻压力;
2、Gearman的应用场景:
服务器的访问压力比较大时,我们可以通过负载均衡来将负载分散到多台服务器上. 但有些比较耗时的请求.比如:
(1) 需要连接邮件服务器,发送一封超长的HTML邮件。
(2) 需要对用户上传的图片进行裁剪,生成多份缩略图。
(3) 需要将用户上传的文件分发到多台服务器上。
等等
在我们的日常应用中经常遇到,用户需要等待一段时间,这个请求才能完成,比如在用户上传照片时,照片上传成功后,然后是裁剪,最后生成缩略图,在这么一 个过程中,用户只能等待,所以对用户的体验来讲是相当不好的。可能在用户第一次使用过后,下次就很难再让他使用这个图片的上传功能了。
那么有没有一种方法将这些处理过程放在后台慢慢运行呢?答案是肯定的,通过分布式处理可以将这些比较耗时的任务放在后台,甚至分散到多台服务器上去 处理,对于这个问题异步处理就派上了用场。
现在有很多开源的软件能实现异步通信,比如ActiveMQ、Hadoop、Gearman和MecacheMQ等,它们巧妙的将计算转移到其他服务器上,而这一切都是隐藏在API中,同时,这些机制都是跨语言的,可以用PHP来分配一个任务,然后将后台的C/C++程序来进行处理,这一切都不是什么问题。
3、安装gearman:(1) 安装gcc
$ yum install gcc44 gcc44-c++ libstdc++44-devel -y
增加环境变量: export CC=/usr/bin/gcc44 or export CC=/usr/bin/gcc export CXX=/usr/bin/g++44 $ source /etc/profile 刷新
(2) 安装 boost
$ cd /usr/local $ mkdir boost $ tar xvzf boost_1_52_0.tar.gz $ cd boost_1_52_0 $ ./bootstrap.sh –prefix=/usr/local/boost 运行后会生成一个b2的可执行文件 $./b2 install 安装完成后需要修改一下环境变量 $ vim /etc/profile 添加:export CPPFLAGS=-I/usr/local/boost/include export LDFLAGS=-L/usr/local/boost/lib
$ source /etc/profile 刷新
boost安装成功
(3) 安装 gearmand
在/usr/local目录下创建gearmand目录
$ tar xvzf gearmand-1.1.4.tar.gz $ cd gearmand-1.1.4 $ CC=gcc44 CXX=g++44 ./configure --disable-libmemcached --disable-libsqlite3 --with-boost=/usr/local/boost --prefix=/usr/local/gearmand/ $ make $ make install $ vim /etc/ld.so.conf 增加 /usr/local/boost/lib $/sbin/ldconfig –v 更新配置(解决各种诡异的无法找到so包问题) $ /usr/local/gearmand/sbin/gearmand -p 4730 -u root --log-file=/tmp/gearmand-4730.log -d
(4) 安装php扩展
$ tar xvzf gearman-1.1.1.tgz $ cd gearman-1.1.1 $ /data1/adbox/local/php/bin/phpize $ ./configure --with-php-config=/data1/adbox/local/php/bin/php-config --with-gearman=/usr/local/gearmand $ make $ make install cd /data1/adbox/local/php/lib/php/extensions/no-debug-non-zts-20090626/ 如果目录里面有gearman扩展 vim /data1/adbox/local/php/lib/php.ini 增加 extension = gearman.so; 然后重启php $kill -USR2 php 2742 (php-fpm的主进程号) 安装好后可以通过一个小程序测试下是否安装成功,保存为verify_gearman.php: <?php print gearman_version() . "\n"; ?> 如果返回1.1.4 ,证明安装成功。
4、gearman功能测试
(1) 开启gearmand 守护进程
$ gearmand -L 127.0.0.1 -p 4730 -u root –d
(2) php 实例
给出了用 PHP 编写的一个 Gearman worker。将这些代码保存在一个名为 worker.php 的文件中。
<?php $worker= new GearmanWorker(); $worker->addServer(); $worker->addFunction("gangfeng", "gangfeng_feed_function"); while ($worker->work()); function gangfeng_feed_function($job) { $enter_string = ($job->workload()); $welcome = "welcome to the feed queue , I am worker\n"; return $welcome.$enter_string; } ?>
给出了用 PHP 编写的一个 Gearman client。将这些代码保存在一个名为 client.php 的文件中。
<?php $client= new GearmanClient(); $client->addServer(); echo "start\n"; echo $client->do("gangfeng", json_encode("abcd")); echo "end\n"; ?>
现在,可以用如下的命令行连接客户机与 worker 了:
/data1/adbox/local/php/bin/php worker.php & /data1/adbox/local/php/bin/php client.php 如果返回 start welcome to the feed queue , I am worker "abcd"end 证明运行成功。 解释: json_encode(“abcd”) 这个参数值必须是字符串 不能是数组, 可以进行序列化或json 传送
5、gearman 扩展
(1) 如果有多个worker会怎么样呢,我们继续操作上面的例子:
$ cp worker.php worker1.php (修改里面的I am worker 为 I am worker1); $ /data1/adbox/local/php/bin/php worker1.php & $ /data1/adbox/local/php/bin/php client.php (执行多次前,思考下返回结果) start welcome to the feed queue , I am worker "abcd"end start welcome to the feed queue , I am worker1 "abcd"end
(2) 异步处理
给出了用 PHP 编写的一个 Gearman worker。将这些代码保存在一个名为 worker2.php 的文件中。
<?php
$worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction("reverse","my_reverse_function"); while ($worker->work()); function my_reverse_function($job) { sleep(1); echo strrev($job->workload()); echo "I am worker2\n"; }
?>
给出了用 PHP 编写的一个 Gearman worker。将这些代码保存在一个名为 worker3.php 的文件中。
<?php
$worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction("reverse","my_reverse_function"); while ($worker->work()); function my_reverse_function($job) { sleep(1); echo strrev($job->workload()); echo "I am worker3\n"; }
?>
给出了用 PHP 编写的一个 Gearman client。将这些代码保存在一个名为 client2.php 的文件中。
<?php
$client = new GearmanClient(); $client->addServer(); echo "beginning...\n"; for ($i = 0; $i < 100; $i++) { $client->doBackground('reverse',($i+1).'_Hello World!')."\n"; } echo "finishing...\n";
?>
这里的Client2.php就是任务的发起者,这里用两个worker连续处理100次字符串反转任务
$ /data1/adbox/local/php/bin/php worker2.php & $ /data1/adbox/local/php/bin/php worker3.php & $ /data1/adbox/local/php/bin/php client2.php
会返回 beginning... finishing... 然后我们看下worker返回 !dlroW olleH_1I am worker2 !dlroW olleH_2I am worker3 !dlroW olleH_3I am worker2 !dlroW olleH_4I am worker3 !dlroW olleH_5I am worker2... 发现在client2.php运行完成后,Worker2 和work3 则是每秒输出一条处理结果,直到所有的任务全部处理完成.
以上主要是说明异步处理是怎么回事,在目前的开发中,怎么将耗时过长的任务进行异步来处理。但在日常的开发中,可能有些任务耗时确实很长,但处理后的结果又需要很快的反馈给用户时,这里我们就需要将处理后的结果即时的保存到数据库中,然后靠专门的程序将结果反馈给用户。可能还会有一个问题,这样异步处理,万一处理失败了怎么办,同样的道理,我们可以将每个任务的处理状态保存起来,然后用程序定时的去扫描,将处理失败的任务再重启执行一次,反复下去,直接它成功完成为止。
(3) 持久化存储
如果我们运行一个 worker 后,然后执行client2.php,在client2.php的过程中,试着kill掉worker2.php,然后client2.php会终止执行。然后再重新打开worker2.php ,结果client2.php还是正常地完成它的工作;這是因为Job Server 幫我們把需求先放在 Queue 裡,等待 Worker 启动后再处理。
Gearman 的最新版本已经将系统特性扩展到了包含持久的作业队列和用一个新协议来通过 HTTP 提交工作请求。对于前者,Gearman 工作队列保存在内存并在一个关系型数据库内存有备份。这样一来,如果 Gearman 守护程序故障,它就可以在重启后重新创建这个工作队列。另一个最新的改良通过一个 memcached 集群增加队列持久性。memcached 存储也依赖于内存,但被分散于几个机器以避免单点故障。
(4) 高级特性
一个连接客户机和 worker 的 Gearman 网络实际上可以使用任何您能想象得到的结构。很多配置能够运行多个代理并将 worker 分配到许多机器上。负载均衡是隐式的:每个可操作的可用 worker(可能是每个 worker 主机具有多个 worker)从队列中拉出作业。一个作业能够同步或异步运行并具有优先级。