本週一個故障,記錄一下。
html
諸位知道,歷史遺留代碼,只要能運行,通常都不肯意去動的。 然而, 遺留問題就像雷區,排雷會炸,不排也會炸。 這不,本週一個電子卡券導出的雷,炸得我真是「面目全非」。前端
具體代碼沒必要細講。 看官只需懂得:電子卡券導出是一個PHP後臺任務,接收消息隊列的導出消息來處理任務。 在捕獲了一個異常以後,走到了異常處理分支。異常分支有句代碼 logger->warn 。 這有何錯 ? logger 並無 warn 方法 ! IDE 也提示的。 因而 PHP 報 fatal error ,直接退出了進程。 這樣,導出任務進程沒法啓動,沒法處理消息,隊列阻塞,前端就一直顯示報表正在生成中。性能
爲何 logger 沒有 warn 方法 , 卻還明顯地寫着 logger->warn ,甚至歷經兩年都沒有發現 ? 想必部分讀者已經瞭然:由於寫在異常捕獲中。異常測試,是很容易被忽略的分支。測試
值得說起的是,logger 有個 warning 的方法。 然而,開發者習慣用 warn 而不是 warning ,而且 warn 是動詞,warning 是名詞。 打日誌本應該用 warn 而非 warning 。 底層 API 設計者但願用新的方式取代老的方式,也必須考慮到大多數開發者的慣用法。
設計
另外一個問題是: 電子卡券導出爲何處理這麼慢?日誌
進一步閱讀代碼可知,電子卡券導出代碼,裏層居然對每個訂單循環進行處理:訪問 DB 獲取卡券信息,調用用戶 API 接口,調用重量級的訂單詳情接口。環環相扣,真是使人「拍案叫絕」啊!htm
爲何會出現這種狀況 ? 原來,爲了方便,導出代碼複用了列表代碼。而列表代碼只須要處理 20 個訂單, 但導出代碼卻會處理數萬訂單。可想其性能能夠低到地內心面去。推測, 可能當時修改列表代碼的時候,並無注意到導出複用了列表代碼,只是在列表代碼裏修改了,但同時導出的處理也影響到了,而修改者渾然不覺。blog
調用重量級的訂單詳情接口,也值得商榷。 列表與導出要顯示的信息不過七八個,卻要調用訂單詳情接口,獲取近百個字段。真是爲了一個輪胎,拖了一輛卡車。須知,這事並不鮮見。注意到,導出外層批量調用了一次新的批量詳情接口,卻不料裏層爲了訂單列表又循環對每一個訂單調用了老的訂單詳情接口,使人以淚洗面!接口
這裏有三個啓示:隊列
處理一個故障,能夠折騰不少時間。好比 「趴墳」啊,開會啊,每個細小的地方,必定要分析得水落石出,使人心服口服,無言以對,—— 哪怕這坨代碼不再會在線上運行。 有這時間,能夠多去發現和思考系統中的潛伏着的問題,根治之。
PS: 無心看到歷史上的今天,發了一篇「代碼問題及對策」 ,裏面早已談到了這些問題。 後人哀之而不鑑之,亦使後人復哀後人矣。