任务调度程序-Gearman
2012-10-02 17:37:43 阿炯

本站赞助商链接,请多关照。 Gearman是一个分发任务的程序框架,可以用在各种场合,与Hadoop相比,Gearman更偏向于任务分发功能。它的 任务分布非常简单,简单得可以只需要用脚本即可完成。Gearman最初用于LiveJournal的图片resize功能,由于图片resize需要消耗大量计算资源,因此需要调度到后端多台服务器执行,完成任务之后返回前端再呈现到界面。采用C语言开发并BSD协议下授权,并支持如下的编程语言:C, Shell, Perl, PHP, Python, Java, MySQL, JMS, C#, .NET, Go。


Gearman provides a generic application framework to farm out work to other machines or processes that are better suited to do the work. It allows you to do work in parallel, to load balance processing, and to call functions between languages. It can be used in a variety of applications, from high-availability web sites to the transport of database replication events. In other words, it is the nervous system for how distributed processing communicates.


Gearman 分布式任务实现原理上只用到2个字段,function name和data。function name即任务名称,由client传给job server, job server根据function name选择合适的worker节点来执行。data通常为执行任务所需的自定义的内容,比如简单的做法可以把需要执行的脚本当成data即可(当然要注 意其中的安全防范)。如果有多个worker可以处理同一个function name, 则job server会自动分配一个。当用于远程监控场景时,可以让每个worker注册成不同的业务名称,以达到方便控制每台worker节点的目的。

Gearman提供了一个通用的应用程序框架,用于将工作转移到更适合于工作的其他机器或流程。它允许并行工作,负载平衡处理,并在语言间调用函数。它可用于从高可用性网站到传输数据库复制事件的各种应用程序。换句话说,它是分布式处理交流的神经系统。关于它的一些优点:

开源它是开源的!Gearman有一个活跃的开源社区,如果需要帮助或者想贡献,都很容易参与进来。担心授权?Gearman是BSD。

多语言 - 有一些语言的接口,这个列表正在增长。您也可以选择使用一种语言提交工作的客户端编写异构应用程序,并在另一种语言中执行该工作的工作人员。

灵活 - 您不受限于任何特定的设计模式。您可以使用您选择的任何模型快速组合分布式应用程序,这些选项之一是Map/Reduce。

快速 - Gearman有一个简单的协议和接口,用C / C ++编写的优化的,线程化的服务器可以最大限度地减少应用程序开销。

嵌入式 - 由于Gearman速度快,重量轻,适用于各种尺寸的应用。以最小的开销引入现有的应用程序也很容易。

没有单点故障 - Gearman不仅可以帮助扩展系统,而且还可以通过容错方式实现。

消息大小没有限制 - Gearman支持最多4gib的单个消息。需要做更大的事情?没问题的,它可以处理大块的消息。

Features
Open Source  - It's free! (in both meanings of the word) Gearman has an active open source community that is easy to get involved with if you need help or want to contribute.

Multi-language  - There are interfaces for a number of languages, and this list is growing. You also have the option to write heterogeneous applications with clients submitting work in one language and workers performing that work in another.

Flexible  - You are not tied to any specific design pattern. You can quickly put together distributed applications using any model you choose, one of those options being Map/Reduce.

Fast  - Gearman has a simple protocol and interface with a new optimized server in C to minimize your application overhead.

Embeddable  - Since Gearman is fast and lightweight, it is great for applications of all sizes. It is also easy to introduce into existing applications with minimal overhead.

No single point of failure  - Gearman can not only help scale systems, but can do it in a fault tolerant way.


特点
Open Source: 属于开放源代码,同时,建立社群提供问题的协助平台。
Multi-language: 多国语言界面。
Flexible: 灵活,不需要设计其他模式,可以快速将应用程序分布运作。
Fast: 它有简单的协定,减少执行没有相关的时间。
Embeddable: 嵌入式,快速与轻量,处理各种应用程序。
No single point of failure: 不仅可以将系统模组化,也能容错方式进行。
No limits on message size: 支援单一讯息 4 gig 大小。
Worried about scaling: 各平台行皆有使用经验,e.g. Tumblr, Yelp, Etsy, etc。


运作原理
Gearman 主要分成三个部分,需求的处理过程涉及三个角色:Client -> Job -> Worker。

