应用框架Gearman

gearman,学习好莱坞大片的翻译方式暂且翻译成“齿轮侠”。是一个“标准的应用程序框架”,它提供了一些列的语言接口,实现了简单方便的跨主机调用、任务分配和伪队列服务。说了这么多,其实我个人的理解就是提供了一套trigger接口,允许一台主机通过业务码执行另一台主机上定义好的任务,而gearman则负责一系列的任务分配和管理。

不同于习惯上的server/client端的称呼,Gearman的角色是server/worker/client。Server正式gearman本身,worker故名思义就是“干活的机器“,client则是发送任务的机器。——貌似Agent/worker/boss更加形象 🙂

还是用Ubuntu1204来做演示,似乎该到了升级的时候。既然是“远程”和“跨主机”的,应该是需要2台以上的主机,但演示而已,这里只用一台机器。

同步异步

首先,还是那老一套

apt-get update && apt-get upgrade

安装gearman server

apt-get install gearman
service gearman-job-server start

OK了,真的就是这么简单!

worker/client的安装。以PHP做例子吧。需要注意的是默认的最新php gearman扩展需要更高版本的lib库,Ubuntu1204apt安装的lib库最高只能支持到1.03版本的PHP扩展。更高版本的Linux可以直接尝试 pecl install gearman命令看是否报错。

apt-get install libgearman6 libgearman-dev php5-dev #安装lib库和依赖包
wget http://pecl.php.net/get/gearman-1.0.3.tgz #下载php扩展包
tar vzxf gearman-1.0.3.tgz
cd gearman-1.0.3/

phpize #生成配置
./configure #配置
make && make install #编译
echo "extension=gearman.so" > /etc/php5/conf.d/gearman.ini #php加载模块

apache2ctl restart #重起apache

冒烟测试一下

root@litrin-test:~# php -i | grep gearman
/etc/php5/cli/conf.d/gearman.ini,
gearman
gearman support => enabled
libgearman version => 0.27

搞定,进入代码部分!

写一个PHP的worker端程序

<?php
 $worker= new GearmanWorker();
 $worker->addServer("127.0.0.1", 4730); //连接本机
 $worker->addFunction("title", "title_function"); //注册“title”业务码,执行"title_function"程序
 while($worker->work()); //好一个死循环
function title_function($job)
 {

  $str = $job->workload(); //通过workload()获得入参
  sleep(2); //假装很忙
  return $str; //出参,必须是string类型!
 }
 ?>

写一个标准的同步client

<?php
 $client= new GearmanClient();
 $client->addServer("127.0.0.1", 4730);
 $handler = $client->do ("title", json_encode(range(0,100))); //do()方法是同步执行,业务码是“title”,入参必须为string
 print $handler;

执行worker端后,worker端会因为一个死循环的存在始终保持着,新开一个终端,执行client端。

root@litrin-test:~# php gc.php
 [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]

成功!

改client为异步。

 <?php
 $client= new GearmanClient();
 $client->addServer("127.0.0.1", 4730);
 $handler = $client->doBackground ("title", json_encode(range(0,100))); //简单粗暴的函数doBackground()
print $handler; //打印任务ID
echo '\n'
var_dump($client->jobStatus($handler)); 获取任务状态

返回同样是简单粗暴

root@litrin-test:~# php gc.php
 H:litrin-test:7
array(4) {
 [0] =>
 bool(true) //任务已加载
 [1] =>
 bool(true) //任务仍在执行中
 [2] =>
 int(0) // 可定义的完成比例,分子
 [3] =>
 int(0) //可定义的完成比例,分母
}

这里需要说明的是通过foBackground的方法,由于后台执行的缘故,返回一个任务ID之后,你将用于无法拿到返回值,对于这种方式,唯一的方法只能通过回调接口实现返回,其实有点坑爹!对于PHP这种缺乏线程控制的语言来说,如果用do同步操作,Client就必须等到worker完成任务才能返回,这个时间很多时候是不可控的。如果doBackground,想获得返回值要么再写个API把ID和result对应起来,要么就粗暴的用共享存储解决——都是很麻烦的实现。你说fork进程?看看业务忙的时候连接数和资源耗用吧。

友情奉送:Python部分

apt-get install  python-gearman

worker端

import gearman
class CustomGearmanWorker(gearman.GearmanWorker):
    def on_job_execute(self, current_job):
        print "Job started"
        return super(CustomGearmanWorker, self).on_job_execute(current_job)
def task_callback(gearman_worker, job):
    print job.data
    return job.data

new_worker = CustomGearmanWorker(['127.0.0.1:4730'])
new_worker.register_task("py_title", task_callback)
new_worker.work()

client端

from gearman import GearmanClient
import json

new_client = GearmanClient(['127.0.0.1:4730'])
#current_request = new_client.submit_job('py_title', json.dumps(range(100)), background=True)
current_request = new_client.submit_job('py_title', json.dumps(range(100)))
new_result = current_request.result
print new_result
推荐阅读:
如果你的眼尖的话,你会发现现在
一直关注我博客的人兴许会注意到
这一段时间,凡是提及容器技术的
话说在数据中心虚拟化的大潮中,

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据