gearman是什么?
它是分布式的程序调用框架,可完成跨语言的相互调用,适合在后台运行工作任务。最初是2005年perl版本,2008年发布C/C 版本。目前大部分源码都是(Gearmand服务job Server)C ,各个API实现有各种语言的版本。PHP的Client API与Worker API实现为C扩展,在PHP官方网站有此扩展的中英文文档。
gearman架构中的三个角色
client:请求的发起者,工作任务的需求方(可以是C、PHP、Java、Perl、Mysql udf等等)
Job Server:请求的调度者,负责将client的请求转发给相应的worker(gearmand服务进程创建)
worker:请求的处理者(可以是C、PHP、Java、Perl等等)
gearman是如何工作的?
从上图可以看出,Gearman Client API,Gearman Worker API,Gearman Job Server都是由gearman本身提供,我们在应用中只需要调用即可。目前client与worker api都很丰富。
gearman的吞吐能力
经过的测试,结果如下:
系统环境:ubuntu-14.0.4 1个CPU 4核 2G内存 (虚拟机)
默认启动:./gearmand -d
client.php
代码语言:javascript复制<?php
echo "starting...", microtime(true), "n";
$gmc = new GearmanClient();
$gmc->setCompleteCallBack(function($task){
//echo $task->data(), "n";
});
$gmc->addServer("127.0.0.1", 4730);
for ($i = 0; $i < 100000; $i ) {
$gmc->addTaskBackground("reserve", "just test it", null, $i);
}
$gmc->runTasks();
echo "end...", microtime(true), "n";
worker.php
代码语言:javascript复制<?php
$gmw = new GearmanWorker();
$gmw->addServer("127.0.0.1", 4730);
$gmw->addFunction("reserve", function($job) {
if ($job->unique() == 99999) {
echo microtime(true), "n";
}
return strrev($job->workload());
});
while($gmw->work());
启动一个job server实例:job server IP:127.0.0.1 PORT:4730
启动一个worker: php worker.php
worker注册reserve函数,将client的job字符串反转后返回。
client工作任务的消息为:just test it(12字节)
同步:4100/s异步:25700/s
memcached内存准持久化的吞吐能力测试./gearmand -d -q libmemcached --libmemcached-servers=127.0.0.1:11211
client投递100000个工作任务:16400/s
gearman典型的部署结构
从上图可以看出,gearman支持的特性:
1.高可用
启动两个job server,他们是独立的服务进程,有各自的内存队列。当一个job server进程出现故障,另一个job server可以正常调度。(worker api与client api可以完成job server故障的切换)。在任何时候我们可以关闭某个worker,即使那个worker正在处理工作任务(Gearman不会让正在被执行的job丢失的,由于worker在工作时与Job server是长连接,所以一旦worker发生异常,Job server能够迅速感知并重新派发这个异常worker刚才正在执行的工作)
2.负载均衡(附gearman协议会详细解释)
job server并不主动分派工作任务,而是由worker从空闲状态唤醒之后到job server主动抓取工作任务。
3.可扩展
松耦合的接口和无状态的job,只需要启动一个worker,注册到Job server集群即可。新加入的worker不会对现有系统有任何的影响。
4.分布式
gearman是分布式的任务分发框架,worker与job server,client与job server通信基于tcp的socket连接。
5.队列机制
gearman内置内存队列,默认情况队列最大容量为300W,可以配置最大支持2^32-1,即4 294 967 295。
6.高性能
作为Gearman的核心,Job server的是用C/C 实现的,由于只是做简单的任务派发,因此系统的瓶颈不会出在Job server上。
两种工作任务
后台工作任务Background job——时序图
由图可知,client提交完job,job server成功接收后返回JOB_CREATED响应之后,client就断开与job server之间的链接了。后续无论发生什么事情,client都是不关心的。同样,job的执行结果client端也没办法通过Gearman消息框架 获得。
一般工作任务Non-background job——时序图
由图可知,client端在job执行的整个过程中,与job server端的链接都是保持着的,这也给job完成后job server返回执行结果给client提供了通路。同时,在job执行过程当中,client端还可以发起job status的查询。当然,这需要worker端的支持的。
关于持久化
对于队列持久化的问题,是一个值得考虑的问题。持久化必然影响高性能。gearman支持后台工作任务的持久化,支持drizzle、mysql、memcached的持久化。对于client提交的background job,Job server除了将其放在内存队列中进行派发之外,还会将其持久化到外部的持久化队列中。一旦Job server发生问题重启,外部持久化队列中的background job将会被恢复到内存中,参与Job server新的派发当中。这保证了已提交未执行的background job不会由于Job server发生异常而丢失。并且我测试发现如果开启了持久化,那么后台工作任务会先将工作任务写到持久化介质,然后在入内存队列,再执行。非后台工作任务,由于client与job server是保持长连接的状态,如果工作任务执行异常,client可以灵活处理,所以无须持久化。
gearman框架中的一个问题
从典型部署结构看出,两个Job server之间是没有连接的。也就是Job server间是不共享background job的。如果通过让两个Job server指向同一个持久化队列,可以让两个Job serer互相备份。但实际上,这样是行不通的。因为Job server只有在启动时才会将持久化队列中的background job转入到内存队列。也就是说,Job server1如果宕机且永远不启动,Job server2一直正常运行,那么Job server1宕机前被提交到Job server1的未被执行的background job将永远都呆在持久化队列中,得不到执行。另外如果多个job server实例指向同一个持久化队列,同时重启多个job server实例会导致持久队列中的工作任务被多次载入,从而导致消息重复处理。
我建议的部署结构
采用memcached做后台工作任务的准持久化队列,最好memcached和job server在内网的不同机器。两个机器的两个服务同时挂掉的可能性比较小,同时也保证了高性能。而且memcached应该为两个相互独立实例,防止其上述的gearman框架中的问题。我们可以做一个监控脚本,如果某个job server异常退出,可以重启,也最大化的保证了job server的高可用。
关于gearman的管理工具
目前有一个现在的管理工具,https://github.com/brianlmoon/GearmanManager,但是只支持php-5.2,不过可以自行修改支持php-5.4,我建议如果使用PHP作为worker进程,使用php-5.4以上的版本。该工具的设计方法可以借鉴,可以比较好的管理gearman worker。时间有限,还没有深入研究。
应用场景
1.结合linux crontab,php脚本负责产生job,将任务分发到多台服务器周期性的并发执行。可以取代目前我们比较多的crontab的工作任务。
2.邮件短信发送
3.异步log
4.跨语言相互调用(对于密集型计算的需求,可以用C实现,PHP直接调用)
5.其他耗时脚本
gearman安装(unbuntu)
1.下载
#wget https://launchpadlibrarian.net/165674261/gearmand-1.1.12.tar.gz
2.安装依赖包
#sudo apt-get install libboost1.55-all-dev gperf libevent libevent-dev uuid libmemcached-dev #tar zxvf gearmand-1.1.12.tar.gz #cd gearmand-1.1.12.tar.gz
#./configure --prefix=/home/phpboy/Server/gearman
#make & make install
3.启动
a)默认启动
./gearman -d
b)支持memcached准持久化
./gearmand -d -q libmemcached --libmemcached-servers=127.0.0.1:11211
4.安装php的gearman扩展
#wget http://pecl.php.net/get/gearman-1.1.2.tgz #tar zxvf gearman-1.1.2.tgz#cd gearman-1.1.2 #phpize #./configure --with-php-config=php-config #make & make install
5.php client api与php worker api的测试,可以用上面我的测试的示例
附gearmand(job server的启动参数简单说明)
-b, –backlog=BACKLOG 连接请求队列的最大值 -d, –daemon Daemon 守护进程化 -f, –file-descriptors=FDS 可打开的文件描述符数量 -h, –help -l, –log-file=FILE Log 日志文件 -L, –listen=ADDRESS 开启监听的地址 -p, –port=PORT 开启监听的端口 -P, –pid-file=FILE File pid file -r,–protocol=PROTOCOL 使用的协议 -q, –queue-type=QUEUE 持久化队列类型 -t, –threads=THREADS I/O线程数量 -u, –user=USER 进程的有效用户名 libdrizzle Options: --libdrizzle-host=HOST Host of server. --libdrizzle-port=PORT Port of server. --libdrizzle-uds=UDS Unix domain socket for server. --libdrizzle-user=USER User name for authentication. --libdrizzle-password=PASSWORD Password for authentication. --libdrizzle-db=DB Database to use. --libdrizzle-table=TABLE Table to use. --libdrizzle-mysql Use MySQL protocol. libmemcached Options: --libmemcached-servers=SERVER_LIST List of Memcached servers to use. libsqlite3 Options: --libsqlite3-db=DB Database file to use. --libsqlite3-table=TABLE Table to use. libpq Options: --libpq-conninfo=STRING PostgreSQL connection information string. --libpq-table=TABLE Table to use. http Options: --http-port=PORT Port to listen on.
附gearman通信协议,个人翻译与理解:
总括
Gearman工作在TCP上,默认端口为4730,client与job server、worker与job server的通信都基于此tcp的socket连接。client是工作任务的发起者,worker是可以注册处理函数的工作任务执行者,job server为工作的调度者。协议包含请求报文与响应报文两个部分,所有发向job server的数据包(TCP报文段的数据部分)认为是请求报文,所有从job server发出的数据包(TCP报文段的数据部分)认为是响应报文。worker或者client与job server间的通信是基于二进制数据流的,但在管理client也有基于行文本协议的通信。
请求的报文体
响应的报文体
、
二进制包
请求报文与响应报文是由二进制包封装。一个二进制包由头header和可选的数据部分data组成。
header的组成
a.报文类别,请求报文或者响应报文,4个字节 "