Go微服務(wù)架構(gòu)實戰(zhàn)-【公粽號:堆棧future】
1. 微服務(wù)架構(gòu)上篇
1. grpc技術(shù)介紹
2. grpc+protobuf+網(wǎng)關(guān)實戰(zhàn)
3. etcd技術(shù)介紹
4. 基于etcd的服務(wù)發(fā)現(xiàn)與注冊
5. 基于etcd的分布式鎖實戰(zhàn)
2. 微服務(wù)架構(gòu)中篇
5. 基于ingress和service實現(xiàn)灰度發(fā)布
6. 常見的服務(wù)治理策略
干貨:
服務(wù)容錯: 故障轉(zhuǎn)移/快速失敗/故障恢復(fù)等
流量控制:滑動時間窗口/令牌桶/分布式限流等
1. 服務(wù)容錯
通過一張圖一目了然:容錯設(shè)計模式:
1. 斷路器模式
斷路器的基本思路是很簡單的谒拴,就是通過代理(斷路器對象)來一對一地(一個遠程服務(wù)對應(yīng)一個斷路器對象)接管服務(wù)調(diào)用者的遠程請求逗概。斷路器會持續(xù)監(jiān)控并統(tǒng)計服務(wù)返回的成功榜揖、失敗、超時、拒絕等各種結(jié)果兜粘,當(dāng)出現(xiàn)故障(失敗构挤、超時散吵、拒絕)的次數(shù)達到斷路器的閾值時耽装,它狀態(tài)就自動變?yōu)椤癘PEN”愤炸,后續(xù)此斷路器代理的遠程訪問都將直接返回調(diào)用失敗,而不會發(fā)出真正的遠程服務(wù)請求掉奄。通過斷路器對遠程服務(wù)的熔斷丸升,避免因持續(xù)的失敗或拒絕而消耗資源瘾晃,因持續(xù)的超時而堆積請求,最終的目的就是避免雪崩效應(yīng)的出現(xiàn)。由此可見爷绘,斷路器本質(zhì)是一種快速失敗策略的實現(xiàn)方式,它的工作過程可以通過下面圖來表示:從調(diào)用序列來看价淌,斷路器就是一種有限狀態(tài)機淤齐,斷路器模式就是根據(jù)自身狀態(tài)變化自動調(diào)整代理請求策略的過程。一般要設(shè)置以下三種斷路器的狀態(tài):
- CLOSED:表示斷路器關(guān)閉憨栽,此時的遠程請求會真正發(fā)送給服務(wù)提供者帜矾。斷路器剛剛建立時默認處于這種狀態(tài),此后將持續(xù)監(jiān)視遠程請求的數(shù)量和執(zhí)行結(jié)果屑柔,決定是否要進入 OPEN 狀態(tài)屡萤。
- OPEN:表示斷路器開啟,此時不會進行遠程請求掸宛,直接給服務(wù)調(diào)用者返回調(diào)用失敗的信息死陆,以實現(xiàn)快速失敗策略。
- HALF OPEN:這是一種中間狀態(tài)唧瘾。斷路器必須帶有自動的故障恢復(fù)能力措译,當(dāng)進入 OPEN 狀態(tài)一段時間以后,將“自動”(一般是由下一次請求而不是計時器觸發(fā)的饰序,所以這里自動帶引號)切換到 HALF OPEN 狀態(tài)领虹。該狀態(tài)下,會放行一次遠程調(diào)用求豫,然后根據(jù)這次調(diào)用的結(jié)果成功與否塌衰,轉(zhuǎn)換為 CLOSED 或者 OPEN 狀態(tài),以實現(xiàn)斷路器的彈性恢復(fù)蝠嘉。
OPEN 和 CLOSED 狀態(tài)的含義是十分清晰的最疆,與我們?nèi)粘I钪须娐返臄嗦菲鞑]有什么差別,值得討論的是這兩者的轉(zhuǎn)換條件是什么蚤告?最簡單直接的方案是只要遇到一次調(diào)用失敗努酸,那就默認以后所有的調(diào)用都會接著失敗,斷路器直接進入 OPEN 狀態(tài)杜恰,但這樣做的效果是很差的获诈,雖然避免了故障擴散和請求堆積仍源,卻使得外部看來系統(tǒng)將表現(xiàn)極其不穩(wěn)定。現(xiàn)實中烙荷,比較可行的辦法是在以下兩個條件同時滿足時镜会,斷路器狀態(tài)轉(zhuǎn)變?yōu)?OPEN:
- 一段時間(譬如 10 秒以內(nèi))內(nèi)請求數(shù)量達到一定閾值(譬如 20 個請求)。這個條件的意思是如果請求本身就很少终抽,那就用不著斷路器介入戳表。
- 一段時間(譬如 10 秒以內(nèi))內(nèi)請求的故障率(發(fā)生失敗、超時昼伴、拒絕的統(tǒng)計比例)到達一定閾值(譬如 50%)匾旭。這個條件的意思是如果請求本身都能正確返回,也用不著斷路器介入圃郊。
以上兩個條件同時滿足時价涝,斷路器就會轉(zhuǎn)變?yōu)?OPEN 狀態(tài)。
斷路器做的事情是自動進行服務(wù)熔斷持舆,這是一種快速失敗的容錯策略的實現(xiàn)方法色瘩,也是一種典型的服務(wù)降級策略。舉個例子:你女朋友被前男友約出去了逸寓,你打她手機沒人接居兆,你氣沖沖地的掛斷后(快速失敗)竹伸,然后你有打了另外三個你女朋友閨蜜的手機號(故障轉(zhuǎn)移)泥栖,都還是沒能找到你女朋友(重試超過閾值)。這時候你非常生氣地在微信上給她留言“三分鐘不回電話就分手”勋篓,以此來與你取得聯(lián)系吧享。原諒我這么舉例,雖然不太吉利譬嚣,但是你給你女朋友留言這個行為便是服務(wù)降級邏輯钢颂。
其他服務(wù)治理的工具,譬如Envoy
拜银、istio
等也同樣會包含有類似的設(shè)置殊鞭。
2. 重試模式
重試模式適合解決系統(tǒng)中的瞬時故障,簡單的說就是有可能自己恢復(fù)(Resilient盐股,稱為自愈钱豁,也叫做回彈性)的臨時性失靈耻卡,網(wǎng)絡(luò)抖動疯汁、服務(wù)的臨時過載(典型的如返回了 503 Bad Gateway 錯誤)這些都屬于瞬時故障。重試模式實現(xiàn)并不困難卵酪,即使完全不考慮框架的支持幌蚊,靠程序員自己編寫十幾行代碼也能夠完成谤碳。在實踐中,重試模式面臨的風(fēng)險反而大多來源于太過簡單而導(dǎo)致的濫用溢豆。我們判斷是否應(yīng)該且是否能夠?qū)σ粋€服務(wù)進行重試時蜒简,應(yīng)同時滿足以下幾個前提條件:
僅在主路邏輯的關(guān)鍵服務(wù)上進行同步的重試,不是關(guān)鍵的服務(wù)漩仙,一般不把重試作為首選容錯方案搓茬,尤其不該進行同步重試。
僅對具備冪等性的服務(wù)進行重試队他。
重試必須有明確的終止條件卷仑,常用的終止條件有兩種:
- 超時終止
- 次數(shù)終止
由于重試模式可以在網(wǎng)絡(luò)鏈路的多個環(huán)節(jié)中去實現(xiàn),比如客戶端發(fā)起調(diào)用時自動重試麸折,網(wǎng)關(guān)中自動重試锡凝、負載均衡器中自動重試,等等垢啼,而且現(xiàn)在的微服務(wù)框架都足夠便捷窜锯,只需設(shè)置一兩個開關(guān)參數(shù)就可以開啟對某個服務(wù)甚至全部服務(wù)的重試機制。
2. 流量控制
與容錯模式類似芭析,對于如何進行限流锚扎,也有一些常見的設(shè)計模式可以參考使用,本節(jié)將介紹滑動時間窗放刨、令牌桶以及分布式限流三種限流設(shè)計模式工秩。
1. 滑動時間窗口
有一個滑動時間窗口算法,在計算機科學(xué)的很多領(lǐng)域中都有成功的應(yīng)用进统,比如著名的TCP協(xié)議的流量控制等都是使用這個算法實現(xiàn)流控的助币。具體實現(xiàn)大概可以想象下就是在不斷向前流淌的時間軸上,漂浮著一個固定大小的窗口螟碎,窗口與時間一起平滑地向前滾動眉菱。任何時刻靜態(tài)地通過窗口內(nèi)觀察到的信息,都等價于一段長度與窗口大小相等掉分、動態(tài)流動中時間片段的信息俭缓。由于窗口觀察的目標都是時間軸,所以它被稱為形象地稱為“滑動時間窗模式”酥郭。
滑動時間窗口模式可以保證任意時間片段內(nèi)华坦,只需經(jīng)過簡單的調(diào)用計數(shù)比較,就能控制住請求次數(shù)一定不會超過限流的閾值不从,在單機限流或者分布式服務(wù)單點網(wǎng)關(guān)中的限流中很常用惜姐。不過,這種限流也有其缺點,它通常只適用于否決式限流歹袁,超過閾值的流量就必須強制失敗或降級坷衍,很難進行阻塞等待處理,也就很難在細粒度上對流量曲線進行整形条舔,起不到削峰填谷的作用
枫耳。
2. 令牌桶
假設(shè)我們要限制系統(tǒng)在 X 秒內(nèi)最大請求次數(shù)不超過 Y,那就每間隔 X/Y 時間就往桶中放一個令牌孟抗,當(dāng)有請求進來時迁杨,首先要從桶中取得一個準入的令牌,然后才能進入系統(tǒng)處理凄硼。任何時候仑最,一旦請求進入桶中卻發(fā)現(xiàn)沒有令牌可取了,就應(yīng)該馬上失敗或進入服務(wù)降級邏輯帆喇。與此同時令牌桶也有最大容量限制警医,這意味著當(dāng)系統(tǒng)比較空閑時,桶中令牌累積到一定程度就不再無限增加坯钦,預(yù)存在桶中的令牌便是請求最大緩沖的余量预皇。上面這段話,可以轉(zhuǎn)化為以下步驟:
- 讓系統(tǒng)以一個由限流目標決定的速率向桶中注入令牌婉刀,比如要控制系統(tǒng)的訪問不超過 100 次吟温,速率即設(shè)定為 1/100=10 毫秒。
- 桶中最多可以存放 N 個令牌突颊,N 的具體數(shù)量是由超時時間和服務(wù)處理能力共同決定的鲁豪。如果桶已滿,第 N+1 個進入的令牌會被丟棄掉律秃。
- 請求到時先從桶中取走 1 個令牌爬橡,如果桶已空就進入降級邏輯。
桶:bucket 速率:rate
令牌桶模式的實現(xiàn)看似比較復(fù)雜棒动,每間隔固定時間就要放新的令牌到桶中糙申,但其實并不需要真的用一個專用線程或者定時器來做這件事情,只要在令牌中增加一個時間戳記錄船惨,每次獲取令牌前柜裸,比較一下時間戳與當(dāng)前時間,就可以輕易計算出這段時間需要放多少令牌進去粱锐,然后一次性放入即可疙挺,所以真正編碼并不會顯得很復(fù)雜。
3. 分布式限流
一種常見的簡單分布式限流方法是將所有服務(wù)的統(tǒng)計結(jié)果都存入集中式緩存(如 Redis)中怜浅,以實現(xiàn)在集群內(nèi)的共享铐然,并通過分布式鎖、信號量等機制,解決這些數(shù)據(jù)的讀寫訪問時并發(fā)控制的問題锦爵。在可以共享統(tǒng)計數(shù)據(jù)的前提下,原本用于單機的限流模式理論上也是可以應(yīng)用于分布式環(huán)境中的奥裸,可是其代價也顯而易見:每次服務(wù)調(diào)用都必須要額外增加一次網(wǎng)絡(luò)開銷险掀,所以這種方法的效率肯定是不高的,流量壓力大時湾宙,限流本身反倒會顯著降低系統(tǒng)的處理能力樟氢。
anyway,出現(xiàn)問題解決它就好了侠鳄,但是你不能因為它一兩個缺點就不用埠啃,我覺得這不是一個程序員良好的做事風(fēng)格,能扛事的人一般都是能成大事的人伟恶。
3. 小結(jié)
服務(wù)治理的話題隨便拿出一個來研究就能讓你增長不少見識碴开,所以說大家下去有時間可以專門研究下相關(guān)的服務(wù)或者產(chǎn)品,比如我們提到的envoy以及istio等博秫,看下它們是如何做到全部或者部分治理的潦牛,博采眾長,才能脫胎換骨挡育,加油巴碗。