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