事情起因
耗子逗貓 —— 沒事找事
前幾天,在工作不太忙的時候,為了展示我在工作中積極主動,技術能力較強,并給領導留個好印象,我就去翻翻項目代碼有沒有可優化的空間。
沒想到,我真讓我找著啦。
禍端就此埋下了!
有用戶反饋查詢訂單列表接口有點慢,我就去打印每一步的耗時信息。發現查詢訂單之前,需要先根據用戶ID查詢用戶信息,而查詢用戶信息接口需要調用用戶團隊提供的服務,有時候網絡較慢的時候,耗時達到200毫秒。
而查詢訂單接口層層調用的時候,調用了好幾次查詢用戶信息接口。當然可以改成再最上層查詢一次,然后層層往下傳遞,這樣一來改的地方比較多,也很麻煩。
我琢磨著能不能加個本地緩存,把用戶信息緩存起來,這樣就不用每次去調用用戶服務查詢了。剛好就想到了使用,聽說高級程序員都用,我也想用一下試試。
是線程私有的,調用結束后,線程銷毀了,里面數據也跟著沒了。
聽著是線程安全的,應該沒什么問題。
動手實踐
我先寫一個的工具類,用來存儲和獲取用戶信息:
/**
* @ 本地緩存用戶信息
**/
class {
?
// 使用存儲用戶信息
final = new ();
?
/**
* 獲取用戶信息
*/
User () {
// 如果中沒有用戶信息,就從請求解析出來放進去
if (.get() == null) {
.set(.());
}
.get();
}
?
}
然后在查詢訂單接口里面,調用這個工具類的方法獲取用戶信息,最后根據用戶信息查詢訂單信息,完美。
/**
* 獲取訂單列表方法
*/
List () {
// 1. 從緩存中獲取用戶信息
User user = .();
// 2. 根據用戶信息,調用用戶服務獲取訂單列表
.(user);
}
自測、提測、驗收、上線,接口訪問速度“嗖”一下就上去了,一切看上去都是那么完美。
事與愿違
上線一個小時后,值班群炸了。
陸續開始有用戶反饋自己剛下的訂單不見了,其他用戶也有反饋自己的訂單列表莫名其妙多了一些訂單。
我一臉懵逼,沒碰到過這種情況,逐漸反饋的用戶越來越多,我已經不知所措了。
領導當機立斷,趕緊回滾服務。
半個小時后,回滾完畢,用戶的情緒逐漸平復下來。
故障復盤
線上故障解決后我的訂單詳情查詢,緊接著就開始排查問題產生的原因。
經過無數次打日志、debug,終于定位到問題了。
確實是線程私有的,并且會在線程銷毀后,里面的數據也會被清理掉。
但是問題就出在,無論我們服務端用的是、Jetty、、Dubbo等,都不會來一個請求就創建一個線程,而是創建一個線程池,所有請求共享這這個線程池里的線程。
一個線程處理完一個請求,并不會被銷毀??赡軐е露鄠€用戶請求共用一個線程,最后出現數據越權,看到了別的用戶的訂單。
解決方案
解決辦法就是,在使用完后,再調用方法清除數據。
/**
* @ 本地緩存用戶信息
**/
class {
?
// 使用存儲用戶信息
final = new ();
?
/**
* 獲取用戶信息
*/
User () {
// 如果中沒有用戶信息,就從請求解析出來放進去
if (.get() == null) {
.set(.());
}
.get();
}
?
/**
* 刪除用戶信息
*/
void () {
.();
}
?
}
使用try/catch包裹業務代碼,然后在中清除數據。
/**
* 獲取訂單列表
*/
List () {
// 1. 從緩存中獲取用戶信息
User user = .();
// 2. 根據用戶信息,調用用戶服務獲取訂單列表
try {
.(user);
} catch ( e) {
throw new (e.());
} {
// 3. 使用完后,刪除用戶信息
.();
}
null;
}
故障定級
影響用戶超過10w,或者錯誤數據超過10w,或者資損大于100w,故障定級為P1,全年績效C。
本來想優化程序性能,提高訪問速度,給領導一個好印象,好顯得自己技術能力強,工作積極主動。
這下好了,不但年終獎沒了,工作還可能保不住了。
事故總結
經過這次事故我的訂單詳情查詢,我總結了以下幾點教訓:
沒事兒別瞎逞能。
沒有金剛鉆,別攬瓷器活。
不求有功,但求無過。
重構優化的水太深,你把握不住。
免責聲明:部分文章信息來源于網絡以及網友投稿,本站只負責對文章進行整理、排版、編輯,出于傳遞更多信息之目的,并不意味著贊同其觀點或證實其內容的真實性,如本站文章和轉稿涉及版權等問題,請作者在及時聯系本站,我們會盡快為您處理。