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

时间:2017-09-07 18:23:34

标签: php mysql google-app-engine slim propel

我们的团队一直在开发这个RESTful API,使用Slim PHP作为路由器和Propel ORM与MySQL,使用此app.yaml config

将其部署为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网络应用程序使用,通过所有开发,我们一直收到奇怪的无模式服务器崩溃500s,更准确地说:

  

500服务器错误错误:服务器错误服务器遇到错误   并且无法完成您的请求。请在30秒后再试一次。

使用App Engine日志。

  

处理此请求的进程遇到问题,   导致它退出。这可能会导致使用新流程   对于您的申请的下一个请求。 (错误代码204)

在随机端点,否则在99%的情况下工作正常,我们当然不会因为这些随机崩溃而投入生产。

我们尝试了什么:

  1. 检查是否正在访问MySQL max_connections,因为我们每次请求都会打开并关闭一个连接。
  2. 为了测试F4_1G,我们将实例从F1升级,以解决我们可能内存不足的可能性。
  3. 使用dev_appserver.py在localhost中进行压力测试,(我们不会在此处遇到任何崩溃)
  4. 尝试抓住整个Slim App进行调试(它实际上从未捕获到异常,因此它让我们认为它与Google App Engine有关)
  5. 以下是正常请求流程的一些代码。

    app.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();
    

    router.php

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

    访问控制器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;
    
    }
    

2 个答案:

答案 0 :(得分:2)

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

在使用任务队列和基本缩放时,我们还在App Engine的标准版本上遇到了同样的问题。它看起来并不像你那样做但是如果是这样的话,我们发现的唯一解决方案是在queue.yaml中启用重试并设置“快速失败”'将任务添加到推送队列时的标头:

$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');

无论何时我们收到错误,我们都可以通过Memcache中的密钥{TASK_NAME}_1找到第一条消息,但我们永远找不到第二条{TASK_NAME}_2。就像你说的那样,没有异常被捕获,因为整个脚本都会死掉。

这种行为让我们相信,由于我们使用的是完整版本,因此谷歌实施Curl可能存在问题:

extension = php_curl.dll

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

希望以上解决方案之一适合您,如果您有机会,可以告诉我们PHP.ini文件中的内容吗?

答案 1 :(得分:1)

这是由threadsafe: yes引起的,请将其设置为no / false。