Go可用性(七) 總結(jié): 一張圖串聯(lián)可用性知識點
在前面的幾篇文章當(dāng)中我們聊到了 隔離設(shè)計、令牌桶算法、漏桶算法、自適應(yīng)限流和熔斷,可用性的建設(shè)遠不止這些,這一部分的內(nèi)容在進階訓(xùn)練營中也講了 7 個小時,其他部分如果感興趣的話推薦購買源課程觀看。
由于前面的文章大部分都在講限流相關(guān)的內(nèi)容,所以我們先看一下不同的限流方式的對比
限流對比
微服務(wù)可用性設(shè)計總結(jié)
接下來我們就一起來串聯(lián)我們之前講到的和課程上講到的一些內(nèi)容總結(jié)一下可用性應(yīng)該怎么做。
微服務(wù)可用性設(shè)計總結(jié)
如上圖所示,我們從一個簡單的用戶訪問出發(fā),用戶訪問到我們的服務(wù)一般是先通過我們的移動客戶端或者是瀏覽器,然后請求再依次通過 CDN、防火墻、API網(wǎng)關(guān)、BFF以及各個后端服務(wù),整條鏈路還是比較長的。
我們上圖其實已經(jīng)一部分體現(xiàn)了隔離設(shè)計,所以后面我就不再提了。
1. 移動客戶端/瀏覽器
客戶端是觸及用戶的第一線,所以這一層做的可用性優(yōu)化尤為的重要
降級: 降級的本質(zhì)是提供給用戶有損服務(wù),所以在觸及用戶的第一線如何安撫好或者說如何騙過用戶的眼睛尤為重要
- 本地緩存,客戶端需要有一些本地緩存數(shù)據(jù),不僅可以加速用戶首屏的加載時間,還可以在后端服務(wù)出現(xiàn)故障的時候起到一定的緩沖作用
- 降級數(shù)據(jù)兼容,服務(wù)端有時為了降級會返回一些 mock 數(shù)據(jù)或者是空數(shù)據(jù),這些數(shù)據(jù)一定要和客戶端的對接好,如果沒有對接好很容易就會出現(xiàn)異?;蛘呤前灼?/li>
流控: 在服務(wù)出現(xiàn)問題的時候,用戶總是會不斷的主動嘗試重試,如果不加以限制會讓我們本就不堪重負的后端服務(wù)雪上加霜
- 所以在客戶端需要做類似熔斷的流控措施,常見的思路有指數(shù)級退讓,或者是通過服務(wù)端的返回獲取冷卻的時間
2. BFF/Client
BFF 是我們后端服務(wù)的橋頭堡,當(dāng)請求來到 BFF 層的時候,BFF 既是服務(wù)端,又是客戶端,因為它一般需要請求很多其他的后端服務(wù)來完成數(shù)據(jù)的編排,提供客戶端想要的數(shù)據(jù)
超時控制: 超時控制需要注意的兩點是默認值和超時傳遞
- 默認值,基礎(chǔ)庫需要有一些默認值,避免客戶端用戶漏填,錯填,舉個例子,如果開發(fā)填寫一個明顯過大的值 100s 才超時,這時候我們基礎(chǔ)庫可以直接拋出錯誤,或者是警告只有手動忽略才可以正常啟動。我之前有一個應(yīng)用就是因為忘記配置超時時間,依賴的服務(wù) hang 住導(dǎo)致我的服務(wù)也無法正常服務(wù)了,即使我之前做了緩存也沒有用,因為之前的邏輯是只有請求報錯才會降級使用緩存數(shù)據(jù)。
- 超時傳遞,例如我們上圖,假設(shè)我們整個請求的超時時間配置的 500ms,BFF 里面首先經(jīng)過一些邏輯判斷消耗了 100ms,然后去請求 redis,我們給 redis 配置的超時時間 max_con 是 500ms,這時候就不能用 500ms 作為超時時間,得用 min(請求剩余的超時時間,max_con)也就是 400ms 作為我們的超時時間,同樣我們請求下游的服務(wù)也需要將超時時間攜帶到 header 信息里面,這樣下游服務(wù)就可以繼承上游的超時時間來進行超時判斷。
負載均衡: 一般我們比較常用的負載均衡策略就是輪訓(xùn),或者說加個權(quán)重,這個比較大的問題就是,我們的服務(wù)性能并不是每個實例都一樣,收到宿主機的型號,當(dāng)前機器上服務(wù)的數(shù)量等等因素的影響,并且由于我們的服務(wù)是在隨時漂移和變化的,所以我們沒有辦法為每個實例配上合適的權(quán)重。
- 所以我們可以根據(jù)一些統(tǒng)計數(shù)據(jù),例如 cpu、load 等信息獲取當(dāng)前服務(wù)的負載情況,然后根據(jù)不同的負載情況進行打分,然后來進行流量的分配,這樣就可以將我們的流量比較合理的分配到各個實例上了。
重試: 重試一定要注意避免雪崩
- 當(dāng)我們的服務(wù)出現(xiàn)一些錯誤的時候,我們可以通過重試來解決,例如如果部分實例過載導(dǎo)致請求很慢,我們通過重試,加上面的負載均衡可以將請求發(fā)送到正常的實例,這樣可以提高我們的 SLA
- 但是需要的注意的是,重試只能在錯誤發(fā)生的地方進行重試,不能級聯(lián)重試,級聯(lián)重試很容易造成雪崩,一般的做法就是約定一個 code 只要出現(xiàn)這個 code 我們就知道下游已經(jīng)嘗試過重試了,我們就不要再重試了
熔斷: 一般來說如果只是部分實例出現(xiàn)了問題,我們通過負載均衡階段+重試一般就可以解決,但如果服務(wù)整體出現(xiàn)了問題,作為客戶端就需要使用熔斷的措施了。
- 熔斷常見的有開啟,關(guān)閉,半開啟的狀態(tài),例如 hystrix-go 的實現(xiàn),但是這種方式比較死板,只要觸發(fā)了熔斷就一個請求都無法放過,所以就又學(xué)習(xí)了 Google SRE 的做法,同構(gòu)計算概率來進行判斷,沒有了半開啟的狀態(tài),開啟的時候也不會說是一刀切。
降級: 當(dāng)我們請求一些不那么重要的服務(wù)出現(xiàn)錯誤時,我們可以通過降級的方式來返回請求,降級一般在 BFF 層做,可以有效的防止污染其他服務(wù)的緩存。常見的討論有返回 mock 數(shù)據(jù),緩存數(shù)據(jù),空數(shù)據(jù)等
3. Server
BFF 其實也是服務(wù)端,但是為了流暢的講解,主要將其作為了客戶端的角色。服務(wù)端主要的是限流的措施,當(dāng)流量從 BFF 來到我們的服務(wù)之后,我們會使用令牌桶算法嘗試獲取 token,如果 token 不夠就丟棄,如果 token 足夠就完成請求邏輯。
我們的 token 是從哪里來的呢?
攔截器會定時的向 Token Server 上報心跳數(shù)據(jù),包含了一些統(tǒng)計信息,同時從 Token Server 獲取一定數(shù)量的 Token,當(dāng) Token Server 接收到請求之后會通過最大最小公平分享的算法,根據(jù)每個服務(wù)實例上報的統(tǒng)計信息進行 Token 的分配。
這個其實就是之前沒有講到的分布式限流的思路,在單個服務(wù)實例上又使用了單機限流的算法
總結(jié)
到這里我們的可用性相關(guān)的知識點就算是告一段落了,前面的文章主要講解了限流的相關(guān)知識點,雖然其他的沒有細說,但是這一篇總結(jié)也算是都涉及到了,包括隔離設(shè)計、限流(單機限流、自適應(yīng)限流、分布式限流)、超時控制、降級、熔斷、負載均衡、重試。OK,話不多說,我們下篇文章見。
本文轉(zhuǎn)載自微信公眾號「mohuishou」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系mohuishou公眾號。