線上一個服務0:00-0:20沒有任何問題,0:20之后突然一個服務調用量增加(不合理接口調用量應該都是0:00開始猛地暴漲),
接口可用率降到50%以下。如果是核心交易接口,那么訂單將影響一半以上,很可怕。還好,不是核心業務,是一個輔助展示
業務,並且業務本來不應該打開。
那么為什么配置被打開?為什么調用量增加?馬上和下游溝通,以及查找問題,如有情況對系統做降級處理,返回通用數據,
因為下游程序發生了bug,在配置服務時候導致配置異常,不該調用我們接口配置被打開,調用我們接口量暴漲。
為什么調用量暴漲之后接口可用率下降?一種情況是調用量暴漲導致,超過了服務可相應極限導致服務可用率降低,經定位
發現不是流量暴漲導致,因為服務各種cpu、內存、網絡資源使用率均正常,服務可承受流量為當時十倍也不會有問題,故排除
這種情況。
排除流量超過之后,那就是邏輯存在bug,下游請求參數錯誤或我們程序本身有bug在大流量下有用戶觸發到該bug,有了這
兩種假定。繼續日志定位是線上服務有null值導致,具體什么原因呢無法定位,因為線上打日志方式是log.error(e.getMessage())
沒有打印詳細信息,關鍵時刻掉了鏈子,無奈只好馬上將預發布加上log.error(e.getMessage(),e)打印詳細錯誤棧信息輔助快速定
位問題。
經修改后預發布進行定位發現問題是:使用for循環遍歷集合,另外一個集合與他進行判斷數據不再集合中則移除數據如下樣
例所示:
for(String str : stringList){
if(!otherList.contains(str)){
stringList.remove(str);
}
}
因為在遍歷集合時對集合進行移除操作,這種操作會導致計數器異常,最終導致程序異常。
修改方式一種采用倒敘方式遍歷:
for(int i=stringList.size()-1;i>-1;i--){
String str = stringList.get(i);
if(!otherList.contains(str)){
stringList.remove(i);
}
}
這種通過倒敘遍歷方式避免移除數據,不會導致集合遍歷下標錯誤,程序完全正確,是一種程序遍歷方式。
再有一種修改方式:
for(Iterator<String> it = stringList.iterator();it.hasNext();){
通過支持刪除迭代器遍歷方式遍歷集合方式刪除數據也是沒有問題的。也是一種正確數據刪除方式。 還有其他比如通過另一個
集合記錄待刪除數據,通過removeAll()一次刪除符合刪除要求數據等多個方式。
回過頭來總結一下,線上問題出現根本原因,一是基礎不扎實,二是測試不到位,不該犯得錯誤犯了,再有就是編碼不規范,
如果異常日志打印詳細合理,也能節省時間,很快就能定位線上服務問題,節省定位問題時間。
基礎是及其重要一件事,也是一件“很小”的事,但卻往往決定我們技術架構、設計成敗。不能好高騖遠,要腳踏實地。勿在
沙台築高樓--侯傑。上邊程序bug如是在中間件程序或線上支付流程大家可以想象下,中間件情況下是線上全部服務受影響,一種
是影響線上訂單服務,按交易額是50億計算就是影響25億以上,想想就后怕,做事要認真做好每一件“小事”與大家共勉。
微信搜索:debugme123
掃描二維碼關注: