最近在作一個調度平臺改造的項目,quartz在測試環境跑的是單機環境,生產上兩臺服務器作集羣。java
測試環境是ok的,生產上線後報錯,一個類java.lang.classNotFoundException(註明:這個類被別人修改了名稱,如今使用的新名字)web
第一次:失敗數據庫
從代碼上排除了對舊的job類的引用(配置文件和類都排除了)緩存
推測是服務器緩存了該類。服務器
嘗試:測試
清除緩存,重啓服務器,仍然報上述錯誤。編碼
第二次:失敗spa
將生產上的配置拉到測試環境上,反覆測試,重啓服務器時會自動清除緩存。設計
推測是quartz的那個類爲全局變量,在生產上會作同步。調試
嘗試:
在測試環境上再次搭建一臺調度服務器,從生產上將配置和執行所有拉到測試環境上,執行ok
反覆調試,仍然沒有發現同步的跡象。
沒有重現生產上的異常,不敢上線了。
第三次:失敗
那麼這個舊的job類究竟從哪裏調用的?找不到頭緒!會不會保存到數據庫吧?
當時以爲這個想法很搞笑,從設計的角度上來講,quartz應該不容許將別的類引入到本身的體系吧。
但也沒路可走,就查看數據庫,看看有沒有保存在數據庫中。你猜對了,它對原本來本的躺在數據庫的表中:
CREATE TABLE QRTZ_JOB_DETAILS( JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE VARCHAR(1) NOT NULL, IS_VOLATILE VARCHAR(1) NOT NULL, IS_STATEFUL VARCHAR(1) NOT NULL, REQUESTS_RECOVERY VARCHAR(1) NOT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (JOB_NAME,JOB_GROUP)) TYPE=InnoDB;
好吧! 查看該字段,發現確實是舊的類,被不是新的類。
那麼爲何在測試環境中發現呢?
進入測試庫,也沒有發現舊的類,好吧。
第四次:成功
再次部署到生產上,仍是報錯:類找不到。
確認問題處在數據庫中,我對quartz的表一張張的查找,仍然找不到這個記錄,那就從寫入庫開始入手,查了quartz的代碼,發現job_detail表中有個字段job_data,它的類型是blob,會不會存在這裏呢?
確實,能夠打開此blob查看,數據時放到這裏了。
這個當心一些,再次檢查是否有別的blob字段存放舊的job類,發如今triggers表中也有個字段job_data,至此問題發現了。可怎麼解決呢?blob類型的數據不能直接經過update來執行,畢竟要考慮到編碼的因素,拿就釜底抽薪,直接將類重構爲之前的類。
從此次經從來看,舊項目果真是坑,我就直愣愣的掉進去了。
結論:
計算機是個理性的東西,故一切皆有可能,即使是最不可能的事情也要去一一確認。在查找問題時最好想清楚全部發生故障的可能,而後一一排除,直到找到最終的問題。
對web開發來講,解決此類問題的通常思路以下:
1,從全局的角度來看,應用程序,緩存,數據庫是三大獨立模塊,這些部分都有可能發生異常,應該首先排查應用程序自己的異常(這個機率最大);其次是緩存(同步)模塊排查;最後是數據庫模塊排查。
2,全局肯定好的前提下,細分上述的模塊,將可能出現的問題一一列出。
3,動手,驗證想法。對一個好的開發者來講,動手只是驗證的手段,思路纔是最重要的。