文章目錄
- 一、闡述問題
- 二、開始排查
- 1.執行代碼展示
- 2.PHP層面排查問題
- 3.系統層面排查問題
- 1. 分析系統日志
- 2. core dump 分析
- 2.1 core dump 是什么
- 2.2 core dump 配置 并 生成 core 文件
- 2.3 gdb 解析 core 文件
- 4. 問題解決
- 三、贈送內容
- 四、總結
一、闡述問題
這個問題花了我起碼10個小時,必須得總結一下。
問題是這樣的,我在laravel 里面連接了一下sqlserver的數據庫,然后頁面直接就報502
。去項目下的日志看,也沒有任何報錯。
二、開始排查
1.執行代碼展示
$serverName = '192.168.116.180\messyna'; //數據庫服務器地址
$connectionInfo = array("UID" => "mssa", "PWD" => "12345677", "Database" => 'test111');
$conn = sqlsrv_connect($serverName, $connectionInfo);
if($conn == FALSE){echo "連接失敗!";var_dump(sqlsrv_errors());exit;
}else{echo "鏈接成功";
}
echo "連接成功!";
exit;
這就是普通的連接sqlserver的代碼。只要執行這段代碼,直接就報 502!
Sqlserver
的配置肯定沒問題,前一天還是可以執行的。而且有其他的機器能執行。
2.PHP層面排查問題
經過一段時間的亂碰,覺得還是看一下php-fpm
的錯誤日志。
找到php-fpm的配置,找到錯誤日志路徑。
終于看到報錯信息:
deepseek
的回答結果如下:
WARNING: [pool www] child 4542 exited on signal 11 (
SIGSEGV
) after 542.345727 seconds from start
-
含義:www 進程池中的子進程 4542 在運行 542秒(約9分鐘) 后,因
信號 11(SIGSEGV)
崩潰退出。-
SIGSEGV(分段錯誤)
:表示進程試圖訪問非法內存地址,常見原因包括:-
PHP 擴展(如 Redis、Opcache 等)存在 bug。
-
PHP 代碼中存在
內存溢出
(如無限遞歸、大數組操作)。 -
服務器內存不足或配置錯誤(如 pm.max_children 設置過高)。
-
硬件問題(如內存條故障,但概率較低)。
-
-
我的分析測試:
硬件問題可以排除,最近我都沒動過什么配置之類的。而且是虛擬主機,不可能。PHP 代碼中存在內存溢出可以排除。就一個連接,能有什么溢出內存不足,我將虛擬主機加大了2G內存, 結果還是502,說明不是內存問題。擴展問題,感覺有點像
- mysql的連接是正常的,就sqlserver 不正常
- 重新安裝 pdo_sqlsrv 和 sqlsrv 兩個擴展,結果依然是502,跟擴展沒關系重裝php8.2,結果測試,還是502
經過以上的測試,差不多可以知道,應該不是php的問題。應該是centos系統的問題。不管怎么測試。指向的都是 分段錯誤
3.系統層面排查問題
1. 分析系統日志
dmesg | grep php
在系統日志中篩選與 “php” 相關的信息
取一條日志出來看看:
[65062.298372] php-fpm[1288]: segfault at 0 ip 00007fc555571fd6 sp 00007fff26f52bb8 error 4 in libc-2.17.so[7fc555433000+1c4000]
經過查資料分析:
這個錯誤提示表明 PHP-FPM 進程發生了段錯誤(segfault
),這通常是由內存訪問違規引起的嚴重錯誤。
segfault at 0
:程序嘗試訪問內存地址 0x0(空指針),這通常是由于未初始化的指針或內存損壞導致的。
libc-2.17.so
:錯誤發生在 C 標準庫中,這是系統核心組件,可能由以下原因觸發:
- PHP 擴展與 libc 不兼容。
- PHP 本身存在內存管理漏洞。
- 系統庫文件損壞。
error 4
:表示 SEGV_ACCERR(訪問權限錯誤),即程序嘗試訪問沒有權限的內存區域。
總體上來說,應該是讀取內存地址無效。但是沒有具體的信息,過于籠統,還需要進一步的調試。
又經過了漫長的查資料,終于查到了一點方向,core dump
2. core dump 分析
2.1 core dump 是什么
-
core dump 是什么?
core dump(核心轉儲) 是操作系統在程序異常終止(如崩潰、段錯誤、非法指令等)
時,將進程當時的內存狀態、寄存器內容、程序計數器值等關鍵信息寫入到一個文件中的過程。這個文件被稱為 core 文件,它本質上是進程運行時狀態的 “快照
”。 -
core dump 的作用
-
調試程序錯誤
開發人員可以通過分析core 文件
,定位程序崩潰的具體位置(如哪行代碼引發錯誤)、變量值、函數調用棧等信息,從而快速排查內存越界、空指針引用、段錯誤等問題。 -
系統故障分析
在服務器環境中,core dump 可用于分析長期運行的服務(如 Web 服務器、數據庫)突然崩潰的原因,避免問題反復出現。 -
性能優化參考
雖然 core dump 主要用于錯誤定位,但也能間接反映程序的內存使用模式,為性能優化提供線索。
-
-
core dump 的觸發場景
當程序遇到以下情況時,系統通常會生成 core dump:- 訪問非法內存地址(如空指針解引用、數組越界)
- 執行非法指令(如除以 0、無效的 CPU 操作碼)
- 收到無法處理的信號(如 SIGSEGV、SIGABRT)
- 內存不足或被系統強制終止(如 OOM Killer 觸發)
正和我意,觸發場景正好能解決我的問題。
2.2 core dump 配置 并 生成 core 文件
-
設置 core 文件大小為無限制(unlimited):
//臨時調試 ulimit -c unlimited//調試完最后記得關閉 core dump ulimit -c 0
-
執行 php 代碼,報錯 502。 此時在項目的根目錄下,會生成一個 core 文件。
這幾個core 文件就記錄了 內存讀取失敗的相關情況,那接下來就是讀取這個core 文件了
2.3 gdb 解析 core 文件
GDB(GNU Debugger) 是 Linux/Unix 系統下最常用的 代碼調試工具
,主要用于分析和修復程序崩潰、死鎖、內存泄漏
等問題
1. 安裝 gdb
yum install gdb
2. 生成 GDB 回溯信息
gdb php core.2134
(gdb) bt full # 獲取完整的堆棧回溯
3. 文件內容如下:
4. 經過deepseek分析:
4. 問題解決
根據 GDB
完整堆棧回溯信息,問題的根源已經很明顯了
OpenSSL庫版本沖突 ,有兩個庫版本,ODBC驅動嘗試初始化SSL連接時,不同版本的OpenSSL庫發生沖突,導致內存訪問異常
確實是有兩個,而且那個還是前一天我安裝 python 時候產生的。
直接刪除openssl111
,因為openssl111 安裝前,一直是正常的。肯定是 openssl111 安裝了,導致出問題
刪除后,執行代碼,一切正常。終于解決
三、贈送內容
以下是監控 PHP-FPM 主進程,然后程序崩潰時,可以查看具體情況
# 附加到 PHP-FPM 主進程
sudo gdb -p $(pgrep -o php-fpm)# 當崩潰發生時,輸入以下命令抓取堆棧
(gdb) bt full # 查看完整調用棧
(gdb) info threads # 查看所有線程狀態
(gdb) quit # 退出
四、總結
整個過程非常艱辛,由什么問題都不知道一直到解決,查了很多資料。走了很多的彎路。
一些工具都是第一次使, core dump,gdb
以前基本上沒使用過。
需要持續的學習,持續的踩坑,才能到達最終的彼岸 =》保安