PHP利用Gearman來處理並行多進程問題php
by yuansirweb
2013 年 11 月 25 日shell
Linux, PHP, 開發應用服務器
0網絡
轉載請註明: 轉載自Yuansir-web菜鳥 | LAMP學習筆記併發
本文連接地址: PHP利用Gearman來處理並行多進程問題負載均衡
最近工做中開發的一套系統,其中不少都是須要操做多服務器的,好比須要同時發佈數據到2000個服務器上,或者同時向2000個服務器拉取數據。剛開始的解決方案就是單純用PHP的curl_multi的方式併發處理請求,並且參考了淘寶技術博客的《Rolling cURL: PHP併發最佳實踐》,可是因爲網絡和數據以及各個服務器等等的一些狀況致使這種併發處理的響應時間很慢,由於在併發請求的過程當中還包括記錄日誌,處理數據等邏輯,等待處理結果並返回,因此也不能友好的知足後臺操做的體驗。curl
如今從新設計一種方案,利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 鏈接來進行的。
stackGearman能夠將工做的負載分擔到不一樣的機器中。
cluster
安裝配置
我只是記錄下我安裝配置的過程,我在Ubuntu和CentOS中都試了下。
CentOS YUM 安裝
1
rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/x86_64/epel-release-6-5.noarch.rpm
2
yum install -y gearmand
Ubuntu apt 安裝
1
apt-get install gearman
源碼編譯
1
yum install uuid-devel libuuid libuuid-devel uuid boost-devel libevent libevent-devel
2
wget -c https://launchpad.net/gearmand/1.2/1.1.7/+download/gearmand-1.1.7.tar.gz
3
tar zxvf gearmand-1.1.7.tar.gz
4
./configure --prefix=/usr/local/gearmand
5
make && make install
安裝好之後啓動
1
gearmand -d
加上-d參數是表示後臺運行,你能夠gearmand -h 來查看其它的選項,啓動的時候帶上其它配置參數
1
/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
安裝PHP Gearman擴展
我都是用pcel來安裝的,你也能夠下載源碼包來編譯安裝,可是記得要先安裝libgearman和re2c,否則擴展編譯安裝會出錯。
01
pecl install gearman #不成功並提示版本問題能夠試試 pecl install gearman-1.0.3,默認好像是1.1.2
02
03
編譯安裝也很簡單
04
05
wget -c http://pecl.php.net/get/gearman-1.1.1.tgz
06
tar zxvf gearman-1.1.1.tgz
07
phpize
08
./configure
09
make && make install
10
echo "extension=gearman.so" >> /etc/php.ini
PHP接口函數
Gearman提供不少完善的擴展函數,包括GearmanClient,GearmanJob,GearmanTask,GearmanWorker,具體能夠查看PHP官方手冊.
這是官方提供的Example其中的一個,至關與一個併發的分發任務處理的例子
gearman_client.php
01
<?php
02
03
$client = new GearmanClient();
04
$client->addServer();
05
06
// initialize the results of our 3 "query results" here
07
$userInfo = $friends = $posts = null;
08
09
// This sets up what gearman will callback to as tasks are returned to us.
10
// The $context helps us know which function is being returned so we can
11
// handle it correctly.
12
$client->setCompleteCallback(function(GearmanTask $task, $context) use (&$userInfo, &$friends, &$posts) {
13
switch ($context)
14
{
15
case 'lookup_user':
16
$userInfo = $task->data();
17
break;
18
case 'baconate':
19
$friends = $task->data();
20
break;
21
case 'get_latest_posts_by':
22
$posts = $task->data();
23
break;
24
}
25
});
26
27
// Here we queue up multiple tasks to be execute in *as much* parallelism as gearmand can give us
28
$client->addTask('lookup_user', 'joe@joe.com', 'lookup_user');
29
$client->addTask('baconate', 'joe@joe.com', 'baconate');
30
$client->addTask('get_latest_posts_by', 'joe@joe.com', 'get_latest_posts_by');
31
32
echo "Fetching...\n";
33
$start = microtime(true);
34
$client->runTasks();
35
$totaltime = number_format(microtime(true) - $start, 2);
36
37
echo "Got user info in: $totaltime seconds:\n";
38
var_dump($userInfo, $friends, $posts);
gearman_work.php
01
<?php
02
03
$worker = new GearmanWorker();
04
$worker->addServer();
05
06
$worker->addFunction('lookup_user', function(GearmanJob $job) {
07
// normally you'd so some very safe type checking and query binding to a database here.
08
// ...and we're gonna fake that.
09
sleep(3);
10
return 'The user requested (' . $job->workload() . ') is 7 feet tall and awesome';
11
});
12
13
$worker->addFunction('baconate', function(GearmanJob $job) {
14
sleep(3);
15
return 'The user (' . $job->workload() . ') is 1 degree away from Kevin Bacon';
16
});
17
18
$worker->addFunction('get_latest_posts_by', function(GearmanJob $job) {
19
sleep(3);
20
return 'The user (' . $job->workload() . ') has no posts, sorry!';
21
});
22
23
while ($worker->work());
我在3個終端中都執行了gearman_work.php
1
ryan@ryan-lamp:~$ ps aux | grep gearman* | grep -v grep
2
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
3
ryan 2992 0.0 0.8 43340 9036 pts/0 S+ 14:05 0:00 php /var/www/gearmand_work.php
4
ryan 3713 0.0 0.8 43340 9036 pts/1 S+ 14:05 0:00 php /var/www/gearmand_work.php
5
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
1
Fetching...
2
Got user info in: 3.03 seconds:
3
string(59) "The user requested (joe@joe.com) is 7 feet tall and awesome"
4
string(56) "The user (joe@joe.com) is 1 degree away from Kevin Bacon"
5
string(43) "The user (joe@joe.com) has no posts, sorry!"
看到上面的3.03 seconds,說明client請求過去的任務被並行分發執行了。
在實際的生產環境中,爲了監測gearmand和work的進程沒有被意外退出,咱們能夠藉助Supervisor這個工具,下次我再單獨來寫個Supervisor的筆記。
(轉載請標明出處:Yuansir-web菜鳥-LAMP學習筆記:PHP利用Gearman來處理並行多進程問題)