找回密码
 会员注册
查看: 16|回复: 0

nginxfastcgi缓存设计缺陷导致的502错误

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-10-9 16:58:46 | 显示全部楼层 |阅读模式
nginx fastcgi 缓存设计缺陷导致的 502 错误 nginx fastcgi 缓存设计缺陷导致的 502 错误 比克 贝壳产品技术 贝壳产品技术 “贝壳产品技术公众号”作为贝壳官方产品技术号,致力打造贝壳产品、技术干货分享平台,面向互联网/O2O开发/产品从业者,每周推送优质产品技术文章、技术沙龙活动及招聘信息等。欢迎大家关注我们。 242篇内容 2019年05月23日 20:00 作者比克(企业代号名),目前负责贝壳找房主站研发的相关工作。1摘要看似正常的 php-fpm 请求处理,nginx 却返回 502,出错的原因是因为 php warning 信息触发了 nginx fastcgi 缓存上的缺陷。本文详细描述了此缺陷的复现方法,最后在第7部分给出了结论和改进的办法。最后部分是基于本文内容,对 php 开发者提出的的编程小建议,它们能让大家写出更加健壮的服务。(本篇文章PC浏览器下阅读体验更佳)2现象概述在 LNMP 架构的 Web 服务器中,nginx 会偶现 502 错误,且会有 too big header 的日志记录。 但是观察 php 程序的输出,它的 header 部分都不超过 1K,(nginx 的 fastcgi 缓存一般不小于 4K),肯定不是单纯地因为 header 过大。发生此情况时,php 程序还会同时触发 warning 信息,这个 warning 信息可能与这个 502 情况有关。那么是否是 warning 信息过长导致 502 的呢?经过简单的实验观察发现,并非 warning 信息越长,越会触发 502,这里应该存在着更加复杂的规律。3寻找规律这里我们从 warning 的长度这条线索出发,通过一个实验来统计 warning 信息长度和 502 之间的关联关系。软件环境为 windows 10 x64 系统,php 7.0.12, nginx 1.11.5。nginx 缺陷相关的代码和其最新的 master 分支代码没有区别, 所以使用 1.11.5 即可。为了易于分析,我们把 nginx 的 fastcgi 的缓存设置为 1K,正常服务器应该不小于 4K。1fastcgi_buffer_size1k;再构造一个产生 warning 信息的 php 脚本。这个脚本接收一个 GET 参数 len 来控制 warning 信息的长度。error_log 函数会直接输出内容到 warning 信息。1buffer.pos==u->buffer.last){ 4 5if(!f->fastcgi_stdout){ 6u->buffer.pos=u->buffer.start; 7u->buffer.last=u->buffer.pos; 8f->large_stderr=1; 9}1011returnNGX_AGAIN;12}这里可以看到,当缓存已经充满 stderr 数据,但尚未收到过 stdout 的数据( f->fastcgi_stdout 为 0)时,那么就会清空缓存,继续接收剩下的数据。当缓存大小为 1K 的时候,此逻辑处理就会形成一个 1024 间隔分布的触发器。这就是本实验中,502 分布具有 1024 间距的原因。所以为了稳定复现 502,php 例子代码增加了 stdout 的强制输出代码。7结论由于对 stderr 和 stdout 数据共用一个缓存空间,且为同级优先级时,stderr 数据在特定长度下,就会挤压 stdout 数据的空间,从而触发 too big header 日志,造成 HTTP 502 响应。 但是此时 fastcgi 应用很可能已经正常处理了这个请求。这种 502 和 fastcgi 进程不足造成的 502 的区别是,前者这个请求已经被处理了,可能已经执行了某些写入操作,在实际应用中,重试请求需要考虑幂等处理。而后者的这个请求,根本没有被 fastcgi 应用接受,重试请求也谈不上需要幂等处理。如果要解决这个缺陷,最好的方案是能够提高 stdout 数据的优先级。当解析 stdout 数据空间不足时,可以清空缓存中的 stderr 数据,这样 too big header 就是真实的 too big header 了。当然,采取独立缓存也是一个办法,但是这样可能对 nginx 的性能有些影响。8php开发小建议程序员不在乎 warning,是因为 warning 不影响正常流程。本例中,warning 在某种情形下会变为 error,进而影响服务的表现。所以测试和上线回归时,一定要消除所有 warning 。遇到 php warning 导致的 502时,增大 nginx 的 fastcgi_buffer_size 设置只能缓解问题:在 warning 长度较小时,能够避免产生 502。当代码的某个循环中出现 warning 时,stderr 数据量可能会很大,502 会呈现间断分布的特征。这里要强调,nginx 不能解决所有问题,程序员自己消除代码中所有产出的 warning 才是正当的解决方案。如有需求的话,下面 php.ini 的设置值 (也可以放在 php-fpm.conf 中),可以将错误输出导入指定的文件,而不是返回给 nginx。1display_errors=Off;2log_errors=On;3error_log="path/to/log";工程上使用的 php-fpm,在产生一个合格的 HTTP 响应时,需要使用 fastcgi 协议和 nginx 通讯,有兴趣的同学可以自行阅读 fastcgi 协议规范、php-fpm 的源码、nginx 的相关模块的源码。9参考文献1)FastCGI_Specification by Mark R. Brown2)Nginx一次奇怪的502 报错探究 by 浮生(企业代号名) @ 贝壳产品技术作 者:比克(企业代号名)出品人:五花肉、克虏伯(企业代号名)---------- END ----------推荐阅读Yii2数据模型-基于场景的验证 预览时标签不可点 关闭更多小程序广告搜索「undefined」网络结果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-4 06:07 , Processed in 0.449986 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表