Client: 负责建立一个工作,发送需求 (application) 给 Job Server,而 Job Server 会去找适合的 Worker 去转发工作。

Job Server: 了解 Client 端的需求,并查看哪个机器可以处理这项要求,在系统里它通常会是个 Daemon。

Worker: Worker 通过 Job Server 的分派,开始执行 Client 端的工作。

Message Queue
执行 Message Queue 服务的 Job Server 可以是多台服务器组成,也就是分散式架构,在 Job Server 上执行 Worker 程式。
这些 Worker 程式会一直循环地等候,直到 Job Server 呼叫它执行工作。
Client 端发送出需求之后,会将需要的资料及动作记录在 Job Server 上,这时 Job Server 会查看是否有空闲并符合需求的 Worker。
在 Worker 结束工作后,会发送通知给 Job Server ,这时 Job Server 就会视状况把结果回传给 Client。
Client 端不需等候需求的执行结果,可以直接继续执行其他动作。

Job Server 负载方式
当 Client 可能同时发出多个需求给 Job Server,由 Message Queue 接手进行列队。而 Job Server 开始处理多个需求,若其中一个发生问题,可以 Failover 到其他的机器。同时,Worker 会将多个需求一起进行运算,再看是同步或异步模式,回传结果给 Client。

同步 (Synchronous)
同步(Synchronous) 是指 Client 将需求 (Application) 丢给 Gearmand。
由 Gearmand 分派 Job 给各 Worker 去处理。
并同步 Response 回传给 Gearmand 告诉 Client 现在进度。

异步 (Asynchronous)
异步 (Asynchronous) 是指 Client 将需求 (Application) 丢给 Gearmand。
由 Gearmand 分派 Job 给各 Worker 去处理。
Worker 处理完毕后,才会将结果回传给 Gearmand 告诉 Client 现在进度。


Gearman如何工作原理

Gearman堆栈



一个Gearman驱动的应用程序由三部分组成:一个客户端,一个工作者和一个作业服务器。客户端负责创建要运行的作业并将其发送到作业服务器。作业服务器将找到可以运行作业并转发作业的合适工作人员。工作人员执行客户端请求的工作,并通过作业服务器向客户端发送响应。Gearman提供您的应用程序调用的客户端和工作者API来与Gearman作业服务器(也称为gearmand)交谈,因此您不需要处理网络或作业的映射。在内部,gearman客户端和工作者API使用TCP套接字与作业服务器进行通信。为了更详细地解释Gearman的工作原理,我们来看看一个简单的应用程序,它将颠倒字符串中字符的顺序。这个例子在PHP中给出,

首先编写一个客户端应用程序,负责发送作业并等待结果,以便打印出来。它通过使用Gearman客户端API来发送一些与函数名相关的数据,在这种情况下是函数reverse。这个代码是(为了简洁,省略了错误处理):
<?php>
// Reverse Client Code
$client = new GearmanClient();
$client->addServer();
print $client->do("reverse", "Hello World!");

此代码初始化一个客户端类,将其配置为使用带有add_server(不带参数表示使用127.0.0.1默认端口)的作业服务器,然后通知客户端API以reverse工作负载“Hello world!”运行该功能。就Gearman而言,函数名称和参数是完全任意的,所以您可以发送适合您应用程序的任何数据结构(文本或二进制文件)。此时,Gearman客户端API将把该作业打包到一个Gearman协议数据包中,并将其发送到作业服务器以查找可以运行该reverse 功能的合适的工作人员。现在让来看看工人代码:
<?php>
// Reverse Worker Code
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction("reverse", function ($job) {
  return strrev($job->workload());
});
while ($worker->work());

Gearman流



这段代码定义了一个函数my_reverse_function,它接受一个字符串并返回该字符串的反转。它被一个工作对象用来注册一个函数,该函数reverse被设置为连接到与客户端相同的本地作业服务器。当作业服务器接收到要运行的作业时,它查看已经注册了该功能名称reverse的工作人员列表,并将该作业转发给其中一个空闲工作人员。然后,Gearman工作者API接受这个请求,运行该功能my_reverse_function,并通过作业服务器将该功能的结果发送回客户端。

如您所见,客户端和工作者API(以及作业服务器)处理作业管理和网络通信,因此您可以专注于应用程序部分。有几种不同的方法可以在Gearman中运行作业,包括异步处理和优先作业的背景。有关详细信息,请参阅可用于各种API文档。

