你了解微服務(wù)的超時(shí)傳遞嗎?

為什么需要超時(shí)控制鲸鹦?

很多連鎖故障的場(chǎng)景下的一個(gè)常見問題是服務(wù)器正在消耗大量資源處理那些早已經(jīng)超過客戶端截止時(shí)間的請(qǐng)求慧库,這樣的結(jié)果是,服務(wù)器消耗大量資源沒有做任何有價(jià)值的工作馋嗜,回復(fù)已經(jīng)超時(shí)的請(qǐng)求是沒有任何意義的齐板。

超時(shí)控制可以說是保證服務(wù)穩(wěn)定性的一道重要的防線,它的本質(zhì)是快速失敗(fail fast)嵌戈,良好的超時(shí)控制策略可以盡快清空高延遲的請(qǐng)求覆积,盡快釋放資源避免請(qǐng)求的堆積。

服務(wù)間超時(shí)傳遞

如果一個(gè)請(qǐng)求有多個(gè)階段熟呛,比如由一系列 RPC 調(diào)用組成宽档,那么我們的服務(wù)應(yīng)該在每個(gè)階段開始前檢查截止時(shí)間以避免做無用功,也就是要檢查是否還有足夠的剩余時(shí)間處理請(qǐng)求庵朝。

一個(gè)常見的錯(cuò)誤實(shí)現(xiàn)方式是在每個(gè) RPC 服務(wù)設(shè)置一個(gè)固定的超時(shí)時(shí)間吗冤,我們應(yīng)該在每個(gè)服務(wù)間傳遞超時(shí)時(shí)間,超時(shí)時(shí)間可以在服務(wù)調(diào)用的最上層設(shè)置九府,由初始請(qǐng)求觸發(fā)的整個(gè) RPC 樹會(huì)設(shè)置同樣的絕對(duì)截止時(shí)間椎瘟。例如,在服務(wù)請(qǐng)求的最上層設(shè)置超時(shí)時(shí)間為3s侄旬,服務(wù)A請(qǐng)求服務(wù)B肺蔚,服務(wù)B執(zhí)行耗時(shí)為1s,服務(wù)B再請(qǐng)求服務(wù)C這時(shí)超時(shí)時(shí)間剩余2s儡羔,服務(wù)C執(zhí)行耗時(shí)為1s宣羊,這時(shí)服務(wù)C再請(qǐng)求服務(wù)D璧诵,服務(wù)D執(zhí)行耗時(shí)為500ms,以此類推仇冯,理想情況下在整個(gè)調(diào)用鏈里都采用相同的超時(shí)傳遞機(jī)制之宿。

image

如果不采用超時(shí)傳遞機(jī)制,那么就會(huì)出現(xiàn)如下情況:

  1. 服務(wù)A給服務(wù)B發(fā)送一個(gè)請(qǐng)求苛坚,設(shè)置的超時(shí)時(shí)間為3s
  2. 服務(wù)B處理請(qǐng)求耗時(shí)為2s比被,并且繼續(xù)請(qǐng)求服務(wù)C
  3. 如果使用了超時(shí)傳遞那么服務(wù)C的超時(shí)時(shí)間應(yīng)該為1s,但這里沒有采用超時(shí)傳遞所以超時(shí)時(shí)間為在配置中寫死的3s
  4. 服務(wù)C繼續(xù)執(zhí)行耗時(shí)為2s泼舱,其實(shí)這時(shí)候最上層設(shè)置的超時(shí)時(shí)間已截止等缀,如下的請(qǐng)求無意義
  5. 繼續(xù)請(qǐng)求服務(wù)D

如果服務(wù)B采用了超時(shí)傳遞機(jī)制,那么在服務(wù)C就應(yīng)該立刻放棄該請(qǐng)求柠掂,因?yàn)橐呀?jīng)到了截止時(shí)間项滑,客戶端可能已經(jīng)報(bào)錯(cuò)。我們?cè)谠O(shè)置超時(shí)傳遞的時(shí)候一般會(huì)將傳遞出去的截止時(shí)間減少一點(diǎn)涯贞,比如100毫秒枪狂,以便將網(wǎng)絡(luò)傳輸時(shí)間和客戶端收到回復(fù)之后的處理時(shí)間考慮在內(nèi)。

進(jìn)程內(nèi)超時(shí)傳遞

不光服務(wù)間需要超時(shí)傳遞進(jìn)程內(nèi)同樣需要進(jìn)行超時(shí)傳遞宋渔,比如在一個(gè)進(jìn)程內(nèi)串行的調(diào)用了Mysql州疾、Redis和服務(wù)B,設(shè)置總的請(qǐng)求時(shí)間為3s皇拣,請(qǐng)求Mysql耗時(shí)1s后再次請(qǐng)求Redis這時(shí)的超時(shí)時(shí)間為2s严蓖,Redis執(zhí)行耗時(shí)500ms再請(qǐng)求服務(wù)B這時(shí)候超時(shí)時(shí)間為1.5s,因?yàn)槲覀兊拿總€(gè)中間件或者服務(wù)都會(huì)在配置文件中設(shè)置一個(gè)固定的超時(shí)時(shí)間氧急,我們需要取剩余時(shí)間和設(shè)置時(shí)間中的最小值颗胡。

