在 Apache 與 Oracle 共存的 Linux 主機上,一個為清理 Apache 共享記憶體而寫的排程腳本,因缺乏擁有者判斷邏輯,誤刪除 Oracle 的信號量陣列,導致生產資料庫瞬間當機。本文還原事發經過、錯誤徵兆與教訓,為同類環境敲響警鐘。
環境:Red Hat AS 3、Oracle 9.2.0.4、Apache + Resin 共跑單機。Apache 長期運行會耗盡共享記憶體,報錯 No space left on device: Couldn't create accept lock。運維寫腳本定時清理 ipcs -s 顯示的信號量,屢試不爽。
新增一個 Apache 應用後,腳本照常執行清理並重啟 Apache,服務恢復。幾分鐘後 Oracle 資料庫突然掛掉,alter.log 湧現大量錯誤:
ORA-27157: OS post/wait facility removed
ORA-27300: OS system dependent operation: semop failed with status: 43
ORA-27301: OS failure message: Identifier removed
ORA-27302: failure occurred at: sskgpwwait1
RECO: terminating instance due to error 27157
執行 ipcs -s 發現 Oracle 持有多組信號量(owner 為 oracle,perms 640,nsems 201)。清理腳本僅以 grep apache 過濾,但實際執行時未正確排除 Oracle 的 IPC 資源,導致 ipcrm sem 刪除了 Oracle 的信號量陣列。Oracle 依賴這些信號量實現進程間通訊與同步,一旦被移除,背景進程(LGWR、SMON、RECO 等)即無法運作,資料庫被迫終止。
# 僅刪除 apache 用戶擁有的信號量
ipcs -s | grep apache | perl -e 'while (<>) { @a=split(/\s+/); print `ipcrm sem $a[1]` }'
關鍵在於 嚴格比對擁有者欄位,不可僅靠關鍵字模糊匹配。
ipcs 資源使用趨勢,設定閾值告警,而非依賴定時暴力清理。這起低級卻嚴重的事故再次證明:DBA 的每一次操作都需三思而後行,特別是涉及作業系統層級共享資源時,容錯率為零。