首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle Job 排程異常診斷實錄:497 天系統運作導致計時器溢位

     編輯:Oracle 資料庫基礎

事故現場

  • 環境:SunOS 5.8,Oracle 9.2.0.3.0 (Enterprise Edition),單實例。
  • 現象:所有 DBMS_JOBDBA_JOBS 顯示 NEXT_DATE 正常但 LAST_DATE 停留在數天前。手動 DBMS_JOB.RUN(job) 正常。
  • 關鍵線索:uptime 顯示主機已連續運行 500 天。

排查過程

1. 檢查 Job 狀態

SELECT job, last_date, last_sec, next_date, next_sec, broken, failures
FROM dba_jobs;

所有 Job BROKEN=N、FAILURES=0,但無實際執行記錄。

2. 建立測試 Job

CREATE OR REPLACE PROCEDURE pining IS BEGIN NULL; END;
VARIABLE jobno NUMBER; VARIABLE instno NUMBER;
BEGIN
  SELECT instance_number INTO :instno FROM v$instance;
  DBMS_JOB.SUBMIT(:jobno, 'pining;', TRUNC(SYSDATE+1/288,'MI'), 'TRUNC(SYSDATE+1/288,''MI'')', TRUE, :instno);
END;

測試 Job 同樣不自動執行,手動 RUN 正常 → 排除 Job 定義邏輯問題,鎖定排程器進程 (CJQ0) 異常。

3. 重啟 CJQ0 進程嘗試

ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 0;  -- 等 2-3 分鐘殺掉 CJQ0
ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 5;  -- PMON 重啟 CJQ0

Alert Log 確認 Restarting dead background process CJQ0,但 Job 仍不執行。再次調整參數導致 CJQ0 反覆死亡。

4. 重啟資料庫

離峰時段 Shutdown/Startup,CJQ0 正常啟動,但 Job 依然不跑 → 非進程存活問題,涉及核心計時邏輯。

5. 發現 Oracle Bug (Metalink Note)

Bug: slgcsf()/slgcs() on Solaris stops incrementing after ~497 days uptime.
Root: gethrtime() returns nanoseconds > 42949672950000000 (2^32 * 10^4?)
      slgcs() stays at 0xFFFFFFFF.
Impact: kkJSsrh() uses "now = slgcs()" to compare timestamps.
        After 497 days, "now - last_run" always 0 → Job scheduler thinks no time elapsed.
Fix: Included in 9.2.0.6 Patchset (Solaris 9.2.0.6 尚未釋出時)。

6. 驗證主機運作時間

bash$ uptime
10:00pm up 500 day(s), 14:57, 1 user, load average: 1.31, 1.09, 1.08

完美吻合 497 天臨界點。

解決方案

  1. 立即緩解:安排維護窗口 重啟作業系統 (Reboot OS),歸零 gethrtime() 計數器。
  2. 根治:升級至 Oracle 9.2.0.6+ (含修補) 或遷移至 10g/11g/19c (已修復)。
  3. 監控預警:腳本監控 uptime 或 V$TIMER.HSECS 異常停滯,接近 490 天發出告警。

重啟後驗證

SQL> SELECT job, last_date, last_sec, next_date, next_sec FROM user_jobs;
JOB  LAST_DATE      LAST_SEC  NEXT_DATE      NEXT_SEC
70   26-NOV-04 09:21:04  26-NOV-04 09:26:00

SQL> /  (5分鐘後)
JOB  LAST_DATE      LAST_SEC  NEXT_DATE      NEXT_SEC
70   26-NOV-04 09:26:01  26-NOV-04 09:31:00

SQL> SELECT * FROM v$timer;
HSECS  3388153  (持續遞增,正常)

Job 恢復正常排程執行,V$TIMER 計數器正常遞增。

深度剖析:Oracle 內部計時機制

  • slgcs() (System Layer Get CentiSeconds) 封裝 OS gethrtime() (高解析度時間),轉換為百分秒供內核使用。
  • kkJSsrh() (Job Scheduler 主循環) 週期性呼叫 now = slgcs(),比對 last_run_time 判斷 Job 是否到期。
  • 32 位元無號整數上限 4,294,967,295 約等於 497 天的百分秒數。Solaris gethrtime() 回傳奈秒,轉換邏輯溢位導致 slgcs() 卡在 0xFFFFFFFF。
  • 此計時器亦被其他內核模組使用 (如快取老化、鎖超時、統計收集),潛在影響面極廣。

教訓與最佳實務

教訓行動
長運行系統隱藏計時器溢位風險定期 Reboot OS (建議 < 180 天) 或升級修補版本
Job 不跑不一定是 Job 壞了檢查 CJQ0 進程、V$TIMER、OS uptime、Alert Log 綜合判斷
疑難雜症大膽懷疑 BugMetalink/MOS 搜尋關鍵字 (uptime, slgcs, job queue, 497 days)
升級前驗證 Patchset 釋出狀態確認目標平台已有修補版本再規劃升級

結語

這起「497 天 Job 罷工」案例,揭示了作業系統層面計時器溢位如何穿透資料庫內核影響核心排程功能。它提醒我們:基礎設施層 (OS/Hardware) 的長期運行狀態,同樣是資料庫穩定性的關鍵變數。建立「OS 定期重啟/升級」與「資料庫關鍵指標監控 (V$TIMER, CJQ0 狀態)」雙重防線,才能避免類似「時間炸彈」在關鍵時刻引爆。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved