问题描述
公司boass项目测试环境与生产环境接口请求偶尔返回502错误或者缺失跨域相关的响应头内容,导致前端报跨域错误。
问题分析
首先从测试环境服务器排查
测试环境使用的是宝塔的集成环境,项目运行环境是lnmp。为了找到问题的原因,打算从日志着手,首先是去查看nginx的日志,通过 find / -name nginx.conf
命令找到nginx的配置文件所在位置 /www/server/nginx/conf/nginx.conf
,然后打开文件找到错误日志存放在 /www/wwwlogs
目录下,使用tail
命令打开相关域名的错误日志文件,发现如下错误
2021/09/01 16:28:16 [error] 26418#0: *1041081 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 119.23.123.176, server: xx.com, request: "GET /api/v1/user/user_info HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-71.sock:", host: "xx.com", referrer: "http://192.168.1.47:8080/"
通过搜索网上相关资料,这是关于连接被重置的问题,而且导致的原因很可能是php-fpm,由于php-fpm不能正常返回内容,nginx就报错。
基于这个思路,接着去查看php-fpm的运行日志,使用 find -name php-fpm.log
命令找到php-fpm日志文件位置是 /www/server/php/71/var/log/php-fpm.log
,继续使用tail
命令获取日志内容,发现很多如下警告内容
WARNING: [pool www] child 1775 exited on signal 7 (SIGBUS) after 3996.388230 seconds from start
接着网上搜索相关的错误,找到一些关于thinkphp框架的日志功能开启,导致php-fpm进程被动关闭的文章,再结合自己在本地调试接口时,经常会报没有对runtime/build_route
文件没有写入权限,但明明给了写的权限了。
查看thinkphp5.1框架的官方文档,去了解什么情况下会去写入这个文件。在注解路由功能的页面http://static.kancloud.cn/manual/thinkphp5_1/469333
找到了一句话, 该方式定义的路由在调试模式下面实时生效,部署模式则需要使用 optimize:route 指令生成路由规则文件。 也就是说开启注解路由功能且在调试模式下,每次请求都会重新生成路由文件,也就是会写入上述的 runtime/build_route
文件,结合公司项目中有些接口使用了注解路由,而且开发环境和测试环境是在调试模式下运行,如果有多个接口同时访问,就会造成写入阻塞而报没有权限写入错误,从而导致php-fpm子进程异常退出,最终导致前端访问偶尔出现CORS跨域错误。
生产环境服务器排查
惯性地按照测试环境排查思路去生产环境排查,查看php-fpm的运行日志,确实发现了与测试环境相同的错误日志
WARNING: [pool www] child 1775 exited on signal 7 (SIGBUS) after 3996.388230 seconds from start
但问题是生产环境并没有开启日志,那就疑惑了,继续看php-fpm的日志,发现如下警告
WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning [closed]
根据警告信息以及网上相关的文章,这种情况下需要增加pm.start_servers 或者pm.min/max_spare_servers
参数的值
解决办法
测试环境
关掉thinkphp框架调试模式,或者不使用注解路由,或者允许这个问题存在,毕竟测试环境受影响较小。
生产环境
修改/usr/local/php/etc/php-fpm.d/www.conf
文件,根据配置文件的相关注释
; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.start_servers = 40
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.min_spare_servers = 20
; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 60
将 pm.start_servers,pm.min_spare_servers,pm.max_spare_servers
参数相应的增加n倍。
最后重启 php-fpm
。