当客户端发送大负载时,Gearman变慢了

23

我在使用Gearman时遇到了问题,当我通过Gearman PHP扩展发送大型负载时,向工作进程传输任务速度非常慢。实际上,我们认为负载并不是很大(只有30MB)。目前所有内容(PHP、Gearman、node)都在本地运行,所以网络访问不是瓶颈。

这是PHP客户端的代码:

ini_set('memory_limit', '1G');

$client= new GearmanClient();
$client->addServer('127.0.0.1', '4730');

$schema = file_get_contents('schema.json');
$data = file_get_contents('data.json');

$gearmanData = [
    'schema' => $schema,
    'data' => $data
];

echo "Encoding in JSON the payload\n";

$gearmanDataString = json_encode($gearmanData, JSON_FORCE_OBJECT);

echo "Sending job to Gearman\n";

// This line takes long to execute...
$result = $client->doNormal("validateJsonSchema", $gearmanDataString);

echo "Job finished\n";

var_dump($result);

这是我的Node.js worker,最终将要做一些事情,但现在为空,以证明worker代码不是问题:

var gearmanode = require('gearmanode');

var worker = gearmanode.worker({host: '127.0.0.1' port: 4730});

worker.addFunction('validateJsonSchema', function (job) {
    console.log('I will do something');

    job.workComplete('Toasty!');
});

我在后台启动了我的工作进程,然后运行客户端,在执行$client->doNormal时(刚刚输出发送工作到Gearman),它会冻结30秒左右,最后通过PHP的var_dump输出string(7) "Toasty!"。所以它可以工作,但是处理时间太长。

此外,如果我减少负载的大小(data.json),那么处理时间就会更短,因此负载大小似乎很重要。

我尝试用相同的PHP代码编写了同样的工人程序,并得到了相同的结果:

$worker= new GearmanWorker();
$worker->addServer('127.0.0.1', '4730');
$worker->addFunction("validateJsonSchema", "validateJsonSchema");
while ($worker->work());

function validateJsonSchema($job)
{
  return 'ToastyPHP!';
}

更新

使用node.js客户端,与PHP实现几乎相同的功能,执行速度更快(约3.5秒)。我在PHP版本中做错了什么,或者我缺少一些配置使其更快?

我的node.js客户端:

var gearmanode = require('gearmanode');
var fs = require('fs');

var start = Date.now(); 

var client = gearmanode.client();

schema = fs.readFileSync('schema.json', 'utf8');
data = fs.readFileSync('data.json', 'utf8');

var submitData = JSON.stringify({ "data": data, "schema": schema });

// Runs much faster than PHP
var job = client.submitJob('validateJsonSchema', submitData, {background: false});

job.on('complete', function() {
    console.log('RESULT >>> ' + job.response);
    client.close();

    var end = Date.now(); 

    console.log(end-start + ' milliseconds'); // Always shows around 3500 milliseconds
});

你知道这是为什么吗?Gearman 能处理这种大小的有效载荷吗?在我看来,30MB 并不算太大。


2
你可能需要重新考虑你的有效载荷大小,因为Gearman会在内存中维护整个有效载荷。 - Paras
1
你尝试过将 $schema 和 $data 编码为 base64 或其他不是 JSON 字符串的格式吗?在我的测试服务器上,运行着 PHP 5.3.3 和 CentOS 6.6,似乎存在编码 JSON 的问题,就像你正在尝试的那样。这只是一个猜测,但也许将 JSON 封装在 JSON 中会给 Gearman 带来问题?使用 base64 对 $data 和 $schema 进行编码,我的测试运行良好(在 0.1 秒内)。 - xangxiong
@MaxiWheat 你尝试过流式传输的方法吗? - joewright
@MaxiWheat 你应该考虑使用异步处理。你可以调用doBackground方法而不是doNormal,这样如果你的进程需要时间,它不会影响前台。 - sandeep_kosta
Node是异步且非阻塞的,因此我认为这就是Node执行更快的原因,而不是php的同步特性。 - user1893702
显示剩余23条评论
1个回答

1

请检查一下这段代码是否适用于您,完成工作所需的时间非常短。

worker.php:

echo "Starting\n";
$gmworker = new GearmanWorker();

# Add default server (localhost).
$gmworker->addServer('127.0.0.1', '4730');
$gmworker->addFunction("jsonValid", "jsonValid");



print "Waiting for job...\n";
while ($gmworker->work()) {
    if ($gmworker->returnCode() != GEARMAN_SUCCESS) {
        echo "return_code: " . $gmworker->returnCode() . "\n";
        break;
    }
}

function jsonValid($job)
{
    return 'ToastyPHP!';
}

Client.php

ini_set('memory_limit', '1G');

$client = new GearmanClient();
$client->addServer('127.0.0.1', '4730');
$client->setCompleteCallback("complete");
$time = time();

echo "<pre>Sending job..." . "\n";


$schema = file_get_contents('AllSets.json');
$data = file_get_contents('AllSets.json');


$gearmanData = Array(
    'schema' => $schema,
    'data' => $data
);

$gearmanDataString = json_encode($gearmanData, JSON_FORCE_OBJECT);

$client->addTask("jsonValid", $gearmanDataString, null, 'Json');
$client->runTasks();

echo "Job finished\n";

$endtime = time();
print "Completed in " . ($endtime - $time) . ' seconds' . "\n";

function complete($task)
{
    print "Unique : " . $task->unique() . "\n";
    print "Data : " . $task->data() . "\n";
}

我已经使用了addTask和runTasks方法,而不是doNormal。发送JSON数据时,我使用了来自http://mtgjson.com/的AllSets.json文件,大小约为30Mb(总负载),作业在1秒钟内完成,并尝试一个大约200Mb的文件后,需要4秒钟。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接