(7)彈力設(shè)計篇之“重試設(shè)計”

概要:

1漱挚、重試的場景,比如流控渺氧,并不是所有的失敗場景都適合重試旨涝。

2、重試的策略侣背,簡單的指數(shù)退避策略白华,和 Spring 實現(xiàn)的多種策略》纺停可以用 Java 的 Annotation 來實現(xiàn)弧腥,或者用 Server Mesh 的方式,不必寫在業(yè)務(wù)邏輯里潮太。

3鸟赫、重試設(shè)計的重點。

關(guān)于重試消别。微服務(wù)化掉抛蚤,遠(yuǎn)程調(diào)用,會涉及到網(wǎng)絡(luò)上的問題寻狂。有很多的各式各樣的組件岁经,如:DNS 服務(wù),網(wǎng)卡蛇券、交換機缀壤、路由器、負(fù)載均衡等設(shè)備纠亚,這些設(shè)備都不一定是穩(wěn)定的塘慕,在數(shù)據(jù)傳輸?shù)恼麄€過程中,只要一個環(huán)節(jié)出了問題蒂胞,都會導(dǎo)致問題图呢。

一、重試的場景

" 重試 " 的語義是我們認(rèn)為這個故障是暫時的,而不是永久的蛤织,所以赴叹,我們會去重試

要重試調(diào)用超時指蚜、被調(diào)用端返回了某種可以重試的錯誤(如繁忙中乞巧、流控中、維護(hù)中摊鸡、資源不足等)绽媒。

不要重試業(yè)務(wù)級的錯誤(如沒有權(quán)限、或是非法數(shù)據(jù)等錯誤)免猾,技術(shù)上的錯誤(如:HTTP 的 503 等是辕,這種原因可能是觸發(fā)了代碼的 bug,重試下去沒有意義)掸刊。

二、重試的策略

有個重試的最大值赢乓,經(jīng)過一段時間不斷的重試后忧侧,就沒有必要再重試了,應(yīng)該報故障了牌芋。休息一會兒再重試蚓炬,這樣可以避免因為重試過快而導(dǎo)致網(wǎng)絡(luò)上的負(fù)擔(dān)更重。

1.Exponential Backoff 指數(shù)級退避 :每一次重試所需要的休息時間都會翻倍增加躺屁。讓被調(diào)用方能夠有更多的時間來從容處理我們的請求肯夏。和 TCP 的擁塞控制有點像。

(1)定義一個調(diào)用返回的枚舉類型犀暑,包括 5 種返回錯誤——成功 SUCCESS驯击、維護(hù)中 NOT_READY、流控中 TOO_BUSY耐亏、沒有資源 NO_RESOURCE徊都、系統(tǒng)錯誤 SERVER_ERROR。

public enum Results {

? ? SUCCESS,

? ? NOT_READY,

? ? TOO_BUSY,

? ? NO_RESOURCE,

? ? SERVER_ERROR

}

(2)定義一個 Exponential Backoff 的函數(shù)广辰,其返回 2 的指數(shù)暇矫。這樣,每多一次重試就需要多等一段時間择吊。如:第一次等 200ms李根,第二次要 400ms,第三次要等 800ms……

public static long getWaitTimeExp(int retryCount) {

? ? long waitTime = ((long) Math.pow(2, retryCount) );

? ? return waitTime;

}

(3)真正的重試邏輯几睛。我們可以看到房轿,在成功的情況下,以及不屬于我們定義的錯誤下,我們是不需要重試的冀续,而兩次重試間需要等的時間是以指數(shù)上升的琼讽。

2.Spring 的重試策略

Spring Retry 是專門的一個項目:https://github.com/spring-projects/spring-retry,把 Spring 封裝成了一個組件洪唐,以 AOP 的方式通過 Annotation 的方式使用钻蹬。

@Service

public interface MyService {

? ? @Retryable(

? ? ? value = { SQLException.class },

? ? ? maxAttempts = 2,

? ? ? backoff = @Backoff(delay = 5000))

? ? void retryService(String sql) throws SQLException;

? ? ...

}

