背景
最近几天发现服务器经常在某个时间段cpu突然过载 老板发了几次消息让排查一下问题原因。这台服务器主要是作为api调用的服务器,所以一旦出现问题就可能会影响客户。
服务器相关
阿里云服务器 24核48GB 公网带宽为5Mbps; 一台负载均衡的服务器 16核 32GB
服务器上的项目为php Laravel和golang项目作为api接口
排查思路
1.看下是网络攻击还是瞬时网络请求过多导致的(大概率为网络请求过多)
2.看下cpu过载期间请求最多的接口是哪几个,该接口是否有报错和慢查询。
3.查看laravel的项目日志 看下时候有报错
初步诊断
1.查看阿里云记录的日志发现cpu过载期间的请求数量是普通情况下的4到5倍,且查看日志只有数据库超时连接的错误(这个应该是请求数量过多 数据库连接数太多导致的) 查看过载情况下laravel接口15分钟段内请求数量为125766和闲时的15分钟内为49192
2.cpu过载时使用top命令查看发现占用cpu最多的进程是php-fpm
3.查看php-fpm的慢日志分析;慢日志存放目录为(www/server/php/73/var/log/slow.log)
tail -f slow.log #监控当前的慢日志
4.监控慢日志发现有慢日志如下内容
点击查看代码
[24-Jul-2025 17:30:52] [pool www] pid 28728
script_filename = /www/wwwroot/name.jiaoguanyi.cn/public/index.php
[0x00007fdc2861e570] hasChildren() /www/wwwroot/name.jiaoguanyi.cn/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php:78
[0x00007fdc2861e500] hasChildren() unknown:0
[0x00007fdc2861e4b0] next() unknown:0
[0x00007fdc2861e460] next() unknown:0
[0x00007fdc2861e410] next() unknown:0
[0x00007ffe21de3cf0] ???() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php:109
[0x00007fdc2861e370] gc() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:133
[0x00007fdc2861e2f0] collectGarbage() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:60
[0x00007fdc2861e220] handle() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
[0x00007fdc2861e150] Illuminate\Pipeline\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
[0x00007fdc2861e090] Illuminate\Routing\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:66
[0x00007fdc2861df60] handle() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
[0x00007fdc2861de90] Illuminate\Pipeline\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
[0x00007fdc2861ddd0] Illuminate\Routing\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/fideloper/proxy/src/TrustProxies.php:57
[0x00007fdc2861dd30] handle() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
[0x00007fdc2861dc60] Illuminate\Pipeline\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
[0x00007fdc2861dba0] Illuminate\Routing\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:31
[0x00007fdc2861daf0] handle() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151
[0x00007fdc2861da20] Illuminate\Pipeline\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
[0x00007fdc2861d960] Illuminate\Routing\{closure}() /www/wwwroot/name.jiaoguanyi.cn/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:31
分析了下这个慢日志的原因是 session文件过多 于是我手动查看了下目前session文件一共有多少个
ls -l /www/wwwroot/name.jiaoguanyi.cn/storage/framework/sessions | wc -l
显示有513065个 50多万个!session文件过多会导致GC执行缓慢
cpu过载的关键原因
通过慢日志查询到了当前项目session过多的问题。那么为什么session文件过多会导致cpu过载呢?这里就不得不提到laravel项目的session垃圾回收机制。
垃圾回收机制(以文件驱动为例)
- 扫描 Session 存储目录(默认在 storage/framework/sessions/)
- 检查每个 Session 文件的上次修改时间(mtime)。
- 如果当前时间减去修改时间大于
SESSION_LIFETIME
(过期),则删除该文件。
为什么文件驱动会导致性能问题?
laravel使用session来存储用户的状态信息(如用户登录状态)当你的环境配置为SESSION_DRIVER=file时候会在/storage/framework/sessions的目录下生成对应的文件来存储,而且laravel的垃圾回收会扫描session存储目录、检查每个session文件的上次修改时间(mtime)、 如果当前时间减去修改时间大于 SESSION_LIFETIME(过期),则删除该文件。
- I/O 密集:当 Session 文件数量很大时,扫描整个目录并检查每个文件的修改时间会消耗大量 I/O 资源。
- 递归扫描:如果使用 Symfony Finder 组件(如你日志中显示的),它可能会递归扫描目录(尽管你的 Session 文件应该都在同一级目录),但每个文件的系统调用都很昂贵。
解决session文件过的的问题
思路:
1.把当前旧的session文件清理掉
2.改用高效的session驱动 如redis
3.调整session GC的概率
清理旧的session文件
点击查看代码
# 手动清理过期 Session
cd /www/wwwroot/name.jiaoguanyi.cn/storage/framework/sessions/
find . -type f -mmin +120 -delete # 删除2小时前的文件
更改session驱动为redis
在.env文件中修改(前提是该项目已经支持redis)
SESSION_DRIVER=redis
调整session GC的概率
修改 config/session.php
'lottery' => [1, 10000], // 从 1/100 改为 1/10000 触发概率