Nginx+PHP(laravel) 环境 499 错误码排查过程小记

Nginx+PHP(laravel) 环境 499 错误码排查过程小记

大家好,又见面了,我是全栈君。

前言

某公安项目过程中,在内网服务器部署 WNMP 环境,运行 Laravel 框架代码,后查看日志发现某一时刻突然所有请求 499,并持续一段时间,遂排查原因。

过程

0x01

经搜索得知:
哪些情况下会使 Nginx 返回 HTTP CODE 499?

首先,这个问题百度谷歌应该都能搜到。
其次,我还是回答一下

499, client has closed connection

代表客户端主动断开了连接,一般是服务端处理时间太长了,客户端等不了就断开了
还有一种情况就是有人攻击,故意消耗服务端资源

在nginx源码中,499对应的定义是 “client has closed connection”。这很有可能是因为服务器端处理的时间过长,客户端“不耐烦”了。要解决此问题,就需要在程序上面做些优化了。

即:「客户端主动关闭连接」

但某一时间段内全部请求均为返回 499,这显然不是所有客户端主动意识上的「关闭」,可能是因为客户端等待超时,自动关闭连接;加上 499 的时间段内包含部分 502,让我不得不怀疑:

PHP 进程「死」了。

0x02

这里的死,不一定是进程结束,也有可能是僵尸,或是陷入死循环,一直在执行某个脚本……

若是逐个检查代码时间来不及(以先解决问题为重),遂排查:
Nginx+FastCGI 到底是谁影响超时时间

以及:
PHP-max_execution_time 与 fpm.request_terminate_timeout 介绍

0x03

经过上面的调整,大约一周后再次维护服务器。发现情况有所改善—— 499 错误已经由某一时段大量、集中出现变为偶尔发生,且只出现在某几个特定 URI 请求上。

我决定对这几个 URI 对应的接口控制器代码进行检查。由于系统开发时间紧张,代码质量并不高,怀疑是否是程序内有 BUG。

首先查看代码执行时间,约为 1900 ms 左右,简直太慢!经过仔细检查,发现几个严重问题:

  • 查出某表「全部结果」,再「遍历」结果集,查询每条记录「多个字段」的关联模型
  • 未执行 php artisan optimize
  • 未关闭 debug 模式
  • 未调整 log_level

其中,后几条或许无关紧要,但第一条绝对是致命的。

假设一种常见的模型关联场景:

某作者有多篇文章,每篇文章又有多条评论、赞。

由此,若是采用类似:

posts = posts::where('user_id', 1);
foreach(posts as post){
    likes = post->likes;
    comments = post->comments;
}

在 Laravel 框架内使用类似如上的方式查询,假设作者的文章数为 n,每篇文章关联的模型有 2 个(likes & comments),则执行此控制器,对于数据库的时间复杂度为:O(n*2+1),需要执行如此大量的 SQL 语句!这在后端设计中应该是需要完全避免的,理想情况的时间复杂度应该是 O(n),n 为常量,不受数据规模的影响。

于是修改代码,过程不再详叙,参见 Laravel 官方文档,或:
Laravel 学习笔记之模型关联预加载

经过修改,在 Chrome 开发者工具内查看请求 Timing,缩短为原来时间的一半,800ms 左右。

(但此值仍然不够理想,受到视图渲染、操作系统等原因的影响,后期继续优化,不属于本文讨论范围。)

后记

对于部分接口,请求一次需要执行几百条 SQL;那么,回到最开始的问题:

某次请求后,突然引发大量 499。究其根本原因,是否在于因代码的不严谨,引起的 MySQL 死锁呢?

值得研讨。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111681.html原文链接:https://javaforall.net

(0)
上一篇 2022年2月17日 上午7:00
下一篇 2022年2月17日 上午8:00


相关推荐

  • 使用StopWatch计算耗时[通俗易懂]

    使用StopWatch计算耗时[通俗易懂]一、传统计算耗时方式一般采用System.currentTimeMillis()来获取时间,然后打印当前时间与任务开始执行时间的差值。记录开始时间点记录结束时间点输出当前时间与任务开始执行时间的差值代码如下:publicstaticvoidmain(String[]args)throwsInterruptedException{longstartTime=System.currentTimeMillis();//dos

    2022年6月23日
    30
  • python缺省值_python函数缺省值

    python缺省值_python函数缺省值random 函数描述 random 方法返回随机生成的一个实数 它在 0 1 范围内 语法 importrandom random 注意 random 是不能直接访问的 需要导入 random 模块 然后通过 random 静态对象调用该方法 实例演示 importrandom random 0 5print

    2026年3月20日
    3
  • MySql删除重复数据(只保留一条)

    MySql删除重复数据(只保留一条)MySql 删除重复数据 1 问题引入前一段遇到 MySql 数据重复的问题 由于重复向同一张表导入同一批数据 导致前台展示的数据重复 唯一方便快捷的方法莫过于利用 delete 操作删除重复数据 已经封板发布 只保留其中一条数据 但真的是书到用时方恨少 技术也如此 当时只好在网上搜索资源 最终解决了燃眉之急 但是对找到的 delete 语句并不是太理解 后来抽时间自己研究了一下 现在稍微理解了一点 分享给大家 希望对大家有帮助 2 数据准备创建表 CREATETABLEt del repeti

    2026年3月18日
    2
  • linux gfortran编译,gfortran编译学习

    linux gfortran编译,gfortran编译学习一 http wiki ubuntu org cn index php title Compiling Fortran amp variant zh cn 二 http blog sciencenet cn blog 653490 786218 html 1 gfortran c 编译源代码生成 o 文件 然后再将这些文件连接起来 gfortran o 将生成的 o 文件连接起来

    2026年3月19日
    1
  • RevealTrans图片切换效果

    RevealTrans图片切换效果RevealTrans更新时间:2013-06-0117:11:59|RevealTrans兼容性:IE5.5+语法:filter:progid:DXImageTransform.Micros

    2022年7月3日
    24
  • 锐评 | Kimi K2,接过这一棒

    锐评 | Kimi K2,接过这一棒

    2026年3月12日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号