[TOC]
# 1 Gearman简介
## 1.1 概况
Gearman是一个用来把工作委派给其他机器、分布式的调用更适合做某项工作的机器、并发的做某项工作在多个调用间做负载均衡、或用来在调用其它语言的函数的系统。
## 1.2 组成
Gearman是一个分发任务的程序架构,由三部分组成:
* Gearman client:提供gearman client API给应用程序调用。API可以使用C,PHP,PERL,MYSQL UDF等待呢个语言,它是请求的发起者。
* Gearman job server:将客户端的请求分发到各个gearman worker的调度者,相当于中央控制器,但它不处理具体业务逻辑。
* Gearman worker:提供gearman worker API给应用程序调用,具体负责客户端的请求,并将处理结果返回给客户端。
## 1.3 应用
Mogilefs的分布式文件系统的核心就是用gearman实现的。
* 这个软件的应用场景很多,比如视频网站的视频处理,分布式日志处理,电子邮件处理,文件同步处理,图片处理等等,只要是可以放开,不影响体验和响应的场 景,需要并行进行大量计算和处理的程序都是可以的。Yahoo在60或更多的服务器上使用gearman每天处理600万个作业。新闻聚合器digg构建 了一个相同规模的gearman网络,每天可处理400000个作业。
* Gearman不但可以做为任务分发,还可以做为应用方面的负载均衡。可以让worker放在不同的一堆服务器上,也可以启动放在同一个cpu的多个核 上。比如,应用视频转换程序,不希望web服务器来处理视频格式转换,这时,可以在这一堆服务器上进行任务分发,在上面加载worker处理视频格式,对 外的web服务器就不会被视频转换过程影响。而且扩展方便,加一台服务器到任务调度中心,注册成worker即可,这时job server会在请求到来的时候,将请求发送给空闲的worker。还可以运行多个job server,组成ha架构,如果一个job server当掉了,client和worker会自动迁移到另一台job server上。
1.4 工作原理图
![](https://box.kancloud.cn/71a0489ae48c6002ca8f92d3f043d288_479x302.png)
2 运行过程
`一个Gearman请求的处理过程涉及三个角色:Client -> Job -> Worker。`
* Client:请求的发起者,可以是 C,PHP,Perl,MySQL UDF 等等。
* Job:请求的调度者,用来负责协调把 Client 发出的请求转发给合适的 Work。
* Worker:请求的处理者,可以是 C,PHP,Perl 等等。
`因为 Client,Worker 并不限制用一样的语言,所以有利于多语言多系统之间的集成。`
`甚至我们通过增加更多的 Worker,可以很方便的实现应用程序的分布式负载均衡架构。`
# 3 Gearman下载
1)官网
http://gearman.org/
2)官网下载
https://launchpad.net/gearmand
3)官网使用向导
http://gearman.org/getting-started/
4)gearman服务
https://github.com/gearman/gearmand/releases
5)gearman-php扩展
https://github.com/wcgallego/pecl-gearman/releases
# 4 Gearman安装
```
//更新下载列表
apt-get update
//安装服务
apt-get install gearman-server
apt-get install gearman-job-server
apt-get install gearman-tools
//查看进程 是否安装成功
ps -aux | grep gearman
gearman 10896 0.0 0.6 68684 6448 ? Ssl Mar06 0:06 /usr/sbin/gearmand --log-file=/var/log/gearman-job-server/gearman.log
root 22920 0.0 0.2 4692 2072 pts/3 S+ 10:23 0:00 grep --color=auto gear
//查看监听端口
# netstat -anp | grep 4730
```
## 4.1 详细参数
-b,--backlog= 储备的监听连接数量
-d, --daemon 后台运行
-f, --file-descriptors= 文件描述符的数量
-h, --help 帮助
-j, --job-retries= 在ob server移除不可用job之前运行的次数,防止不断运行导致其他可用worker崩溃。默认没有限制
-l, -log-file= 日志文件存放位置(默认记录最简单日志)
-L, --listen= 监听的IP,默认全部接受
-p, --port= 指定监听端口
-P, --pid-file= 指定进程ID写入位置
-r, --protocol= 加载协议模块
-q, --queue-type= 指定持久化队列
-t, --threads= 使用的I/9线程数量。默认为0
-u, --user= 启动后,切换到指定用户
-V, --version 显示版本信息
## 5 Gearadmin 管理
```
输入以下命令,查看4730端口情况。
(echo "status" ; sleep 2 ) | telnet 192.168.142.130 4730
或者输入以下命令查看gearman运行情况
# gearadmin --status
email002
emailtemplate001
```
* 字段说明:"已知注册的任务" "正在运行的任务" "队列中的任务" "可用的 Worker".
* emailtemplate 0 0 1,注册的任务名为 emailtemplate,0 个正常在运行,队列为空,有一个可用的 Worker.
## 5.1 常用参数
* --status 查看 Status for the server.
* --workers 查看 Workers for the server.
* --shutdown 关闭服务器。
# 6 Gearman使用
## 6.1 Gearmanjob
```php
/**
* @param array $argv 传入worker名称
* 或者 $_SERVER['argv']
*
*/
$channel = !empty($argv[1]) ? $argv[1] : 'email';
$worker = new GearmanWorker();
$worker->addServer('192.168.142.130', '4730');
//参数1:worker在Gearadmin管理中显示的名称,参数2回调方法
$worker->addFunction($channel,array(new GearmanWorkerDeal($channel),'invoke'));
while($worker->work());
```
## 6.2 GearmanWorker
```php
class GearmanWorkerDeal{
public $channel;
public static $dealResult = false;
public function __construct($channel = 'email') {
$this->channel = $channel;
}
/**
* @param GearmanJob $job
*/
public function invoke(GearmanJob $job) {
$ret = $job->workload();
$ret = unserialize($ret);
$func = $this->channel.'Invoke';
if(!empty($ret) && method_exists(new GearmanWorkerDeal($this->channel),$func)) {
//业务处理
$this->$func($ret);
}
}
public function emailInvoke($data = []){
$vars = [
'to'=>[$data['email']],
'sub'=>[
'%userName%'=>[$data['userName']],
'%subject%'=>[''],
'%content%'=>[$data['content']],
'%emailIconClass%' => [$data['type']],
],
];
$params = array(
'api_user'=>'api_user',
'api_key'=>'api_key',
'template_invoke_name' => '模版名称',
'subject' => '标题',
'from' => '发件人邮箱',
'fromname' => '发件人姓名',
'substitution_vars'=>json_encode($vars),
);
$ret = self::requestApi($params);
}
//请求接口发送
public static function requestApi($params = []) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_URL, 'https://sendcloud.sohu.com/webapi/mail.send_template.json');
//不同于登录SendCloud站点的帐号,您需要登录后台创建发信子帐号,使用子帐号和密码才可以进行邮件的发送。
curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
$result = curl_exec($ch);
//请求失败
if($result === false) {
echo 'last error : ' . curl_error($ch);
}
curl_close($ch);
return $result;
}
}
```
## 6.3 启动Job端
启动job端 任务服务器,让该命令在后台执行,并把输出重定向到email_error.log文件。
`nohup /usr/bin/php /data/Gearmanjob.php email > /data/email_error.log 2>&1 &`
>[info]
> nohup:不挂断地运行命令
> &:在后台运行
> 2>&1:是将标准出错重定向到标准输出,这里的标准输出已经重定向到了email_error.log文件,即将标准出错也输出到email_error.log文件中
## 6.4 创建Client
```php
$client = new GearmanClient();
$client->addServer('192.168.142.130', '4730');
$data = [
'email' => '',
'userName' => '',
'content' => '',
'type' => ''
]
//参数1:Worker的名称,参数2:序列化后的参数
$ret = $client->doBackground('emial', serialize($data));
echo $ret."\r\n";
```
# 7 使用注意
* 在调试或者更新Worker代码后,一定要重启进程。
* 命令行下执行带参数php,并取得参数:
* 可使用 $argv 或者 $_SERVER['argv'] 或者 getopt('a:b:')
* 测试文件
```php
print_r($argv);
echo "\n";
echo $argc;
echo "\n";
?>
```
* 命令行下调用
```
$ php test.php aaa ccc bbbb
Array
(
[0] => test.php //参数0,文件本身
[1] => aaa //参数1
[2] => ccc //参数2
[3] => bbbb //参数3
)
4 //$argc的值,参数的总数
```