面向祖传代码 Debug,我挽回了一位准备跑路的程序员

article/2025/9/14 14:19:35

交流群的风格突然骤变,没有了往日的灌水扯淡,居然聊起了技术。

在这里插入图片描述
在这里插入图片描述

看了大家的全部的聊天记录,发现问题并没解决。群里难得这么多人聊技术,抱着问答不断,必有回响的原则,主动勾搭一起看看是什么问题。

大概了解其问题是这样,apache 子进程一直异常退出

$ sudo tail -f /var/log/httpd/error_log
[Sun Jun 13 19:32:25.660349 2021] [core:notice] [pid 23340] AH00052: child pid 20605 exit signal Bus error (7)
[Sun Jun 13 19:32:25.660413 2021] [core:notice] [pid 23340] AH00052: child pid 20606 exit signal Bus error (7)
[Sun Jun 13 19:35:39.862368 2021] [core:notice] [pid 23340] AH00052: child pid 21332 exit signal Bus error (7)
[Sun Jun 13 19:35:50.872363 2021] [core:notice] [pid 23340] AH00052: child pid 21369 exit signal Bus error (7)
[Sun Jun 13 19:39:43.079650 2021] [core:notice] [pid 23340] AH00052: child pid 18595 exit signal Bus error (7)
[Sun Jun 13 19:42:08.210353 2021] [core:notice] [pid 23340] AH00052: child pid 21348 exit signal Bus error (7)
[Sun Jun 13 19:42:16.221076 2021] [core:notice] [pid 23340] AH00052: child pid 21331 exit signal Bus error (7)
[Sun Jun 13 19:42:16.221177 2021] [core:notice] [pid 23340] AH00052: child pid 23156 exit signal Bus error (7)
[Sun Jun 13 19:44:11.329344 2021] [core:notice] [pid 23340] AH00052: child pid 27824 exit signal Bus error (7)

现场复现

了解到其架构是 apache + php ,群友也是临时接受的祖传代码,项目也不是很清楚。可以使用strace来看看,背后到底是什么问题

$ ps -ef|grep apache

首先看到主进程 id 是 23340,这里需要跟着其子进程,所以我执行了如下命令

$ sudo strace -o strace.log -s 1024 $(pidof "/usr/sbin/httpd" -o 23340|sed 's/\([0-9]*\)/-p \1/g')
strace: Process 26212 attached
strace: Process 26211 attached
strace: Process 26191 attached
strace: Process 25940 attached
...

参数大概解释下

code释义
-o strace.log输出 strace 日志到 strace.log
-s 1024当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节
pidof “/usr/sbin/httpd” -o 23340排除主进程 23340 之外的 httpd 子进程

然后新开一个窗口监控日志

