代码之家  ›  专栏  ›  技术社区  ›  Gabe Spradlin

Gearman PHP扩展:死作业服务器=所有工作人员响应缓慢

  •  2
  • Gabe Spradlin  · 技术社区  · 11 年前

    我从这个问题开始: Gearman: 3 seconds between client request and worker receive. Is this normal?

    环境:

    • Ubuntu 12.04桌面
    • 第5.3.10页
    • Gearman(带有PHP扩展1.1.1的libgearman 1.1.5)
    • 局域网上的多个服务器

    我无法让员工的响应时间小于3秒,我也不知道为什么。我把它缩小到我构建的一个包装类。然后,我将它进一步缩小到类中的一个特定方法。长话短说,真正的问题似乎在于PHP扩展中GearmanWorker的addServer方法。

    我的包装类试图连接到3个Gearman作业服务器。实际上只有2台在运行。当我试图连接到所有3个时,我会收到第3个无法连接的警告。我还得到了3秒的工作响应时间。当我删除添加服务器的尝试时,即当前关闭的作业服务器,那么工作响应时间约为0.003秒。

    现在你可能会问,为什么不从你要连接的服务器列表中删除下一个服务器呢?好吧,首先它不会总是向下。第二,当其中一台当前已启动或5分钟前已启动的服务器不再运行时,会发生什么?现在所有的作业都至少需要3秒。现在我想可能有一种方法可以将超时时间配置为1秒,但更好的解决方案IMO是,有一种方式可以将死服务器从工作人员试图获取作业的服务器列表中删除。

    在我的研究中,有一种addServer方法。还有一个addFunction方法。然后是一个注销方法,用于从给定工作者的列表中删除工作者功能。但是,我没有看到removeServer方法。

    那么,有没有办法剔除GearmanWorker中的作业服务器列表,或者我需要杀死对象,重新实例化它,然后重新连接到新的、剔除的可用作业服务器列表?杀死并重新启动GearmanWorker似乎远非理想。

    扫描(并连接)所有活动作业服务器的最佳方法是什么,同时避免作业服务器失效所固有的超时?

    谢谢

    1 回复  |  直到 7 年前
        1
  •  1
  •   Gabe Spradlin    11 年前

    所以最终看来,我并不是唯一一个有这个问题的人。Gearman的谷歌小组中也没有人能找到解决方案。因此,最终我编写了自己的代码(从Gearman Monitor中提取部分),以确定哪些作业服务器已经启动并运行,哪些没有。

    try {
                $cxn = @fsockopen($ip, $gHosts->ports[$host], $errCode, $errMsg, $timeout);
    
                /* Using the new \Net_Gearman_Manager on a dead job server kept leading to
                 *  fatal error which was uncaught. Thus crashing the script and leading
                 *  no update of the server status
                */
                //$gearmanManager = new \Net_Gearman_Manager($ip . ':' . $gHosts->ports[$host], 1);
    
                if ($cxn === FALSE) {
                    write_log($fLog, 'Connection FAILED');
                    $output[$host] = FAILURE;
                } else {
                    write_log($fLog, 'Connection Succeeded');
                    $output[$host] = SUCCESS;
                }
            } catch (Net_Gearman_Exception $e) {
                write_log($fLog, $e->getMessage());
                $output[$host] = FAILURE;
            } catch (Exception $e) {
                write_log($fLog, $e->getMessage());
                $output[$host] = FAILURE;
            } // if (@$wrkr->addServer($ip, $gHosts->ports[$host]))
    

    $gHosts类是一个配置类,它保存了我的每个潜在Gearman作业服务器的IP和端口。我在$gHosts中遍历每个潜在的作业服务器并对其进行测试。

    然后,我将输出写入memcache和一个文本文件。在我开始真正尝试加载机器之前,内存缓存本身工作得很好。然后memcache连接将重复失败。现在我使用文本文件作为备份,问题已经消失了。

    我将最后一次连接到每个Gearman作业服务器的尝试存储在一个数组中,其中键是服务器的名称,值是最后一次尝试的时间戳。如果尝试成功,则时间戳为正。如果尝试失败,则时间戳为负数。时间戳使我能够确定数据是陈旧的还是新鲜的。

    然后,在使用Gearman的脚本中,我有一个围绕PHP扩展类的Client和Worker包装类。它们在我想要的时间范围内自动更新连接。这样,停止响应的Gearman作业服务器就会停止使用,脚本虽然可能在短时间内运行缓慢,但通常运行速度相当快。

    希望这能帮助到其他人。