Gearman如何有用

上面的例子看起来像是很多工作来运行一个函数,但是有很多方法可以用。最简单的答案是,你可以使用Gearman作为用不同语言编写的客户端和工作者之间的接口。如果希望PHP-Web应用程序调用用C语言编写的函数,则可以将PHP客户端API与C工作程序API配合使用,并在中间粘贴作业服务器。当然,还有更高效的方式来做这件事(比如用C写一个PHP扩展),但是你可能需要一个PHP客户端和一个Python工作者,或者一个MySQL客户端和一个Perl工作者。您可以轻松地混合和匹配任何支持的语言界面,只需要所有应用程序都能够理解所发送的工作量。你最喜欢的语言是不是支持?获得参与项目,对于你或者现有的Gearman开发人员来说,在C库的顶部放置一个语言包装可能相当容易。

Gearman的另一个有用的方法是把工作代码放在一个更适合工作的单独的机器上(或者一组机器上)。假设PHP-Web应用程序想要进行图像转换,但这是在Web服务器机器上运行它的太多处理。您可以将映像发送到单独的一组工作机器上进行转换,这样负载不会影响Web服务器和其他PHP脚本的性能。通过这样做,您也可以获得一种自然形式的负载平衡,因为作业服务器仅向闲置的工作人员发送新作业。如果在特定机器上运行的所有工作人员都很忙,则不必担心在那里发送新工作。这使得多核服务器的扩展非常简单:工人机器上有16个核心吗?启动你的工人的16个实例(或更多,如果他们没有CPU绑定)。也可以无缝添加新机器来扩展您的工作池,只需启动它们,安装工作代码,并将它们连接到现有的作业服务器。

Gearman集群



现在可能会问如果作业服务器死亡?您可以运行多个作业服务器,并让客户端和工作人员连接到配置的第一个可用作业服务器。这样,如果一个工作服务器死亡,客户端和工作人员会自动故障转移到另一个工作服,可能不想运行太多的作业服务器,但有两到三个是冗余的好主意。左图显示了一个简单的Gearman集群的外观。

从这里可以根据需要扩展您的客户和工作人员。作业服务器可以轻松处理一次连接数百个客户端和工作人员。可以在容量允许的情况下绘制自己的物理(或虚拟)机器生产线,可能将负载分配到任意数量的机器。有关具体使用和安装的更多细节,请参阅示例部分。

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

<?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

<?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支持的特性

高可用
启动两个job server,他们是独立的服务进程,有各自的内存队列。当一个job server进程出现故障,另一个job server可以正常调度。(worker api与client api可以完成job server故障的切换)。在任何时候我们可以关闭某个worker,即使那个worker正在处理工作任务(Gearman不会让正在被执行的job丢失的,由于worker在工作时与Job server是长连接,所以一旦worker发生异常,Job server能够迅速感知并重新派发这个异常worker刚才正在执行的工作)

负载均衡
job server并不主动分派工作任务,而是由worker从空闲状态唤醒之后到job server主动抓取工作任务。

可扩展
松耦合的接口和无状态的job,只需要启动一个worker,注册到Job server集群即可。新加入的worker不会对现有系统有任何的影响。

分布式
gearman是分布式的任务分发框架,worker与job server,client与job server通信基于tcp的socket连接。

队列机制
gearman内置内存队列,默认情况队列最大容量为300W,可以配置最大支持2^32-1,即4 294 967 295。

高性能
作为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的高可用。

管理工具

应用场景
结合linux crontab,php脚本负责产生job,将任务分发到多台服务器周期性的并发执行。可以取代目前我们比较多的crontab的工作任务。
邮件短信发送
异步log
跨语言相互调用(对于密集型计算的需求,可以用C实现,PHP直接调用)
其他耗时脚本

安装(unbuntu)

下载编译安装

$>wget https://launchpadlibrarian.net/165674261/gearmand-1.1.12.tar.gz
安装依赖包
$>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
$>/configure --prefix=/home/phpboy/Server/gearman
$>make & make install

启动
a)默认启动
$>./gearman -d

b)支持memcached准持久化
$>./gearmand -d -q libmemcached --libmemcached-servers=127.0.0.1:11211

安装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
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工作在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也有基于行文本协议的通信。

请求的报文体


响应的报文体


后台工作任务Background job


一般工作任务Non-background job


二进制包
请求报文与响应报文是由二进制包封装。一个二进制包由头header和可选的数据部分data组成。

header的组成

1.报文类别,请求报文或者响应报文,4个字节
“REQ” 请求报文
“RES” 响应报文

2.包类型,高(大)字节序(网络字节序),4个字节可能的类型有:
类型值  名称    报文类型 发送者   
1 CAN_DO REQ    Worker    
2 CANT_DO REQ    Worker    
3 RESET_ABILITIES     REQ    Worker    
4 PRE_SLEEP           REQ    Worker    
5 (unused)            -      -   
6 NOOP                RES    Worker    
7 SUBMIT_JOB          REQ    Client    
8 JOB_CREATED         RES    Client    
9 GRAB_JOB            REQ    Worker    
10 NO_JOB              RES    Worker    
11 JOB_ASSIGN          RES    Worker    
12 WORK_STATUS         REQ    Worker    
13 WORK_COMPLETE REQ    Worker   
14 WORK_FAIL           REQ    Worker  
15 GET_STATUS          REQ    Client  
16 ECHO_REQ            REQ    Client/Worker  
17 ECHO_RES            RES    Client/Worker  
18 SUBMIT_JOB_BG       REQ    Client
19 ERROR               RES    Client/Worker  
20 STATUS_RES          RES    Client  
21 SUBMIT_JOB_HIGH     REQ    Client  
22 SET_CLIENT_ID       REQ    Worker  
23 CAN_DO_TIMEOUT REQ    Worker  
24 ALL_YOURS           REQ    Worker  
25 WORK_EXCEPTION      REQ    Worker  
26 OPTION_REQ          REQ    Client/Worker  
27 OPTION_RES          RES    Client/Worker  
28 WORK_DATA           REQ    Worker    
29 WORK_WARNING        REQ    Worker   
30 GRAB_JOB_UNIQ       REQ    Worker  
31 JOB_ASSIGN_UNIQ     RES    Worker  
32 SUBMIT_JOB_HIGH_BG  REQ    Client  
33 SUBMIT_JOB_LOW      REQ    Client  
34 SUBMIT_JOB_LOW_BG   REQ    Client  
35 SUBMIT_JOB_SCHED    REQ    Client  
36 SUBMIT_JOB_EPOCH    REQ    Client

可选数据部分长度,高(大)字节序(网络字节序),4个字节,可表示的值为4294967295。

数据部分,数据部分的各个部分为null字符分隔。

具体各包类型的说明
client和worker可发送请求报文
ECHO_REQ

当job server收到此包类型的请求报文时,就简单的产生一个包类型为ECHO_RES,同时将请求报文的数据部分作为响应报文的数据部分的报文。主要用于测试或者调试。

如:
Client -> Job Server  00 52 45 51 0REQ  报文类型  00 00 00 a0 16 (Packet type: ECHO_ERQ)    00 00 00 04 4 (Packet length)  74 65 73 74 test   (Workload)
ECHO_RESclient和worker可接收响应报文
当job server响应ECHO_REQ报文时发送的包类型为ECHO_RES的响应报文

如:
Job Server -> Client  00 52 45 53 0RES  报文类型  00 00 00 a1 17 (Packet type: ECHO_ERS)  00 00 00 04 4 (Packet length)  74 65 73 74 test   (Workload)

当job server发生错误时,需要通知client或者workerERROR
client发送的请求报文:(仅能由client发送的请求报文)
SUBMIT_JOB, SUBMIT_JOB_BG,SUBMIT_JOB_HIGH, SUBMIT_JOB_HIGH_BG,SUBMIT_JOB_LOW, SUBMIT_JOB_LOW_BG

当client有一个工作任务需要运行,就会提交相应的请求报文,job server响应包类型为JOB_CREATED数据部分为job handle的响应报文。SUBMIT_JOB为普通的工作任务,client得到状态更新及通知任务已经完成的响应;SUBMIT_JOB_BG为异步的工作任务,client不关心任务的完成情况;SUBMIT_JOB_HIGH为高优先级的工作任务,SUBMIT_JOB_HIGH_BG为高优先级的异步任务;SUBMIT_JOB_LOW为低优先级的工作任务,SUBMIT_JOB_LOW_BG为低优先级的异步任务。