image

context實(shí)現(xiàn)超時(shí)傳遞

context原理非常簡(jiǎn)單,但功能卻非常強(qiáng)大吩坝,go的標(biāo)準(zhǔn)庫也都已實(shí)現(xiàn)了對(duì)context的支持毒姨,各種開源的框架也實(shí)現(xiàn)了對(duì)context的支持,context已然成為了標(biāo)準(zhǔn)钉寝,超時(shí)傳遞也依賴context來實(shí)現(xiàn)弧呐。

我們一般在服務(wù)的最上層通過設(shè)置初始context進(jìn)行超時(shí)控制傳遞,比如設(shè)置超時(shí)時(shí)間為3s

ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

當(dāng)進(jìn)行context傳遞的時(shí)候嵌纲,比如上圖中請(qǐng)求Redis俘枫,那么通過如下方式獲取剩余時(shí)間,然后對(duì)比Redis設(shè)置的超時(shí)時(shí)間取較小的時(shí)間

dl, ok := ctx.Deadline()
timeout := time.Now().Add(time.Second * 3)
if ok := dl.Before(timeout); ok {
    timeout = dl
}

服務(wù)間超時(shí)傳遞主要是指 RPC 調(diào)用時(shí)候的超時(shí)傳遞逮走,對(duì)于 gRPC 來說并不需要要我們做額外的處理鸠蚪,gRPC 本身就支持超時(shí)傳遞,原理和上面差不多,是通過 metadata 進(jìn)行傳遞邓嘹,最終會(huì)被轉(zhuǎn)化為 grpc-timeout 的值酣栈,如下代碼所示 grpc-go/internal/transport/handler_server.go:79

if v := r.Header.Get("grpc-timeout"); v != "" {
        to, err := decodeTimeout(v)
        if err != nil {
            return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err)
        }
        st.timeoutSet = true
        st.timeout = to
}

超時(shí)傳遞是保證服務(wù)穩(wěn)定性的一道重要防線,原理和實(shí)現(xiàn)都非常簡(jiǎn)單汹押,你們的框架中實(shí)現(xiàn)了超時(shí)傳遞了嗎?如果沒有的話就趕緊動(dòng)起手來吧起便。

go-zero 中的超時(shí)傳遞

go-zero 中可以通過配置文件中的 Timeout 配置 api gatewayrpc 服務(wù)的超時(shí)棚贾,并且會(huì)在服務(wù)間自動(dòng)傳遞。

之前的 一文搞懂如何實(shí)現(xiàn) Go 超時(shí)控制 里面有講解超時(shí)控制如何使用榆综。

參考

《SRE:Google運(yùn)維解密》

項(xiàng)目地址

https://github.com/zeromicro/go-zero

歡迎使用 go-zerostar/fork 支持我們妙痹!

微信交流群

關(guān)注『微服務(wù)實(shí)踐』公眾號(hào)并點(diǎn)擊 交流群 獲取社區(qū)群二維碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鼻疮,一起剝皮案震驚了整個(gè)濱河市怯伊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌判沟,老刑警劉巖耿芹,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異挪哄,居然都是意外死亡吧秕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門迹炼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砸彬,“玉大人,你說我怎么就攤上這事斯入∩暗铮” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵刻两,是天一觀的道長增蹭。 經(jīng)常有香客問我,道長闹伪,這世上最難降的妖魔是什么沪铭? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮偏瓤,結(jié)果婚禮上杀怠,老公的妹妹穿的比我還像新娘。我一直安慰自己厅克,他們只是感情好赔退,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般硕旗。 火紅的嫁衣襯著肌膚如雪窗骑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天漆枚,我揣著相機(jī)與錄音创译,去河邊找鬼。 笑死墙基,一個(gè)胖子當(dāng)著我的面吹牛软族,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播残制,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼立砸,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了初茶?” 一聲冷哼從身側(cè)響起颗祝,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恼布,沒想到半個(gè)月后螺戳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桥氏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年温峭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片字支。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凤藏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出堕伪,到底是詐尸還是另有隱情揖庄,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布欠雌,位于F島的核電站蹄梢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏富俄。R本人自食惡果不足惜禁炒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望霍比。 院中可真熱鬧幕袱,春花似錦、人聲如沸悠瞬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至望迎,卻和暖如春障癌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辩尊。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工涛浙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摄欲。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓蝗拿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒿涎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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