温旭峰好文:
502 是什么?
The server, while acting as a gateway or proxy, received an invaild response from the upstream server it accessed in attempting to fulfill the request.
从概念上来看:上游服务无响应会导致502,那么什么是上游服务?以LNMP架构为例,MySQL是PHP的上游服务,PHP是Nginx的上游服务。一般情况下,发生502都不是nginx的问题,问题主要集中在上游服务Php中,进程数的设置、内存设置、超时设置等都可能会导致502。
我们可以先看看整个请求流程中,哪里出问题可能会出现502?

从路径上来看,发生502有两大类场景:
nginx服务不可用;负载均衡通过健康检查发现上游服务不可用,会直接返回502,不会转发请求到后端服务
fpm异常;Nginx接收不到上游服务(php)的返回,会返回502
回到线上业务现象,只有某个特定的接口出现了502,只要一访问就会502,但是其他接口是好的。这样的现象就比较诡异,通常我们碰到的502都是整体服务不可用导致或者偶发的不同业务502,与我们出现的现象都不一样。那么我们如何定位呢?
从主要路径排查
排查路径:
根据现象,我们可以首先排除Nginx的问题
其次是php-fpm的问题,因为之前线上没有出现配置导致502的问题,并且其他的接口都是正常的,与我们的场景不一致,也可以排除php-fpm配置的问题
Nginx与fpm配置均无异常,ECS也没有异常,那么我们可以猜测是代码的问题。
我们猜测是 代码的问题导致了fpm进程异常退出 ,从而导致特定接口出现了502,但其他接口都是好的。那如何验证这个猜测呢?
看日志
进程异常退出,一般都有日志打印
首先查看php-fpm日志:
WARNING: [pool www] child 30296 exited on signal 11 (SIGSEGV) after 136.678208 seconds from start
从fpm日志,可以看到进程是执行了一个无效的内存引用而退出的。我们查看 /var/log/message 日志,确认一下是否是无效的内存引用导致的进程退出。

发生502的时候都有对应的日志,从日志信息中看是内存访问越界导致的。/var/log/message 日志中 error 后面的数字是比较有用的,上面的是4,转换成二进制是100。
bit2: 值为1表示是用户态程序内存访问越界,值为0表示是内核态程序内存访问越界
bit1: 值为1表示是写操作导致内存访问越界,值为0表示是读操作导致内存访问越界bit0: 值为1表示没有足够的权限访问非法地址的内容,值为0表示访问的非法地址根本没有对应的页面,也就是无效地址
所以含义就是用户态读取的内存地址无效。
结合fpm的日志,我们可以通过以下两种方式来定位具体问题所在:
直接看代码;因为是特定接口我们只需要查看接口的代码,因为是新代码上线后导致的问题,这样看变更代码可以快速定位到问题。我们遇到的问题是yaf框架的问题,附有详细的测试环境与测试代码,可自行尝试复现并使用core dump分析
Core dump;适用于偶发性的不确定的进程异常退出,我们可以从core文件中看到整个调用,进而定位到问题所在
附:
测试环境
CentOS Linux release 7.6.1810 (Core)
php 7.1.12
yaf 3.0.7
<?phpclass Test502Controller extends Controller {public function testRunAction() {$productId = $_REQUEST['product_id'];$params = ['timestamp' => time(),];$this->mergeArr($params, $_REQUEST);// 此处使用$this->post()或$_REQUEST是正常的,不会发生502$regionId = $this->request('region_id', 0);var_dump($productId, $regionId);}private function mergeArr(array $params = [], array &$merger = []):void {$data = &$merger;$data = array_merge($data, $params);}}
拖地先生,从事互联网技术工作,在这里每周两篇文章,聊聊日常的实践和心得。往期推荐:

如果对你有帮助,让大家也看看呗~