如:
1 2 3 4 5 6 7 8 9 10 11 12 13
Client -> Job Server  00 52 45 51 0REQ        (报文类型)  00 00 00 07 7 (Packet type: SUBMIT_JOB)  00 00 00 0d 13 (Packet length)  72 65 76 65 72 73 65 00 reverse0 (Function)  00                          (Unique ID)  74 65 73 74 test (Workload)

SUBMIT_JOB_SCHED
和SUBMIT_JOB_BG类似,此类型的工作任务不会立即执行,而在设置的某个时间运行。

如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Client -> Job Server  00 52 45 51 0REQ        (报文类型)  00 00 00 23 35 (Packet type: SUBMIT_JOB_SCHED)  00 00 00 0d 13 (Packet length)  72 65 76 65 72 73 65 00 reverse0 (Function)  00                        (Unique ID)  01                        (minute 0-59)  01                         (hour 0-23)  01                        (day of month 1-31)  01                         (day of month 1-12)  01                         (day of week  0-6)  74 65 73 74 test (Workload)

SUBMIT_JOB_EPOCH
和SUBMIT_JOB_SCHED作用一样,只是将设置的时间定为了uinx时间戳GET_STATUS获取某个工作任务执行的状态信息

OPTION_REQ
设置client与job server连接的选项

client获取的响应报文:
JOB_CREATED响应包类型为SUBMIT_JOB*的请求报文,数据部分为job handle

WORK_DATA, WORK_WARNING, WORK_STATUS, WORK_COMPLETE,WORK_FAIL, WORK_EXCEPTION

对于后台运行的工作任务,任务执行信息可以通过包类型为上面的值来查看。

STATUS_RES
响应包类型为GET_STATUS的请求报文,通常用来查看一个后台工作任务是否已经完成,以及完成的百分比。

OPTION_RES
响应包类型为OPTION_REQ的请求报文

worker发送的请求报文:

CAN_DO
通知job server可以执行给定的function name的任务,此worker将会放到一个链表,当job server收到一个function name的工作任务时,worker为被唤醒。

CAN_DO_TIMEOUT
和CAN_DO类似,只是针对给定的function_name的任务设置了一个超时时间。

CANT_DO
worker通知job server已经不能执行给定的function name的任务

RESET_ABILITIES
worker通知job server不能执行任何function name的任务

PRE_SLEEP
worker通知job server它将进入sleep阶段,而之后此worker会被包类型为NOOP的响应报文唤醒。

GRAB_JOB
worker向job server抓取工作任务,job server将会响应NO_JOB或者JOB_ASSIG

NGRAB_JOB_UNIQ
和GRAB_JOB类似,但是job server在有工作任务时将会响应JOB_ASSIGN_UNIQ

WORK_DATA
worker请求报文的数据部分更新client

WORK_WARNING
worker请求报文代表一个warning,它应该被对待为一个WARNING

WORK_STATU
Sworker更新某个job handle的工作状态,job server应该储存这些信息,以便响应之后client的GET_STATUS请求

WORK_COMPLETE
通知job server及所有连接的client,数据部分为返回给client的数据

WORK_FAIL
通知job server及所有连接的client,工作任务执行失败

WORK_EXCEPTION
通知job server及所有连接的client,工作任务执行失败并给出相应的异常

SET_CLIENT_ID
设置worker ID,从而job server的控制台及报告命令可以标识各个worker,数据部分为worker实例的标识

ALL_YOURS
暂未实现

worker获取的响应报文:

NOOP
job server唤醒sleep的worker,以便可以开始抓取工作任务

NO_JOB
job server响应GRAB_JOB的请求,通知worker没有等待执行的工作任务

JOB_ASSIGN
job server响应GRAB_JOB的请求,通知worker有需要执行的工作任务

JOB_ASSIGN_UNIQ
job server响应GRAB_JOB_UNIQ的请求,和JOB_ASSIGN一样,只是为client传递了一个唯一标识

基于上述的协议描述一个完整的例子

worker注册可以执行的工作任务

Worker -> Job Server

1 2 3 4 5 6 7
00 52 45 51 0REQ (Magic)  00 00 00 01 1 (Packet type: CAN_DO)  00 00 00 07 7 (Packet length)  72 65 76 65 72 73 65 reverse (Function)
worker检测或者抓取工作任务

