You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TYPO3 11.5.11 PHP进程挂起 会话类报错故障排查

TYPO3站点PHP进程挂起故障原因及解决方案

故障根本原因

  • 核心故障点是静态路由解析环节的对外HTTP请求无超时配置导致进程阻塞:从php-fpm慢日志的调用栈可以明确看到,挂死的进程全部卡在curl_exec函数,对应TYPO3内核的StaticRouteResolver静态路由中间件逻辑。该逻辑会通过Guzzle HTTP客户端发起curl请求拉取静态路由配置的外部目标资源,但默认没有配置请求超时时间,一旦目标地址网络不通、服务无响应,PHP进程会一直阻塞等待curl返回,持续占用php-fpm工作进程。当所有php-fpm worker都被这类阻塞请求占满后,新的用户请求无法被处理,就会表现为站点完全挂死,重启PHP进程释放所有阻塞worker后服务就会临时恢复。
  • 日志里的两个session相关警告都是进程阻塞后的次生问题,不是故障根因,不需要优先排查:
    • session_regenerate_id报错是因为进程长期阻塞时,会话上下文被PHP异常回收,调用会话ID重置方法时没有处于活跃会话状态,才会抛出警告。
    • filemtime stat失败报错是因为会话垃圾回收逻辑遍历会话文件时,目标文件刚好被其他并发进程、系统定时清理任务删除,属于文件存储会话场景下的常见边缘警告,本身不会导致进程挂死。

报错详情

1. 后台会话重置警告

Core: Error handler (BE): PHP Warning: session_regenerate_id(): Cannot regenerate session id - session is not active in /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/install/Classes/Service/SessionService.php line 165

对应代码段:

/**
     * Generates a new session ID and sends it to the client.
     *
     * @return string|false the new session ID
     */

    private function renewSession()
    {
        // we do not have parallel ajax requests so we can safely remove the old session data
        session_regenerate_id(true);
        return session_id();
    }

2. 会话文件GC回收警告

Error handler (BE): PHP Warning: filemtime(): stat failed for /www/htdocs/wxxxxxxx/cmstypo3/typo3temp/var/session/5b746183ce7e94a328dc1c5bb6e5598574a6d5c1/hash_6e60e04342f6660702e7abff85ff99d9 in /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/install/Classes/Service/Session/FileSessionHandler.php line 210

对应代码段:

/**
     * Garbage collect session info. See @session_set_save_handler
     *
     * @param int $maxLifeTime The setting of session.gc_maxlifetime
     * @return bool
     */
    #[\ReturnTypeWillChange]
   
 public function gc($maxLifeTime)
    {
        $sessionSavePath = $this->getSessionSavePath();
        $files = glob($sessionSavePath . '/hash_*');
        if (!is_array($files)) {
            return true;
        }
        foreach ($files as $filename) {
            if (filemtime($filename) + $this->expirationTimeInMinutes * 60 < time()) {
                @unlink($filename);
            }
        }
        return true;
    }

3. php-fpm慢日志记录

[27-Jun-2022 19:02:20]  [pool wxxxxxxx] pid 3601
script_filename = /www/htdocs/wxxxxxxx/cmstypo3/index.php
[0x00007f6b0e2163f0] curl_exec() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php:44
[0x00007f6b0e216350] __invoke() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php:28
[0x00007f6b0e2162a0] GuzzleHttp\Handler\{closure}() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php:48
[0x00007f6b0e2161f0] GuzzleHttp\Handler\{closure}() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php:35
[0x00007f6b0e216110] __invoke() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Middleware.php:31
[0x00007f6b0e216060] GuzzleHttp\{closure}() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php:71
[0x00007f6b0e215fc0] __invoke() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Middleware.php:63
[0x00007f6b0e215f20] GuzzleHttp\{closure}() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/HandlerStack.php:75
[0x00007f6b0e215e90] __invoke() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Client.php:331
[0x00007f6b0e215d40] transfer() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Client.php:168
[0x00007f6b0e215c60] requestAsync() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/vendor/guzzlehttp/guzzle/src/Client.php:187
[0x00007f6b0e215bd0] request() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/core/Classes/Http/RequestFactory.php:55
[0x00007f6b0e215b30] request() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php:131
[0x00007f6b0e215a80] getFromUri() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php:186
[0x00007f6b0e215990] resolveByType() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php:72
[0x00007f6b0e215890] process() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php:172
[0x00007f6b0e2157f0] handle() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php:55
[0x00007f6b0e215760] process() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php:172
[0x00007f6b0e2156c0] handle() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php:94
[0x00007f6b0e2155c0] process() /www/htdocs/wxxxxxxx/cmstypo3/typo3_src-11.5.11/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php:172

解决方案

  • 排查静态路由配置:进入TYPO3后台站点管理模块,检查所有配置为「拉取外部URI内容」类型的静态路由,从服务器本地测试目标地址是否可以正常访问,删除失效的静态路由配置,修正地址填写错误的条目。
  • 给HTTP请求加上全局超时限制:在TYPO3的AdditionalConfiguration.php配置文件中加入如下配置,从根源避免curl请求无期限阻塞:
$GLOBALS['TYPO3_CONF_VARS']['HTTP']['timeout'] = 5;
$GLOBALS['TYPO3_CONF_VARS']['HTTP']['connect_timeout'] = 3;

以上配置表示连接超时3秒,总请求超时5秒,超过时限直接中断请求,不会长期占用PHP进程。

  • 优化php-fpm配置:在php-fpm对应站点池的配置中加入request_terminate_timeout = 30s,强制杀死执行超过30秒的PHP进程,避免个别异常请求长期占用worker资源。
  • 修复次生session警告(非必须,不影响核心故障解决):
    • 给session_regenerate_id调用加上会话状态判断,修改SessionService.php的renewSession方法,只有会话处于活跃状态时才执行ID重置:
    private function renewSession()
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            session_regenerate_id(true);
        }
        return session_id();
    }
    
    • 给FileSessionHandler.php的GC逻辑加上文件存在判断,调用filemtime前先校验文件是否存在,避免文件被并发删除后触发stat警告:
    foreach ($files as $filename) {
        if (file_exists($filename) && filemtime($filename) + $this->expirationTimeInMinutes * 60 < time()) {
            @unlink($filename);
        }
    }
    
    注意:直接修改核心源码的内容会在下次TYPO3版本升级时被覆盖,优先升级到11.5分支最新小版本解决(后续官方版本已经修复了这两个边缘警告),也可以通过XCLASS方式重写对应类做兼容。
  • 定期清理typo3temp/var/session目录下的过期会话文件,避免单目录下文件数量过多导致glob扫描、文件stat操作性能下降。

内容的提问来源于stack exchange,提问作者mikee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:45:30