配置 @Retryable 注解,只對 SQLException 的異常進(jìn)行重試凭需,重試兩次问欠,每次延時 5000ms。相關(guān)的細(xì)節(jié)可以看相應(yīng)的文檔粒蜈。我在這里顺献,只想讓你看一下 Spring 有哪些重試的策略。

NeverRetryPolicy:只允許調(diào)用 RetryCallback 一次枯怖,不允許重試注整。

AlwaysRetryPolicy:允許無限重試,直到成功度硝,此方式邏輯不當(dāng)會導(dǎo)致死循環(huán)肿轨。

SimpleRetryPolicy:固定次數(shù)重試策略,默認(rèn)重試最大次數(shù)為 3 次蕊程,RetryTemplate 默認(rèn)使用的策略椒袍。

TimeoutRetryPolicy:超時時間重試策略,默認(rèn)超時時間為 1 秒藻茂,在指定的超時時間內(nèi)允許重試驹暑。

CircuitBreakerRetryPolicy:有熔斷功能的重試策略,需設(shè)置 3 個參數(shù) openTimeout辨赐、resetTimeout 和 delegate优俘;關(guān)于熔斷,會在后面描述掀序。

CompositeRetryPolicy:組合重試策略兼吓。有兩種組合方式,樂觀組合重試策略是指只要有一個策略允許重試即可以森枪,悲觀組合重試策略是指只要有一個策略不允許重試即不可以视搏。但不管哪種組合方式,組合中的每一個策略都會執(zhí)行县袱。

Backoff 的策略如下浑娜。

NoBackOffPolicy:無退避算法策略,即當(dāng)重試時是立即重試式散;

FixedBackOffPolicy:固定時間的退避策略筋遭,需設(shè)置參數(shù) sleeper 和 backOffPeriod,sleeper 指定等待策略,默認(rèn)是 Thread.sleep漓滔,即線程休眠编饺,backOffPeriod 指定休眠時間,默認(rèn) 1 秒响驴。

UniformRandomBackOffPolicy:隨機時間退避策略透且,需設(shè)置 sleeper、minBackOffPeriod 和 maxBackOffPeriod豁鲤。該策略在 [minBackOffPeriod, maxBackOffPeriod] 之間取一個隨機休眠時間秽誊,minBackOffPeriod 默認(rèn)為 500 毫秒,maxBackOffPeriod 默認(rèn)為 1500 毫秒琳骡。

ExponentialBackOffPolicy:指數(shù)退避策略锅论,需設(shè)置參數(shù) sleeper、initialInterval楣号、maxInterval 和 multiplier最易。initialInterval 指定初始休眠時間,默認(rèn)為 100 毫秒炫狱。maxInterval 指定最大休眠時間藻懒,默認(rèn)為 30 秒。multiplier 指定乘數(shù)毕荐,即下一次休眠時間為當(dāng)前休眠時間 *multiplier束析。

ExponentialRandomBackOffPolicy:隨機指數(shù)退避策略艳馒,引入隨機乘數(shù)憎亚,之前說過固定乘數(shù)可能會引起很多服務(wù)同時重試導(dǎo)致 DDos,使用隨機休眠時間來避免這種情況弄慰。

三第美、重試設(shè)計的重點

要確定什么樣的錯誤下需要重試;

(1)一些不是很重要的問題時陆爽,應(yīng)該更快失敗而不是重試什往。比如一個前端的交互需要用到后端的服務(wù)。應(yīng)該快速度失敗報錯(比如:網(wǎng)絡(luò)錯誤請重試)慌闭。比如流控别威,應(yīng)該使用指數(shù)退避的方式,避免造成更多的流量驴剔。

(2)如果超過重試次數(shù)省古,或是一段時間,沒有必要再進(jìn)行重試了丧失,新的請求直接返回錯誤就好了豺妓。但如果后端恢復(fù)了不知道,so需要熔斷設(shè)計。