1 2 3 4 5 6 7
Worker -> Job Server  00 52 45 51 0REQ (Magic)  00 00 00 09 9 (Packet type: GRAB_JOB)  00 00 00 00 0 (Packet length)
job server响应worker的抓取工作(没有工作任务)

1 2 3 4 5
00 52 45 53 0RES (Magic)  00 00 00 0a 10 (Packet type: NO_JOB)  00 00 00 00 0 (Packet length)
worker通知job server开始sleep

1 2 3 4 5
00 52 45 51 0REQ (Magic)  00 00 00 04 4 (Packet type: PRE_SLEEP)  00 00 00 00 0 (Packet length)
client提交工作任务

1 2 3 4 5 6 7 8 9 10 11 12 13
Client -> Job Server  00 52 45 51 0REQ        (Magic)  00 00 00 07 7 (Packet type: SUBMIT_JOB)  00 00 00 0d 13 (Packet length)  72 65 76 65 72 73 65 00 reverse0 (Function)  00                         � (Unique ID)  74 65 73 74 test (Workload)
job server响应client的SUBMIT_JOB请求,返回job handle

1 2 3 4 5 6 7
00 52 45 53 0RES (Magic)  00 00 00 08 8 (Packet type: JOB_CREATED)  00 00 00 07 7 (Packet length)  48 3a 6c 61 70 3a 31 H:lap:1 (Job handle)
job server唤醒worker

1 2 3 4 5 6 7
Job Server -> Worker  00 52 45 53 0RES (Magic)  00 00 00 06 6 (Packet type: NOOP)  00 00 00 00 0 (Packet length)
worker的抓取工作任务

Worker -> Job Server
 
00 52 45 51 \0REQ (Magic)
 
00 00 00 09 9 (Packet type: GRAB_JOB)
 
00 00 00 00 0 (Packet length)
job server分配工作任务给worker

Job Server -> Worker
 
00 52 45 53 \0RES (Magic)
 
00 00 00 0b 11 (Packet type: JOB_ASSIGN)
 
00 00 00 14 20 (Packet length)
 
48 3a 6c 61 70 3a 31 00 H:lap:1\0 (Job handle)
 
72 65 76 65 72 73 65 00 reverse\0 (Function)
 
74 65 73 74 test (Workload)
worker完成工作任务通知job server

00 52 45 51 \0REQ (Magic)
 
00 00 00 0d 13 (Packet type: WORK_COMPLETE)
 
00 00 00 0c 12 (Packet length)
 
48 3a 6c 61 70 3a 31 00 H:lap:1\0 (Job handle)
 
74 73 65 74 tset (Response)

job server通知client完成了工作任务

Job Server -> Client

00 52 45 53 \0RES (Magic)
 
00 00 00 0d 13 (Packet type: WORK_COMPLETE)
 
00 00 00 0c 12 (Packet length)
 
48 3a 6c 61 70 3a 31 00 H:lap:1\0 (Job handle)
 
74 73 65 74 tset (Response)
每个client与job server是全双工通信,在一个socket可以完成多个工作任务的投递,但是收到任务的执行结果的顺序可能与投递的顺序不一致。

详见:http://gearman.org/protocol/

Worker的工作流程

Worker通过CAN_DO消息,注册到Job server上。

随后发起GRAB_JOB,主动要求分派任务。

Job server如果没有job可分配,就返回NO_JOB。

Worker收到NO_JOB后,进入空闲状态,并给Job server返回PRE_SLEEP消息,告诉Job server:”如果有工作来的话,用NOOP请求我先。”

Job server收到worker的PRE_SLEEP消息后,明白了发送这条消息的worker已经进入了空闲态。

这时如果有job提交上来,Job server会给worker先发一个NOOP消息。

Worker收到NOOP消息后,发送GRAB_JOB向Job server请求任务。

Job server把工作派发给worker。

Worker干活,完事后返回WORK_COMPLETE给Job server。


最新版本:1.1
支持作业的取消,扩展了 keep-alive 支持;修复了 log_fn 的 bug,增加了 --coredump 参数,移除 enum 结果类型等。

官方主页:http://gearman.org/index.php
该文章最后由 阿炯 于 2024-11-15 10:54:04 更新,目前是第 2 版。