$ sudo tail -f strace.log |grep SIGBUS -B 500
28741 open("/xxxx/www/data/cache/xxx.php", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 15
28741 write(15, "<?php defined('DYMall') or exit('Access Invalid!'); return array ( ) ?>", 71) = 71
28741 close(15)
...
28741 open("/xxxx/www/data/cache/xxx.php", O_RDONLY) = 15
28741 fstat(15, {st_mode=S_IFREG|0644, st_size=71, ...}) = 0
28741 fstat(15, {st_mode=S_IFREG|0644, st_size=71, ...}) = 0
28741 fstat(15, {st_mode=S_IFREG|0644, st_size=71, ...}) = 0
28741 mmap(NULL, 71, PROT_READ, MAP_SHARED, 15, 0) = 0x7f584aee8000
28741 --- SIGBUS {si_signo=SIGBUS, si_code=BUS_ADRERR, si_addr=0x7f584aee8000} ---
28741 chdir("/etc/httpd")               = 0
28741 rt_sigaction(SIGBUS, {SIG_DFL, [], SA_RESTORER|SA_INTERRUPT, 0x7f58499bc5e0}, {SIG_DFL, [], SA_RESTORER|SA_RESETHAND, 0x7f58499bc5e0}, 8) = 0
28741 kill(28741, SIGBUS)               = 0
28741 rt_sigreturn({mask=[]})           = 140017190993928
28741 --- SIGBUS {si_signo=SIGBUS, si_code=SI_USER, si_pid=28741, si_uid=48} ---
28741 +++ killed by SIGBUS +++

SIGBUS 在用户态最为常见的场景,也最容易触发,通常来说根本原因都是进程 mmap 了一个文件后,另外的进程把这个文件截断了,导致 mmap 出来的某些内存页超出文件的实际大小,访问那些超出的内存页就会触发 SIGBUS

验证文件大小变化

监控文件的大小来验证文件是否一直在变化

$ while :; do cat /xxxx/www/data/cache/xxx.php|wc -L ;done
$ while :; do cat /xxxx/www/data/cache/xxx.php|wc -L ;done|grep -v 71

发现文件确实在少数情况下会变为 0 个字节,根据文件的路径,初步估计应该是缓存文件被重写了

确认文件写操作来源

$ sudo yum -y install audit auditd-libs

监控topic_goodsclass.php文件的写入操作

$ sudo auditctl -w /xxxx/www/data/cache/xxx.php -p w

结果类似于

time->Mon Jun 14 21:21:39 2021
type=PROCTITLE msg=audit(1623676899.778:1883303): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=PATH msg=audit(1623676899.778:1883303): item=1 name="/xxxx/www/data/cache/xxx.php" inode=30151674 dev=fd:11 mode=0100644 ouid=48 ogid=48 rdev=00:00 objtype=NORMAL
type=PATH msg=audit(1623676899.778:1883303): item=0 name="/xxxx/www/data/cache/" inode=30151667 dev=fd:11 mode=040755 ouid=48 ogid=48 rdev=00:00 objtype=PARENT
type=CWD msg=audit(1623676899.778:1883303):  cwd="/xxxx/www"
type=SYSCALL msg=audit(1623676899.778:1883303): arch=c000003e syscall=2 success=yes exit=16 a0=55b452b93078 a1=241 a2=1b6 a3=2a items=2 ppid=31318 pid=18269 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" key=(null)

收集一段时间,做下统计

$ sudo ausearch -f /xxxx/www/data/cache/xxx.php |grep "exe="|awk '{print $12,$26}'|sort|uniq -c44200 ppid=31318 exe="/usr/sbin/httpd"

发现都是来自于/usr/sbin/httpd,并没有CLI模式的写入(担心有定时任务来生成缓存),清理掉监控

sudo auditctl -D

多进程文件读写冲突的解决方案

需要注意,在对文件进行fopen($filename, "w+")的时候,就已经将文件清空了,所以加锁需要在fopen目标文件之前,所以我的方式是增加一个文件一一对应的锁文件。如下:
aa.php

function addFileLock($filename, $lock)
{$fp = fopen($filename . ".lock", "w+");flock($fp, $lock);return $fp;
}function releaseLock($fp)
{flock($fp, LOCK_UN);
}$filename = "cc.log";// mock 数据
file_put_contents($filename, "100");$fp = fopen($filename, "r");if ($lockfp = addFileLock($filename, LOCK_SH)) {$n = 10;while ($n > 0) {sleep(1);printf("%d %d\n", time(), --$n);}echo fgets($fp);releaseLock($lockfp);
}fclose($fp);

bb.php

function setFileLock($filename, $lock)
{$fp = fopen($filename . ".lock", "w+");flock($fp, $lock);return $fp;
}function releaseFileLock($fp)
{flock($fp, LOCK_UN);fclose($fp);
}$filename = "cc.log";if ($lockfp = setFileLock($filename, LOCK_EX)) {$fp = fopen($filename, "w+");echo time();fwrite($fp, 200);releaseFileLock($lockfp);
}fclose($fp);

所以先执行 php aa.php 再执行 php bb.php,就能看到效果。

实际代码定位

根据系统调用里面的字符串关键字,搜到了相关的缓存操作代码

28741 write(15, "<?php defined('DYMall') or exit('Access Invalid!'); return array ( ) ?>", 71) = 71

改完之后发现线上还是有问题,本来我已经怀疑人生了,还是通过系统调用发现读取的时候并没有走我增加的共享锁
WechatIMG536.jpg
原来缓存的读取是走的别的逻辑,从上面的截图可以看到缓存的写入已经走了修改之后的代码(加锁逻辑),然后根据个人经验加搜索该缓存写入方法,按图索骥找到了另外一个缓存文件的读取逻辑,然后再次修改,线上问题没有再复现。

问题解决,跑路哥给我发来红包,我心满意足的接受了。

在这里插入图片描述

总结

  1. 首先通过strace复现SIGBUS的场景
  2. 预计是文件在多进程模型下,并发读写导致的问题
  3. 通过auditctl监控统计文件的写操作来源均为httpd没有其他进程来修改
  4. 通过读加共享锁、写加排它锁,线上还是有问题
  5. 再次根据strace 发现读的地方另有他处,根据经验,补上,问题修复

不足的地方:最后定位过于依靠个人经验,不够系统化。

小想法:可以弄一个扩展使用 zend_set_user_opcode_handler 来监控自定义函数和方法和系统方法和函数调用链,然后在每个请求初始化阶段写入日志,比如

write(fd, "{unique code}", xxx);
write(fd, "request uri", xxx);

然后的方法调用在 zend_set_user_opcode_handler里面打印,这样就能方便排查祖传代码的一些业务逻辑问题了。

如果有其他更快更简单的方案,大家留言告诉我。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/SGRxAmMf.shtml

相关文章

第一次敲代码的感受

上图 打了2遍才成功&#xff0c;吐了&#x1f92e; 第一遍错了好几次&#xff0c;最后还是不知道那错了&#xff0c;发给同学都可以运行&#xff0c;我这电脑确不可以运行&#xff01; 最后第二遍终于成功了 &#xff0c;花费一个小时&#xff0c;也不知道还行不&#xff1f…

程序员想知道代码是怎样跑起来的

某一天&#xff0c;程序员使用Java语言实现累加求和的方法&#xff0c;将文件命名为Sample.java。 public class Sample {public static void main(String[] args) {System.out.println(sum(10));}private static int sum(int n) {int res 0;for (int i 1; i < n; i) {res…

从前有一个程序员,成天写代码,后来。。。

之前这里是网易云音乐 的外链&#xff0c;许巍演唱版本的《执着》&#xff0c;我们搞IT 的多少都有些执着&#xff0c;后来网页没有了版权&#xff0c;我只好放上来歌词了。 如果对文章没有太多兴趣&#xff0c;可以只读一遍歌词&#xff0c;或者听一遍歌&#xff0c;哈哈。 每…

开发10年程序员,坐标北京,今天我硬气一回把老板炒了!!!

我的情况 随着越来越多的零基础非专业跳槽人员以及大学计算机专业学生越来越多,导致程序员找工作门槛也越来越高。虽然有着三年的开发经验,也自认为自己能解决很多问题。但是从找工作的这段时间才发现,自己的解决问题的能力是有,但是技术深度不够扎实。 通过对比自己和中…

低代码起势,程序员闷头开发的日子结束了

对于“低代码”的宣传其实已经很久很广泛了&#xff0c;但是争议从来都没有停止。“低代码将会取代程序员”的说法也很荒谬&#xff0c;今天系统整理了低代码&#xff0c;希望能对大家有启示&#xff0c;同时也欢迎各位在评论区指正探讨。 何方神圣&#xff1f; 所谓的低代码开…

程序员的炫技代码写法

程序员的炫技代码写法 程序员&#xff0c;这个职业总是让人感到神秘而又充满魅力。他们手中的代码常常充满了令人惊叹的炫技操作&#xff0c;让人不禁感叹他们的技术能力之高。在这篇博客中&#xff0c;我想和大家分享一些我所知道的程序员的炫技代码写法。 一、代码美感——…

一串代码让你成为机房最靓的仔

1.创建一个记事本文件 2.编辑文件内容 语法格式 color 背景色字体颜色 echo 输出的内容 %0&#xff08;无线循环&#xff09;例如在文件中输入以下内容并保存 color 1a echo 666666 color 2b echo 666666 color 3c echo 666666 color 4d echo 666666 color 5e echo 666666 c…

我爸嘲讽我,写破代码一年才挣十几万,他在工地带50个工人,一个月仅人头费就挣3万多,让我滚回去跟他干工地!...

现在码农的地位有多低&#xff1f; 一位程序员讲述自己被父亲鄙视的经过&#xff1a; 我爸嘲讽我&#xff0c;说我天天写这破代码有啥用&#xff0c;一年就拿十多万死工资。他在工地带 50 个工人&#xff0c;一个人一天抽 20 块钱人头费&#xff0c;一个月都能抽 3 万多&#x…

电视剧中的程序员,是真的敲代码吗?

今天是1024程序员节&#xff0c;今天不聊技术&#xff0c;聊一聊电视剧中出现过的敲代码片段&#xff0c;从咱程序员的视角看看代码是不是真的在写代码哦~ 1. 码不出来&#xff0c;公司要完 从知乎上看到的 用word写代码&#xff1f;放弃吧&#xff0c;写不写得出来&#xff…

给2500万行代码修复bug的程序员都怎么上班?

通常说&#xff0c;一个人造的、很庞大的事物&#xff0c;会给人很厉害的感觉。 比如说摩天大楼⬇️ 或者巨型水坝⬇️ 看着这种东西&#xff0c;世超不禁想到这几个字&#xff1a; “ 人类工程学奇迹 ” 。 但是欣赏归欣赏&#xff0c;这种巨型工程项目如果出了啥子问题&…

感受野与权值共享

什么是全连接&#xff1f; 若有一幅100x100的图像&#xff0c;隐层有100个神经元&#xff0c;每个神经元与每个像素全部连接&#xff0c;则有100*100*100个连接&#xff0c;这就叫做全连接。 什么是局部连接&#xff1f; 若有一幅100x100的图像&#xff0c;隐层有100个神经元…

感受野浅析

感受野的讲解&#xff0c;我在网上查了好多都是错误的&#xff0c;浪费了大量时间&#xff0c;后来总结下来避免大家入坑 一、感受野的概念 感受野&#xff08;Receptive Field&#xff09;的定义&#xff1a;卷积神经网络每一层输出的特征图&#xff08;feature map&#xf…

CNN感受野计算

笔试过程中遇到了感受野计算的问题&#xff0c;赶快把不牢固的知识复习一下。 1 感受野的概念 在卷积神经网络中&#xff0c;感受野的定义是 卷积神经网络每一层输出的特征图&#xff08;feature map&#xff09;上的像素点在原始图像上映射的区域大小。 2 感受野大小的计算…

目标检测和感受野的总结和想法

点击上方“计算机视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 作者丨pprp知乎&#xff08;已授权&#xff09; 来源丨https://zhuanlan.zhihu.com/p/108493730 编辑丨极市平台 导读 经典的目标检测如Faster R-CNN, YOLOv3等都用到了Anchor&#xff0c;本文详细介绍了…

感受野 深度理解

知乎是个好东西&#xff0c;深入理解一些理念&#xff0c;靠博客是不行的。 感受野计算和理解的内容参考自&#xff1a;https://zhuanlan.zhihu.com/p/44106492 / https://zhuanlan.zhihu.com/p/40267131 后两个卷积的内容参考自&#xff1a; https://www.zhihu.com/question…

卷积神经网络感受野的计算

1 到底什么是“感受野”&#xff08;接受野&#xff09;&#xff1f;——Receptive Field “感受野”的概念来源于生物神经科学&#xff0c;比如当我们的“感受器”&#xff0c;比如我们的手受到刺激之后&#xff0c;会将刺激传输至中枢神经&#xff0c;但是并不是一个神经元就…

深度学习-感受野与有效感受野

文章目录 感受野增加感受野有效感受野与反卷积的区别总结 感受野 卷积核的大小(高度和宽度)定义了一个区域的空间范围&#xff0c;改区域可以被卷积核在每个卷积步骤中修改&#xff0c;因而卷积核的大小称为卷积核的“感受野”。 感受野(receptive field, RF)&#xff0c;卷积…

3.3.2 感受野

3.3.2 感受野 1962年Hubel和Wiesel通过对猫视觉皮层细胞的研究&#xff0c;提出了感受野(receptive field)的概念&#xff0c;Fukushima基于感受野概念提出的神经认知机(neocognitron)可以看作是卷积神经网络的第一个实现网络。 3.3.6 卷积网络的感受野Receptive field (RF)以…

目标检测和感受野的总结

目录 1、感受野 2、理论感受野计算 2.1、自上而下感受野计算 2.2、自下而上的计算方法 3、作用 4、关系 5、总结 6、参考文献 经典目标检测和最新目标跟踪都用到了RPN(region proposal network)&#xff0c;锚框(anchor)是RPN的基础&#xff0c;感受野(receptive field…

CNN中的感受野

CNN中有一个概念叫局部感受野&#xff08;local receptive field&#xff09;&#xff0c;那什么是感受野呢&#xff1f;一般的CNN结构都是卷积-池化这样重复下去&#xff0c;比如下表&#xff1a; layers size stride input100*100*1---conv13*31pool12*22conv23*31pool22*2…