(3)如果沒有冪等的設(shè)計琳拭,那么重試是不安全的训堆,可能會導(dǎo)致一個相同的操作被執(zhí)行多次。

(4)重試的代碼比較通用白嘁,不用侵入到業(yè)務(wù)代碼中坑鱼。有兩個模式。代碼級的权薯,像 Java 那樣可以使用 Annotation 的方式姑躲。另外一種是走 Service Mesh 的方式.

(5)對于有事務(wù)相關(guān)的操作。我們可能會希望能重試成功盟蚣,而不至于走業(yè)務(wù)補償那樣的復(fù)雜的回退流程黍析。對此,需要一個比較長的時間來做重試屎开,需要保存住請求的上下文阐枣,對程序的運行有比較大的開銷,所以把這樣的上下文暫存在本機或是數(shù)據(jù)庫中奄抽,騰出資源來去做別的事蔼两,過一會再回來把之前的請求從存儲中撈出來重試。

你實現(xiàn)過哪些場景下的重試逞度?所采用的策略是什么额划?實現(xiàn)的過程中遇到過哪些坑?

評論1:

重試的場景:

1档泽、服務(wù)timeout超時異常

2俊戳、服務(wù)不存在,配置問題馆匿,服務(wù)流控

3抑胎、對error錯誤不重試,如無權(quán)限渐北、參數(shù)錯誤

重試的策略:

1阿逃、數(shù)據(jù)庫中保存重試需要的上下文,目前通過json來保存赃蛛,指定最大重試次數(shù)恃锉、當(dāng)前重試次數(shù),下次運行時間

重試需要注意的地方:

1呕臂、服務(wù)冪等性破托,在重試時需證調(diào)用服務(wù)的冪等性

2、重試數(shù)據(jù)的監(jiān)控诵闭,郵件炼团,短信及時通知

3澎嚣、重試數(shù)據(jù)的結(jié)轉(zhuǎn),防止表數(shù)據(jù)量過大

評論2:

之前做的重試策略是:異常發(fā)生的時候瘟芝,數(shù)據(jù)庫記錄當(dāng)前上下文易桃,依據(jù)重試次數(shù)來確定重試時間,推送給延遲消息隊列控制重試

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锌俱,一起剝皮案震驚了整個濱河市晤郑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贸宏,老刑警劉巖造寝,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吭练,居然都是意外死亡诫龙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門鲫咽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來签赃,“玉大人,你說我怎么就攤上這事分尸〗趿模” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵箩绍,是天一觀的道長孔庭。 經(jīng)常有香客問我,道長材蛛,這世上最難降的妖魔是什么圆到? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮仰税,結(jié)果婚禮上构资,老公的妹妹穿的比我還像新娘抽诉。我一直安慰自己陨簇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布迹淌。 她就那樣靜靜地躺著河绽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唉窃。 梳的紋絲不亂的頭發(fā)上耙饰,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機與錄音纹份,去河邊找鬼苟跪。 笑死廷痘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的件已。 我是一名探鬼主播笋额,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼篷扩!你這毒婦竟也來了兄猩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鉴未,失蹤者是張志新(化名)和其女友劉穎枢冤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铜秆,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡淹真,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了连茧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趟咆。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖梅屉,靈堂內(nèi)的尸體忽然破棺而出值纱,到底是詐尸還是另有隱情,我是刑警寧澤坯汤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布虐唠,位于F島的核電站,受9級特大地震影響惰聂,放射性物質(zhì)發(fā)生泄漏疆偿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一搓幌、第九天 我趴在偏房一處隱蔽的房頂上張望杆故。 院中可真熱鬧,春花似錦溉愁、人聲如沸处铛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撤蟆。三九已至,卻和暖如春堂污,著一層夾襖步出監(jiān)牢的瞬間家肯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工盟猖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讨衣,地道東北人换棚。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像反镇,于是被迫代替她去往敵國和親圃泡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容