首發於 樊浩柏科學院
Gearman 是一個分佈式任務分發系統,經過程序調用(API,跨語言)分佈式地把工做委派給更適合作某項工做的機器,且這些機器能夠以併發的、負載均衡的形式來共同完成某項工做。當計算密集型場景時,適合在後臺使用 Gearman 異步地運行工做任務。php
Gearman 只是一個分佈式程序調用框架,其主要由三部分組成,並經過暴露給使用方的 API 來完成任務委派和執行。html
Gearman 中存在三個重要的角色,分別爲 Client、Job Server、Worker。mysql
Client、Job Server、Worker 典型的部署方案,以下圖:git
那麼,Gearman 是如何利用這三者進行任務的調度呢?github
能夠看出,在實際使用時,咱們只需調用 Gearman 已經實現了 Client 和 Worker 的 API,委派和註冊執行的任務,而無需關心任務的分發和機器的負載均衡問題。sql
到目前爲止,Gearman 已經提供了 C、Shell、Prel、 Nodejs、PHP、Python、Java、C#、Go、MySQL 等版本的 Client、Worker API,詳細信息見 這裏。本文只以 PHP 版爲例,列舉 Gearman 經常使用的 API 。vim
功能描述 | 方法(GearmanClient 類中) |
---|---|
註冊一個 Client | addServer(),單個 addServers(),多個 |
發起 Job 任務 | doNormal(),阻塞會等待 doBackground(),非阻塞 doLow(),低優先級任務 doHigh(),高優先級任務 |
添加 Tash(一組 Job) | addTask()、addTaskBackground() addTaskHigh()、addTaskHighBackground() addTaskLow()、addTaskLowBackground() |
發起 Tash 任務 | runTasks() |
獲取最新操做的結果 | returnCode() |
註冊事件回調 | setCompleteCallback()、setFailCallback() |
說明:Job 是單個任務,每一個任務只會在一個 Worker 上執行,而 Task 是一組 Job,其多個子任務會分配到多個 Worker 上並行執行。
功能描述 | 方法(GearmanWorker 類中) |
---|---|
註冊一個 Worker | addServer(),單個 addServers(),多個 |
註冊處理任務回調 | addFunction() |
等待和執行任務 | work() |
獲取最新操做的結果 | returnCode() |
功能描述 | 方法(GearmanJob 類中) |
---|---|
獲取任務攜帶的序列化數據 | workload() workloadSize(),獲取數據大小 |
向運行的任務發送數據 | sendData() |
說明:Gearman 各端之間數據交互時,數據須要進行序列化處理。
本文安裝 Gearman 須要兩步,第一步安裝守護程序(gearmand)的 Job,第二步安裝 PHP 擴展。api
首先,下載 Gearman 守護程序 gearmand 的 最新源碼,並解壓縮源碼包:php7
cd /usr/src $ wget https://github.com/gearman/gearmand/releases/download/1.1.17/gearmand-1.1.17.tar.gz $ tar zxvf gearmand-1.1.17.tar.gz
接着,安裝 gearmand 的依賴包,並編譯源碼安裝 gearmand:併發
$ yum install boost-devel gperf libuuid-devel libevent-devel $ cd ./gearmand-1.1.17.tar.gz $ ./configure $ make && make install # 安裝成功信息 Libraries have been installed in: /usr/local/lib - have your system administrator add LIBDIR to '/etc/ld.so.conf'
修改/etc/ld.so.conf
配置文件,添加 MySQL 動態連接庫地址:
# /usr/local/mysql/lib爲MySQL動態連接庫libmysqlclient.so的目錄 $ echo "/usr/local/mysql/lib" >>/etc/ld.so.conf # 使其生效 $ /sbin/ldconfig
而後,若是出現以下信息則表示安裝 gearmand 成功。
# 啓動Client和Worker $ gearman # 以下信息則表示成功 gearman Error in usage(No Functions were provided). Client mode: gearman [options] [<data>] # 查看gearmand版本 $ gearmand -V gearmand 1.1.17
從 PECL 下載最新 gearman 擴展(php7 需下載 最新源碼包),並解壓縮安裝:
$ cd /usr/src $ wget http://pecl.php.net/get/gearman-1.1.2.tgz $ tar zxvf gearman-1.1.2.tgz $ cd gearman-1.1.2 $ /usr/local/php/bin/phpize $ ./configure --with-php-config=/usr/local/php/bin/php-config $ make && make install # 安裝成功後信息 Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/
而後,配置 php.ini 文件:
$ php --ini Loaded Configuration File: /usr/local/php/lib/php.ini $ vim /usr/local/php/lib/php.ini #增長內容 extension=gearman.so
重啓 php-fpm 後,出現以下信息則表示安裝擴展成功。
$ php --info | grep "gearman" gearman support => enabled libgearman version => 1.1.17
運行 Gearman ,實際上咱們須要使用到 Client、 Job、Worker 這三個角色。gearman 端實現了 Client 和 Worker 角色的功能 ,使用 PHP 時以擴展形式存在,gearmand 端則實現了 Job 角色的功能。
# 先建立日誌目錄 $ gearmand -d --log-file=/var/log/gearmand.log
若是啓動時出現
Address family not supported by protocol 錯誤,須要增長
-L 0.0.0.0
參數。
查看啓動信息:
$ ps -ef | grep gearman root 6048 1 0 19:56 ? 00:00:00 gearmand -d # 監聽端口 $ netstat -tunpl | grep "gearmand" tcp 0 0 0.0.0.0:4730 0.0.0.0:* LISTEN 6048/gearmand
gearmand 命令的一些參數說明:
爲了方便管理 gearmand,能夠將 gearmand 註冊爲一個 service 服務。
經過 gearman 命令啓動 Client 和 Worker 並非必須的,這裏僅僅是爲了在命令行下測試工具。
首先,啓動一個 Worker,用於列出某個目錄的內容:
$ gearman -w -f ls -- ls -lh
而後,建立一個 Client,用於查找請求的一個做業:
$ gearman -f ls < /dev/null total 4.0K drwxr-xr-x. 21 www www 4.0K Jun 21 23:52 www
當啓動 Job 服務後,PHP 就能夠經過 Gearman 擴展,建立任務和綁定任務處理回調了。PHP 調用 Gearman 的 API 見 外部 API 部分,更多官方示例見 這裏。
Client 工做在同步阻塞模式,Client 發起任務後會等待至 Worker 執行任務結束。
//Client.php $client= new GearmanClient(); $client->addServer(); $msg = 'Hello World!'; echo "Sending $msg\n"; echo "Success: ", $client->doNormal("reverse", $msg), "\n";
//Worker.php $worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction("reverse", "reverse_fn"); echo "Waiting for job...\n"; while ($worker->work()); function reverse_fn($job) { $workload = $job->workload(); echo "Workload: $workload\n"; $result = strrev($workload); echo "Result: $result\n"; return $result; }
輸出結果爲:
//Client Sending Hello World! Success: !dlroW olleH //Worker Waiting for job... Workload: Hello World! Result: !dlroW olleH
三端的交互流程圖,以下:
異步方式時,Client 端不會產生 IO 阻塞,能實現異步執行,在實際應用中能夠結合 fastcgi_finish_request() 函數或者 MQ 來異步使用。
$client= new GearmanClient(); $client->addServer(); $client->setDataCallback("reverse_data"); $msg = 'Hello World!'; echo "Sending $msg\n"; $task = $client->addTaskBackground("reverse", $msg); $msg = 'I am Gearman!'; echo "Sending $msg\n"; $task = $client->addTaskBackground("reverse", $msg); $client->runTasks(); function reverse_data($task) { echo "Data: " . $task->data() . "\n"; }
$worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction("reverse", "reverse_fn"); echo "Waiting for job...\n"; while ($worker->work()); function reverse_fn($job) { $workload = $job->workload(); echo "Workload: $workload\n"; $result = strrev($workload); $job->sendData($result); echo "Result: $result\n"; return $result; }
輸出結果爲:
//Client Sending Hello World! Data: !dlroW olleH //Worker1 Waiting for job... Workload: Hello World! Result: !dlroW olleH //Worker2 Waiting for job... Workload: I am Gearman! Result: !namraeG ma I
Gearman 可使用 GearmanManager 做爲管理工具,命令行下可使用 gearadmin 命令來進行簡易的管理。
$ gearadmin --show-jobs 32 ::7866:86a6:d87f:0%32 - : reserve $ gearadmin --show-jobs H:fhb:79 0 1 0 H:fhb:86 0 1 0 $ gearadmin --status reverse 1 0 0 ls 0 0 0
雖然 Gearman 出現的比較早,可是其支持跨語言調用特性,以及負載均衡的方式委派任務,在分佈式系統下,能夠更加合理高效地利用系統資源。在一些大型的密集型、異步後臺系統也已有成功部署的案例(數據抓取,庫存數據更新、郵件和短信服務等),另 PHP 藉助 Gearman 也能實現多任務處理方案。
推薦: 用 Gearman 分發 PHP 應用程序的工做負載