php - Google App Engine PHP55 随机服务器崩溃(500 次),错误代码为 204

标签 php mysql google-app-engine slim propel

我们的团队一直在开发这个 RESTful API,使用 Slim PHP 作为路由器,使用 MySQL Propel ORM,使用这个 app.yaml 配置将其部署为 Google App Engine 中的服务

service: api
runtime: php55
api_version: 1
threadsafe: yes

instance_class: F1
automatic_scaling:
  min_idle_instances: automatic
  max_idle_instances: automatic
  min_pending_latency: automatic
  max_pending_latency: automatic

skip_files:
- ^vendor/(.*/)+[Tt]ests/.*$
- ^\.(.*)

handlers:
- url: .*
script: app.php

由 Ember.js 网络应用程序使用,在所有开发过程中,我们一直收到奇怪的无模式服务器崩溃 500 次,更准确地说:

500 Server Error Error: Server Error The server encountered an error and could not complete your request. Please try again in 30 seconds.

使用 App Engine 日志。

A problem was encountered with the process that handled this request, causing it to exit. This is likely to cause a new process to be used for the next request to your application. (Error code 204)

在随机端点中,99% 的时间都可以正常工作,当然,我们不想在这些随机崩溃的情况下进入生产。

我们尝试过的:

  1. 检查是否达到了 MySQL max_connections,因为我们在每次请求时都会打开和关闭一个连接。
  2. 为了测试将我们的实例从 F1 升级到 F4_1G,以解决我们可能会耗尽内存的可能性。
  3. 使用 dev_appserver.py 在本地主机中进行压力测试(我们在这里没有遇到任何崩溃)
  4. try catch 整个 Slim 应用程序进行调试(它实际上从未捕获异常,因此我们认为它确实与 Google App Engine 有关)

这是正常请求流程的一些代码。

应用.php

/*
 * Create SLIM application
 */
$app = new \Slim\App([
    "settings"  => [
        "determineRouteBeforeAppMiddleware" => true,
    ]
]);

//Custom Authentication middleware
    $app->add(new \OAuth2Server\SlimAuthenticationMiddleware());

//CORS and Headers Middleware
    $app->add(function($request, $response, $next) {

        $response = $next($request, $response);

        $response = $response->withHeader("Access-Control-Allow-Origin", "*");
        $response = $response->withHeader("Access-Control-Allow-Headers", "Content-Type, authorization");
        $response = $response->withHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, OPTIONS");
        $response = $response->withHeader("content-type", "application/json; charset=utf8");

        return $response;

    });


    require_once("router.php");

    $app->run();

路由器.php

$app->get($apiVersionPath.'/visits/{id}','\Controllers\Visits:get')
    ->add(new \OAuth2Server\ValidateRequestUser(array("doctor", "nurse","superuser","admin")));

访问Controller GET/ID相关代码。

 /**
     * @param Request $request
     * @param Response $response
     * @param []$args
     * @return Response
     */
    public function get($request, $response, $args) {

        $id = $request->getAttribute("route")->getArgument("id");

        $serializer = new Serializer();

        if(!is_numeric($id) || $id == 0){
                    throw new InvalidArgumentException("Invalid Argument");
        }

         $visit = \VisitQuery::create()
                  ->useUserQuery()
                   ->filterByClientId($request->getAttribute("user")->getClientId())
                  ->endUse();

         $visit = $visit->findPk($id);

         if(!isset($visit) || !($visit instanceof \Visit)){
                    throw new EntityNotFoundException("Visit not found");
         }

        $resource = $visit->toResource(false);

        $serializer->addResource($resource);

        $body = $response->getBody();
        $body->write($serializer->serialize());
        return $response;

}

最佳答案

我们在 PHP Flex 引擎上运行 API 服务,并在使用自动缩放时注意到类似的问题。要修复它,我们必须提升实例类(尝试转到 F2)并通过将 min_idle_instances 设置为 2 始终至少运行两个实例。

在使用任务队列和基本扩展时,我们在标准版 App Engine 上也遇到了同样的问题。看起来您还没有这样做,但如果是这样,我们找到的唯一解决方案是在 queue.yaml 中启用重试并在将任务添加到推送队列时设置“快速失败” header :

$pushTask = new PushTask($handler,
  array('message_data' => json_encode($message)),
  array('header'=> 'X-AppEngine-FailFast:true'));

否则,任务组将因 204 错误而失败。

关于您的问题,我感兴趣的一件事是您似乎正在尝试发出 HTTP 请求。在我们所有的测试中,我们能够重现错误的少数方法之一是将数百个任务放入队列中并让每个任务运行以下代码:

$memCache = new Memcache;
$memCache->set($_SERVER['HTTP_X_APPENGINE_TASKNAME'] . '_1', 'Test 1');
ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, 'hi');
curl_setopt($ch, CURLOPT_URL, 'https://www.google.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
set($_SERVER['HTTP_X_APPENGINE_TASKNAME'] . '_' . $index, $message);
$response = curl_exec($ch);
$memCache->set($_SERVER['HTTP_X_APPENGINE_TASKNAME'] . '_2', 'Test 2');

每当我们遇到错误时,我们都能通过它的键 {TASK_NAME}_1 在 Memcache 中找到第一条消息,但我们永远找不到第二条条目 {TASK_NAME}_2。就像你说的,没有异常被捕获,因为整个脚本都死了。

这种行为让我们相信 Google 的 Curl 实现可能存在问题,因为我们使用的是完整版本:

extension = php_curl.dll

但我们没有确定的答案。我们唯一的解决方案是增加我们的实例计数并依靠重试来完成我们的代码。

希望上述解决方案之一对您有用,如果有机会,您能向我们展示一下您的 PHP.ini 文件中的内容吗?

关于php - Google App Engine PHP55 随机服务器崩溃(500 次),错误代码为 204,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46102850/

相关文章:

php - 为什么 count on multiple file input field 在表单输出 1?

python - 在本地 GAE 服务器上运行 flask 时出错 [Errno 13]

google-app-engine - 从任务队列运行 appengine 备份

google-app-engine - 在谷歌应用引擎中部署应用

php - 如何在 Laravel Voyager 中创建自定义 Controller

php - 如何修复 “Object of class stdClass could not be converted to string” : Laravel 5.4

php - 在 SQL 和 PHP 中处理用户输入字符串的正确方法?

mysql - 在 MYSQL 中执行 LEFT OUTER JOIN 时插入零而不是 NULL

php - 编辑和删除按钮在php,ajax中添加到服务器端数据表

php - 什么 PHP/Shell 框架可用于访问 HTTP-POST/-GET 表单(curl 除外)?