架构杂谈《六》
超時(shí)處理模式
在服務(wù)化或者微服務(wù)架構(gòu)里,傳統(tǒng)的整體應(yīng)用拆分成多個(gè)職責(zé)單一的微服務(wù),微服務(wù)之間通過(guò)某種網(wǎng)絡(luò)通信協(xié)議互相通信和交互,完成特定的功能,然而由于網(wǎng)絡(luò)通信的不穩(wěn)定,在設(shè)計(jì)系統(tǒng)時(shí)必須考慮到對(duì)網(wǎng)絡(luò)通信的容錯(cuò),特別是對(duì)調(diào)用超時(shí)問(wèn)題的處理。
一、微服務(wù)的交互模式
1、同步調(diào)用模式
在同步調(diào)用模式中,服務(wù)A調(diào)用服務(wù)B,服務(wù)A的線程阻塞等待服務(wù)B的處理結(jié)果,如果服務(wù)B一直不返回處理結(jié)果,則服務(wù)A一直處于等待狀態(tài)中一直到超時(shí)為止。
(同步調(diào)用模式圖)
2、接口異步調(diào)用模式
在接口異步調(diào)用模式中,服務(wù)A請(qǐng)求服務(wù)B處理某項(xiàng)任務(wù),服務(wù)B處理完后即刻返回給服務(wù)A處理結(jié)果,如果處理成功,則服務(wù)A繼續(xù)干其他任務(wù),而服務(wù)B異步處理這項(xiàng)任務(wù),直到服務(wù)B處理完這項(xiàng)任務(wù)后,才反向通知服務(wù)A任務(wù)已完成,服務(wù)A再做后續(xù)的工作。
?
(接口異步調(diào)用模式)
接口異步調(diào)用模式適用于非核心鏈路上負(fù)載較高的處理環(huán)節(jié),這個(gè)環(huán)節(jié)經(jīng)常耗時(shí)較長(zhǎng)并且對(duì)時(shí)效性要求不高。
3、消息隊(duì)列異步處理模式
消息隊(duì)列異步處理模式利用消息隊(duì)列作為通信機(jī)制,在這種交互模式中,通常服務(wù)A只需將某種事件傳遞給服務(wù)B,而不需要等待服務(wù)B返回結(jié)果。在這種情況下,服務(wù)A與服務(wù)B可以充分解耦,并且在大規(guī)模、高并發(fā)的微服務(wù)系統(tǒng)中,消息隊(duì)列對(duì)流量具有消峰的功能。
?
(消息隊(duì)列異步處理模式)
消息隊(duì)列異步處理模式與接口異步調(diào)用模式類似,多應(yīng)用于非核心鏈路上負(fù)載較高的處理環(huán)節(jié)中,并且服務(wù)的上游不關(guān)心下游的處理結(jié)果,下游也不需要向上游返回處理結(jié)果。
以上這三種交互模式普遍應(yīng)用于服務(wù)化和微服務(wù)架構(gòu)中,它們之間沒(méi)有絕對(duì)的好壞,只需要在特定場(chǎng)景下做出合適的選擇。
二、同步于異步的抉擇
1、盡量使用異步來(lái)替換同步操作
2、能用同步解決的問(wèn)題,不要引入異步。
第一條原則是從業(yè)務(wù)功能的角度出發(fā)的,業(yè)就是從與用戶或者使用方的交互模式出發(fā)的。如果業(yè)務(wù)邏輯允許,用戶對(duì)產(chǎn)品的交互形態(tài)沒(méi)有異議,則我們可以將一些耗時(shí)較長(zhǎng)的、用戶對(duì)響應(yīng)沒(méi)有特別要求的操作異步化,以此來(lái)減少核心鏈路的層級(jí),釋放系統(tǒng)的壓力。
第二條原則是從技術(shù)和架構(gòu)的角度出發(fā)的,這條原則應(yīng)用的前提是同步能夠解決問(wèn)題,這隱含了一個(gè)含義:如果性能不是問(wèn)題,或者所處理的操作是短小的輕量級(jí)處理邏輯,那么同步調(diào)用方式是最理想不過(guò)的,因?yàn)檫@樣不需要引入異步化的復(fù)雜處理流程。
三、交互模式下超時(shí)問(wèn)題的解決方案
1、同步調(diào)用模式下的解決方案
在同步模式下,對(duì)外的接口會(huì)提供服務(wù)契約,契約定義了服務(wù)的處理結(jié)果會(huì)通過(guò)返回值返回給對(duì)方,對(duì)返回的狀態(tài)定義分為以下兩種:
A)成功和失敗(兩狀態(tài)的同步接口)
B)成功、失敗和處理中(三狀態(tài)的同步接口)
1)兩狀態(tài)的同步接口
服務(wù)契約中只規(guī)定了兩種互斥的狀態(tài):成功和超時(shí),服務(wù)處理結(jié)果必須是成功的或者失敗的。在這種情況下可能發(fā)生兩種同步調(diào)用超時(shí)。
第一種同步調(diào)用超時(shí)發(fā)生在使用方調(diào)用此同步接口的過(guò)程中?
針對(duì)這個(gè)問(wèn)題,我們需要服務(wù)的使用方使用前面架構(gòu)雜談中提到的查詢模式,異步查詢處理結(jié)果,在獲得明確的處理結(jié)果后,得知處理結(jié)果是成功還是失敗,然后做相應(yīng)的處理。如果處理結(jié)果為成功,那么使用方可以繼續(xù)下面的操作;如果結(jié)果為失敗,那么調(diào)用方可以發(fā)起重試,請(qǐng)求再次進(jìn)行處理。然而,這里有一個(gè)問(wèn)題,如果查詢模式的返回狀態(tài)是未知請(qǐng)求,那么在這種情況下使用方超時(shí),服務(wù) 1 實(shí)際上沒(méi)有接收到或者還沒(méi)有接收到一開(kāi)始的處理請(qǐng)求,服務(wù)使用方需要使用同一個(gè)請(qǐng)求 ID 進(jìn)行重試,服務(wù) 1 也必須實(shí)現(xiàn)請(qǐng)求處理的幕等性。
第二種同步調(diào)用超時(shí)發(fā)生在內(nèi)部服務(wù)1調(diào)用服務(wù)2的過(guò)程中
在使用方調(diào)用服務(wù) 1,且服務(wù) 1 接收到請(qǐng)求后,同步調(diào)用服務(wù) 2,由于通信出現(xiàn)了問(wèn)題, 所以服務(wù) 1得到超時(shí)的結(jié)果。這時(shí)服務(wù) 1 應(yīng)該怎么做呢?是重試、取消還是快速失敗?
我們看到上圖的左面服務(wù) 1 對(duì)外接口的契約中包含兩個(gè)返回狀態(tài) :成功或者失敗,也就是對(duì)于使用方來(lái)講,不允許有中間的處理中的狀態(tài),對(duì)于這種服務(wù)內(nèi)部超時(shí)的場(chǎng)景,必須使用快速失敗的策略 :針對(duì)這個(gè)超時(shí)錯(cuò)誤,服務(wù)快速返回失敗,同時(shí)在內(nèi)部調(diào)用服務(wù) 2 的沖正接口,服務(wù) 2 的沖正接口可以判斷之前是否接收到請(qǐng)求,如果接收到請(qǐng)求井做了處理,則應(yīng)該做反向的回攘操作。如果服務(wù) 2 之前沒(méi)有接收到處理請(qǐng)求,則忽略沖正請(qǐng)求,以此來(lái)實(shí)現(xiàn)服務(wù)的幕等性。
2)三狀態(tài)的同步接口
對(duì)于上面的第 2 種定義,服務(wù)契約中規(guī)定了三種處理結(jié)果,狀態(tài)值為:成功、失敗和處理中,對(duì)于超時(shí)等系統(tǒng)錯(cuò)誤的請(qǐng)求,其實(shí)可以認(rèn)為是處理中狀態(tài)的一個(gè)特例,在這種場(chǎng)景的應(yīng)用里,超時(shí)被視為內(nèi)部暫時(shí)的問(wèn)題,隨后可能被修復(fù),因此,可能在一定的時(shí)間窗口內(nèi)告知使用方在處理中,隨后修復(fù)問(wèn)題井補(bǔ)償執(zhí)行,達(dá)到最大化請(qǐng)求處理成功的目標(biāo),不至于讓使用方重試,以提升用戶體驗(yàn) 。
服務(wù)處理結(jié)果可能是成功或者失敗,也可能是處理中,在這種情況下可能發(fā)生兩種同步調(diào)用超時(shí)。
第1種同步調(diào)用超時(shí)發(fā)生在使用方調(diào)用此同步接口過(guò)程中,如下圖所示:
這種場(chǎng)景和兩狀態(tài)同步調(diào)用的接口超時(shí)場(chǎng)景類似,使用方調(diào)用服務(wù) 1 的接口,由于網(wǎng)絡(luò)等原因獲得超時(shí)的結(jié)果,這時(shí)使用方應(yīng)該將超時(shí)看作處理中的一個(gè)特例,使用服務(wù) 1 的查詢接口后續(xù)補(bǔ)齊上一個(gè)請(qǐng)求的處理狀態(tài),可參照兩狀態(tài)同步調(diào)用的接口超時(shí)場(chǎng)景的方案。
第 2 種同步調(diào)用超時(shí)發(fā)生在內(nèi)部服務(wù) l 調(diào)用服務(wù) 2 的過(guò)程中,如下圖所示。
在使用方調(diào)用服務(wù) 1, 且服務(wù) 1 接收到請(qǐng)求后,同步調(diào)用服務(wù) 2,由于通信出現(xiàn)了問(wèn)題,所以服務(wù) l 得到超時(shí)的結(jié)果,這時(shí)服務(wù) 1 又應(yīng)該怎么做呢?
這和兩狀態(tài)同步調(diào)用 的內(nèi)部超時(shí)場(chǎng)景不一樣,兩狀態(tài)設(shè)計(jì)由于與使用方約定了契約,不是成功就是失敗,所以必須在同步調(diào)用時(shí)給予一個(gè)明確的結(jié)果,然而,在三狀態(tài)同步調(diào)用的內(nèi)部超時(shí)場(chǎng)景下,可以返回給使用方一個(gè)中間狀態(tài),也就是處理中的結(jié)果,變相地把同步接口變成異步接口 ,達(dá)到最終一致的效果。
在這種場(chǎng)景下,我們更傾向于給用戶更好的體驗(yàn),盡最大努力成功處理用戶發(fā)來(lái)的請(qǐng)求 。因此,針對(duì)在服務(wù) 1 調(diào)用服務(wù) 2 時(shí)超時(shí),我們會(huì)返回給用戶處理中的狀態(tài),隨后系統(tǒng)盡最大努力補(bǔ)償執(zhí)行出錯(cuò)的部分,服務(wù) 1 需要通過(guò)服務(wù) 2 的查詢接口得到最新的請(qǐng)求處理狀態(tài),如果服務(wù) 2 沒(méi)有明確回復(fù), 則可以嘗試重新發(fā)送請(qǐng)求,當(dāng)然,這里需要服務(wù) 2 也實(shí)現(xiàn)了操作的幕等性 。
2. 異步調(diào)用模式下的解決方案
在異步調(diào)用模式下,對(duì)外的接口也會(huì)提供服務(wù)契約,契約定義了服務(wù)的處理結(jié)果會(huì)通過(guò)返回值返回給使用方,返回的狀態(tài)通常為兩個(gè):處理和未處理。和三狀態(tài)同步調(diào)用接口不同的是異步調(diào)用模式還有異步處理返回結(jié)果的通知,狀態(tài)包括處理成功和處理失敗。
不同階段的網(wǎng)絡(luò)通信產(chǎn)生的超時(shí)和處理方案如下。
1)異步調(diào)用接口超時(shí)
異步調(diào)用接口超時(shí)發(fā)生在使用方調(diào)用服務(wù) 1 的受理接口時(shí),同兩狀態(tài)同步調(diào)用接口超時(shí)及三狀態(tài)同步調(diào)用接口超時(shí)的場(chǎng)景是一樣的,需要通過(guò)查詢來(lái)補(bǔ)齊狀態(tài),并根據(jù)狀態(tài)來(lái)判斷后續(xù)的操作,具體的解決方案參考兩狀態(tài)同步調(diào)用接口超時(shí)和三狀態(tài)同步調(diào)用接口超時(shí)的解決方案。
2)異步調(diào)用內(nèi)部超時(shí)
?
? 異步調(diào)用內(nèi)部超時(shí)發(fā)生在服務(wù) 1 受理了使用方的請(qǐng)求后 ,服務(wù) 1 在處理請(qǐng)求時(shí),在調(diào)用服務(wù) 2 的過(guò)程中超時(shí),這和三狀態(tài)同步調(diào)用內(nèi)部超時(shí)的場(chǎng)景相似,由于異步調(diào)用模式使用的是受理模式,所以一旦受理,我們便應(yīng)該盡最大努力將用戶請(qǐng)求的操作處理成功,因此,在服務(wù) 1 調(diào)用服務(wù) 2 超時(shí)的場(chǎng)景下,服務(wù) 1需要根據(jù)服務(wù) 2 的查詢接口獲得最新?tīng)顟B(tài),根據(jù)狀態(tài)補(bǔ)償后續(xù)的操作,這和三狀態(tài)同步調(diào)用內(nèi)部超時(shí)的解決方案一致,不同的是此場(chǎng)景下一旦處理成功,則需要異步回調(diào)通知使用方,而在三狀態(tài)同步調(diào)用內(nèi)部超時(shí)的場(chǎng)景下,只需要等待使用方查詢,不需要通知,也無(wú)法實(shí)現(xiàn)通知。
3)異步調(diào)用回調(diào)超時(shí)
?
? 回調(diào)超時(shí)的問(wèn)題在生產(chǎn)中經(jīng)常出現(xiàn),通常發(fā)生于這樣的場(chǎng)景下:服務(wù) 1 受理后成功地調(diào)用了依賴服務(wù) 2,獲得了明確的處理結(jié)果,但是在將處理結(jié)果通知使用方時(shí)出現(xiàn)超時(shí)。由于使用方有可能是公司內(nèi)部的也可能是外部的 ,網(wǎng)絡(luò)環(huán)境復(fù)雜多變,發(fā)生超時(shí)的概率很大,因此,大多數(shù)公司都會(huì)開(kāi)發(fā)一個(gè)通知子系統(tǒng),用來(lái)專門處理回調(diào)通知。
由于服務(wù) 1通過(guò)回調(diào)通知使用方,所以服務(wù) 1需要保證通知一定可送達(dá),如果遇到超時(shí),則服務(wù) 1 負(fù)責(zé)重新繼續(xù)補(bǔ)償,通常會(huì)設(shè)計(jì)一個(gè)通知時(shí)間按一定間隔遞增的策略,例如 :指數(shù)回退,直到通知成功為止,通知是否成功以對(duì)方的回寫狀態(tài)為準(zhǔn)。
3、消息隊(duì)列異步處理模式的解決方案?
消息隊(duì)列異步處理模式多用于疏松禍合的項(xiàng)目,這些項(xiàng)目通常是在主流程中無(wú)法處理耗時(shí)的任務(wù),恰好耗時(shí)的任務(wù)又不是核心流程的一部分,比如 :電商平臺(tái)的物流、配送等。
這類交互使用消息隊(duì)列進(jìn)行解耦,電商交易系統(tǒng)成功處理交易后,需要發(fā)送消息到消息隊(duì)列服務(wù)器,后續(xù)的流程由物流平臺(tái)處理,也不需要將處理結(jié)果反饋給交易平臺(tái)。
使用消息隊(duì)列解耦后,處理流程被分為兩個(gè)階段:生產(chǎn)者投遞和消費(fèi)者處理,在不同的階段會(huì)產(chǎn)生不同的超時(shí)問(wèn)題,解決方案如下。
1)消息隊(duì)列的生產(chǎn)者超時(shí)
2)消息隊(duì)列的消費(fèi)者超時(shí)
對(duì)于消息隊(duì)列的處理機(jī)與消息隊(duì)列之間的超時(shí)或者網(wǎng)絡(luò)問(wèn)題,通常可以通過(guò)消息隊(duì)列提供的機(jī)制來(lái)解決。
一般消息隊(duì)列會(huì)提供如下兩種方式來(lái)消費(fèi)消息。
1)、自動(dòng)增長(zhǎng)消費(fèi)的偏移量:在一個(gè)消費(fèi)者從消息服務(wù)器中取走消息后,消息隊(duì)列的消息偏移量自動(dòng)增加,即消息一旦被從消息隊(duì)列中取走,則不再存在于服務(wù)器中,假如消息處理機(jī)對(duì)此消息處理失敗,則也無(wú)法從消息服務(wù)器中找回。
2)、手工提交消費(fèi)的偏移量 :在一個(gè)消費(fèi)者從消息服務(wù)器中取走消息后,處理機(jī)先把消息持久到本地?cái)?shù)據(jù)庫(kù)中,然后告訴消息服務(wù)器己經(jīng)消費(fèi)消息,消息服務(wù)器才會(huì)移除消息,如果在沒(méi)有告訴消息服務(wù)器己經(jīng)消費(fèi)消息之前,持久失敗或者發(fā)生了其他問(wèn)題,則消息仍然存在于消息服務(wù)器中,消息處理器下次還可以繼續(xù)消費(fèi)消息。
如果允許丟消息,則我們使用第1種處理方式,這種方式的并發(fā)量高、性能好,但是如果我們對(duì)消息處理的準(zhǔn)確性要求較高,則必須采用第 2 種方式。
?四、超時(shí)補(bǔ)償?shù)脑瓌t
1)服務(wù)1調(diào)用服務(wù)2,如果服務(wù)2響應(yīng)服務(wù)1并且告訴服務(wù)1消息己接收,那么服務(wù)1的任務(wù)就結(jié)束了;如果服務(wù)2處理失敗,那么服務(wù)2應(yīng)該負(fù)責(zé)重試或者補(bǔ)償。在這種情況下,服務(wù)2通常接收消息后先持久再告訴服務(wù)1接收成功,隨后服務(wù)2才開(kāi)始處理持久的消息,避免服務(wù)進(jìn)程被殺掉而導(dǎo)致消息丟失。
2)服務(wù)1調(diào)用服務(wù)2,如果服務(wù)2沒(méi)有給出明確的接收響應(yīng),例如網(wǎng)絡(luò)超時(shí),那么服務(wù)1應(yīng)該持續(xù)進(jìn)行重試,直到服務(wù)2明確表示己經(jīng)接收消息。在這種情況下容易出現(xiàn)重復(fù)的消息,因此在服務(wù)2中通常要保證濾重或者幕等性。
說(shuō)明:
1、參考書籍:《分布式服務(wù)架構(gòu):原理、設(shè)計(jì)與實(shí)戰(zhàn)》
2、如有不合適的地方請(qǐng)反饋。綜合后更改。
總結(jié)
- 上一篇: WTM 构建DotNetCore开源生
- 下一篇: 基于surging 的stage组件设计