Gearman具有多个服务器和php工作人员
我在多台服务器上运行gearman workers时遇到了一个问题,我似乎无法解决这个问题 当工作服务器脱机而不是取消工作进程时,会发生此问题,并导致所有其他工作进程出错和失败 仅1名客户和2名员工的示例- 客户:Gearman具有多个服务器和php工作人员,php,gearman,Php,Gearman,我在多台服务器上运行gearman workers时遇到了一个问题,我似乎无法解决这个问题 当工作服务器脱机而不是取消工作进程时,会发生此问题,并导致所有其他工作进程出错和失败 仅1名客户和2名员工的示例- 客户: $client = new GearmanClient (); $client->addServer ('192.168.1.200'); $client->addServer ('192.168.1.201'); $job = $client->do ('ge
$client = new GearmanClient ();
$client->addServer ('192.168.1.200');
$client->addServer ('192.168.1.201');
$job = $client->do ('generate_tile', serialize ($arrData));
工人:
$worker = new GearmanWorker ();
$worker->addServer ('192.168.1.200');
$worker->addServer ('192.168.1.201');
$worker->addFunction ('generate_tile', 'generate_tile');
while (1)
{
if (!$worker->work ())
{
switch ($worker->returnCode ())
{
default:
echo "Error: " . $worker->returnCode () . ': ' . $worker->error () . "\n";
break;
}
}
}
function generate_tile ($job) { ... }
工作代码正在两个独立的服务器上运行。当每台服务器都启动并运行时,两个工人都会按预期执行作业。当其中一个辅助进程被取消时,另一个辅助进程将按预期执行所有作业
但是,当具有已取消的辅助进程的服务器关闭并完全脱机时,对客户端脚本的请求将挂起,而剩余的辅助进程不会拾取任何作业
我从剩余的工作进程中获得以下一组错误:
Error: 46: gearman_con_wait:timeout reached
Error: 46: gearman_con_wait:timeout reached
Error: 4: gearman_con_flush:write:110
Error: 46: gearman_con_wait:timeout reached
Error: 4: gearman_con_flush:write:113
Error: 4: gearman_con_flush:write:113
Error: 4: gearman_con_flush:write:113
....
当我启动另一台服务器,而不是启动其上的工作进程时,剩余的工作进程立即进入生命并执行任何剩余的作业
我似乎很清楚,我需要在worker进程中使用一些代码来处理任何可能脱机的服务器,但是我不知道如何做到这一点
非常感谢,
Andy我们对多台gearman服务器的测试表明,如果列表中的最后一台服务器(在您的例子中为192.168.1.201)被取下,工作人员将停止执行您描述的方式。(此外,工人从最后一台服务器获取作业。只有在.201上没有作业时,他们才会在.200上处理作业)
这似乎是gearman服务器中链接列表的一个bug,据报道该bug已被修复多次,但对于gearman的所有可用版本,该bug仍然存在。抱歉,我知道这不是一个解决方案,但我们有相同的问题,没有找到解决方案。(如果有人能为这个问题提供有效的解决方案,我同意给予大量奖励)我使用这个类,它跟踪哪些作业在哪些服务器上工作。它还没有经过彻底的测试,只是现在写的。我粘贴了一个经过编辑的版本,所以可能有打字错误或类似的问题,但其他方面似乎可以解决这个问题
<?
class MyGearmanClient {
static $server = "server1,server2,server3";
static $server_array = false;
static $workingServers = false;
static $gmclient = false;
static $timeout = 5000;
static $defaultTimeout = 5000;
static function randomServer() {
return self::$server_array[rand(0, count(self::$server_array) -1)];
}
static function getServer($job = false) {
if (self::$server_array == false) {
self::$server_array = explode(",", self::$server);
self::$workingServers = array();
}
$serverList = array();
if ($job) {
if (array_key_exists($job, self::$workingServers)) {
foreach (self::$server_array as $server) {
if (array_key_exists($server, self::$workingServers[$job])) {
if (self::$workingServers[$job][$server]) {
$serverList[] = $server;
}
} else {
$serverList[] = $server;
}
}
if (count($serverList) == 0) {
# All servers have failed, need to insert all the servers again and retry.
$serverList = self::$workingServers[$job] = self::$server_array;
}
return $serverList[rand(0, count($serverList) - 1)];
} else {
return self::randomServer();
}
} else {
return self::randomServer();
}
}
static function serverWorked($server, $job) {
self::$workingServers[$job][$server] = $server;
}
static function serverFailed($server, $job) {
self::$workingServers[$job][$server] = false;
}
static function Connect($server = false, $job = false) {
if ($server) {
self::$server = self::getServer();
}
self::$gmclient= new GearmanClient();
self::$gmclient->setTimeout(self::$timeout);
# add the default job server
self::$gmclient->addServer($server = self::getServer($job));
return $server;
}
static function Destroy() {
self::$gmclient = false;
}
static function Client($name, $vars, $timeout = false) {
if (is_int($timeout)) {
self::$timeout = $timeout;
} else {
self::$timeout = self::$defaultTimeout;
}
do {
$server = self::Connect(false, $name);
$value = self::$gmclient->do($name, $vars);
$return_code = self::$gmclient->returnCode();
if (!$value) {
$error_message = self::$gmclient->error();
if ($return_code == 47) {
self::serverFailed($server, $name);
if (count(self::$server_array) > 1) {
// ADDED SINGLE SERVER LOOP AVOIDANCE // echo "Timeout on server $server, trying another server...\n";
continue;
} else {
return false;
}
}
echo "ERR: $error_message ($return_code)\n";
}
# printf("Worker has returned\n");
$short_value = substr($value, 0, 80);
switch ($return_code)
{
case GEARMAN_WORK_DATA:
echo "DATA: $short_value\n";
break;
case GEARMAN_SUCCESS:
self::serverWorked($server, $name);
break;
case GEARMAN_WORK_STATUS:
list($numerator, $denominator)= self::$gmclient->doStatus();
echo "Status: $numerator/$denominator\n";
break;
case GEARMAN_TIMEOUT:
// self::Connect();
// Fall through
default:
echo "ERR: $error_message " . self::$gmclient->error() . " ($return_code)\n";
break;
}
}
while($return_code != GEARMAN_SUCCESS);
$rv = unserialize($value);
return $rv["rv"];
}
}
# Example usage:
# $rv = MyGearmanClient::Client("Function", $args);
?>
进一步了解上面@Darhazer的评论。我们也发现了这一点,并解决了如下问题:-
// Gearman workers show a strong preference for servers at the end of a list so randomize the order
$worker = new GearmanWorker();
$s2 = explode(",", Configure::read('workers.servers'));
shuffle($s2);
$servers = implode(",", $s2);
$worker->addServers($servers);
我们随时运行6到10个Worker,在他们完成x个请求后使其过期。由于gearman客户端的“addServer”工作不正常,此代码可以随机选择一个jobserver,如果失败,请尝试下一个,这样您可以平衡负载
// job servers
$jobservers = array('192.168.1.1','192.168.1.2');
// prepare gearman client
$gmclient = new GearmanClient();
// shuffle job servers (deliver jobs equally by server)
shuffle($jobservers);
// add job servers
foreach($jobservers as $jobserver) {
// add random jobserver
$gmclient->addServer($jobserver);
// check server state if ok end foreach
if (@$gmclient->ping('ping')) break;
// if connections fails reset client
$gmclient = new GearmanClient();
}
解决方案测试和工作正常
$client = new GearmanClient();
if(!$client->addServer("11.11.65.73",4730))
$client->addServer("11.11.65.79",4730);
很有趣,谢谢。我已经更改了服务器的顺序,以便我关闭的工作服务器是第一台服务器,而不是最后一台服务器。尽管仍会生成一些错误,但工作服务器确实正确地处理作业。我建议解决这个问题的方法是在客户机服务器上运行一个worker,并将其设置为最后一个服务器。这样,如果任何工作服务器宕机,那么这不是问题,一切正常,因为它们都不是最后添加的服务器,但是如果工作服务器/客户机服务器宕机,那么客户机也会宕机,因此无法处理新作业。有人有到错误报告的链接吗?这是一段方便的代码,谢谢-我看到它随机返回一个服务器,然后构建一个工作服务器阵列,返回多个请求。对于worker脚本,您只需要添加一个服务器?而不是像我一直在做的那样将所有服务器添加到worker,因为您只将单个worker服务器添加到客户端?通常,我将所有worker添加到所有服务器。但我确实有一个工作者需要快速返回结果,为此我使用专用的“本地”(每个网络一个)服务器。这提醒了我,我必须纠正一个错误,如果你只指定一个服务器,它会导致无限重试循环-这对我来说只是个问题,因为如果我在1秒内没有得到答案,我会执行本地(读:“exec()”)处理。对于堆栈溢出,通常会感谢一些解释。