微服務(wù)體系下的服務(wù)治理

一别垮、 前言

微服務(wù)架構(gòu)下,會引入很多服務(wù)問題痒筒,所以少不了需要做服務(wù)治理宰闰,包括:服務(wù)注冊與發(fā)現(xiàn)、服務(wù)配置簿透、服務(wù)限流移袍、服務(wù)熔斷、服務(wù)降級老充、負載均衡葡盗、鏈路追蹤等。以下涉及的Nacos啡浊、Sentinel的詳細介紹見Spring Cloud專題的文章觅够。

關(guān)于服務(wù)治理的范疇?wèi)?yīng)該包括哪些,業(yè)界其實也沒有形成標(biāo)準(zhǔn)巷嚣,但至少包括了前面列出來的內(nèi)容喘先,這是毋庸置疑的。另外廷粒,微服務(wù)架構(gòu)下窘拯,服務(wù)集群規(guī)模會越來越大红且,服務(wù)治理也很難靠人工完成,因此涤姊,微服務(wù)治理的自動化程序要高暇番。

下面,我們就根據(jù)上面列舉的內(nèi)容思喊,一一講解每一塊的服務(wù)治理如何實踐壁酬。

二、 服務(wù)注冊與發(fā)現(xiàn)

在第三篇文章最后我們也有講到注冊中心恨课,從 CAP 理論出發(fā)舆乔,分析出注冊中心應(yīng)該優(yōu)先選擇 AP 模型,且推薦使用 Nacos剂公。

而這次蜕煌,我們來聊聊另一個問題:為什么需要注冊中心?

我們知道诬留,服務(wù)之間相互調(diào)用,就需要知道對方的 IP 和端口贫母。在沒有注冊中心的情況下文兑,每個服務(wù)會將其他服務(wù)的 IP 和端口寫死在自己的配置文件里。這樣的話腺劣,每次需要新增或移除一個服務(wù)實例的時候绿贞,相關(guān)聯(lián)的所有服務(wù)都需要修改配置。當(dāng)服務(wù)比較少的時候橘原,問題還不大籍铁,但隨著服務(wù)越來越多,服務(wù)實例的新增或移除越來越頻繁趾断,依然靠人工手動寫配置和變更配置拒名,對運維和開發(fā)來說簡直就是災(zāi)難。

為了解放雙手芋酌、提高效率增显,服務(wù)注冊與發(fā)現(xiàn)的機制就被聰明的人類設(shè)計出來了。

每一個服務(wù)實例在啟動運行的時候脐帝,都將自己的信息(包括 IP同云、端口和唯一的服務(wù)名字等)上報給注冊中心,注冊中心則會將所有服務(wù)注冊的信息保存到注冊表中堵腹,這就是服務(wù)注冊炸站。

有了注冊中心之后,那服務(wù) A 需要調(diào)用服務(wù) B 時疚顷,就不是服務(wù) A 的配置文件里寫死服務(wù) B 的 IP 和端口了旱易,服務(wù) A 里配置的是服務(wù) B 的名字禁偎,服務(wù) A 會根據(jù)服務(wù) B 的名字向注冊中心請求服務(wù) B 的實例信息,從而拿到服務(wù) B 的 IP 地址和端口咒唆,這就是服務(wù)發(fā)現(xiàn)届垫。另外,服務(wù) B 如果存在多個實例全释,那注冊中心返回的可能就是服務(wù) B 的實例信息列表装处,這時,服務(wù) A 則可以選用某種負載均衡算法取得其中一個 IP浸船,再進行調(diào)用妄迁。有些注冊中心自身也提供了負載均衡算法,直接算好一個 IP 并返回李命,則無需服務(wù) A 自己選擇登淘。

服務(wù)注冊與發(fā)現(xiàn),除了可以動態(tài)獲取 IP封字,還有一個重要的功能就是可以自動監(jiān)控管理服務(wù)器的存活狀態(tài)黔州。主要實現(xiàn)方式就是注冊中心與每個服務(wù)器之間定時發(fā)送心跳包,做健康檢查阔籽。一旦心跳包停止未斑,則可判斷為該服務(wù)器宕機了篇梭,就會標(biāo)記這個實例的狀態(tài)為故障喊废,或者干脆剔除掉這臺機器糯累。當(dāng)故障機器被修復(fù)后,服務(wù)重新啟動后在辆,健康檢查會檢查通過证薇,然后這臺機器就會被重新標(biāo)記為健康。

簡而言之匆篓,使用注冊中心實現(xiàn)服務(wù)的自動注冊與發(fā)現(xiàn)浑度,就是服務(wù)治理的第一步。

三奕删、 服務(wù)配置

每個服務(wù)或多或少總有一些配置參數(shù)要管理俺泣,比如配置服務(wù)訪問的端口、數(shù)據(jù)庫連接參數(shù)完残、Redis連接參數(shù)伏钠、日志參數(shù)、一些熱開關(guān)谨设、黑白名單等等熟掂。在微服務(wù)架構(gòu)系統(tǒng)中,基本都是用配置中心來統(tǒng)一管理所有服務(wù)的配置扎拣。和注冊中心一樣赴肚,配置中心也是微服務(wù)架構(gòu)中的一個基礎(chǔ)設(shè)施素跺。

為什么需要配置中心呢?我們可以看看在沒有配置中心的情況下誉券,是如何處理各種配置參數(shù)問題的指厌。

沒有配置中心的情況下,各個服務(wù)各自管理自己的配置參數(shù)踊跟,有的通過數(shù)據(jù)庫管理配置踩验,有的使用配置文件進行管理。配置文件可能還使用不同格式商玫,有的可能用 properties 文件箕憾,有的可能用 yaml 文件,有的可能用 conf 文件拳昌,有的則可能用 xml 文件袭异。另外,對配置項的命名規(guī)則也可能不一樣炬藤。缺少統(tǒng)一管理御铃,各自為政,運維人員做維護時就會非常痛苦沈矿。而且畅买,如果參數(shù)需要修改,也很不靈活细睡,甚至還要重啟運行中的服務(wù)才能生效。一般一個服務(wù)還會部署多個實例帝火,那該服務(wù)的配置參數(shù)需要修改的時候溜徙,所有實例也都要同步修改和重啟,如果有一臺不小心改錯了參數(shù)犀填,那還可能引發(fā)生產(chǎn)事故蠢壹。

而且,項目中都會有多個環(huán)境:測試環(huán)境九巡、UAT 環(huán)境图贸、生產(chǎn)環(huán)境等。不同環(huán)境的配置參數(shù)一般是不同的冕广,一般分開不同的配置文件進行隔離疏日,比如像下面這樣:

  • 測試環(huán)境:conf-test.yaml
  • UAT 環(huán)境:conf-uat.yaml
  • 生產(chǎn)環(huán)境:conf-prod.yaml

沒有配置中心的情況下,不同環(huán)境的配置參數(shù)也只能手動維護撒汉,這會存在一些問題沟优。一來,生產(chǎn)環(huán)境的配置信息暴露了出來睬辐,容易產(chǎn)生安全事故挠阁;二來宾肺,前面提到的手動改參數(shù)的弊端容易進一步擴大;第三侵俗,如果不小心將測試環(huán)境的配置帶到了生產(chǎn)環(huán)境锨用,也會引發(fā)生產(chǎn)事故。

還有一個弊端就是配置修改無法追溯隘谣,因為采用了靜態(tài)配置文件方式增拥,那修改配置之后,不容易形成記錄洪橘,更無法追溯是誰修改的跪者、什么時間修改的、修改前的內(nèi)容是什么熄求。既然無法追溯渣玲,那么當(dāng)配置出錯時,也就無法回滾配置了弟晚。

而使用配置中心忘衍,就可以很好地解決以上說的那些問題。使用配置中心卿城,就可以統(tǒng)一管理不同環(huán)境枚钓、不同集群的配置,且可以追溯對配置的每一次修改瑟押。

再來說說配置中心的選型搀捷,目前業(yè)界比較流行的配置中心主要集中在三款:Spring Cloud Config、Apollo多望、Nacos嫩舟。下表是這三款產(chǎn)品的對比:

image

Spring Cloud Config 更多只是結(jié)合 Spring Cloud 使用,但不管從功能還是性能怀偷,都不如 Apollo 和 Nacos家厌。在功能方面,Nacos 目前的最新版本已經(jīng)全都支持椎工,另外在性能方面還具備較大優(yōu)勢饭于,所以,我還是比較推薦 Nacos 的维蒙。不過掰吕,如果注冊中心已經(jīng)選用了 Nacos,那配置中心也選用 Nacos 的話颅痊,建議分開部署畴栖,即用作注冊中心的 Nacos 和用作配置中心的 Nacos 要分開部署。

四八千、 服務(wù)限流

限流吗讶、熔斷燎猛、降級,是我們經(jīng)常聽到的三個名詞照皆,但對三者的區(qū)別和關(guān)系重绷,很多人傻傻分不清楚。那我會根據(jù)我的理解膜毁,盡量講明白三者的區(qū)別昭卓,以及如何落地應(yīng)用到實際項目中。

我們知道瘟滨,互聯(lián)網(wǎng)系統(tǒng)候醒,流量的突然暴漲很常見,有些場景是可以預(yù)見的杂瘸,比如雙11倒淫、雙12活動;而有些場景則是不可預(yù)見的败玉,比如一個明星的突然官宣敌土。如果對高流量不做任何保護措施,當(dāng)請求超過服務(wù)器承載極限的時候运翼,系統(tǒng)就會崩潰返干,導(dǎo)致服務(wù)不可用。

那么血淌,在高流量的場景下矩欠,如何保證服務(wù)集群整體穩(wěn)定和可用性呢?主要有兩個方向悠夯,一是通過資源擴容來提升系統(tǒng)整體的容量晚顷,缺點就是成本比較高,且考慮到 ROI(投入產(chǎn)出比)疗疟,也不可能無限擴容。而另一個更經(jīng)濟可行的選擇就是限流瞳氓。

所謂限流策彤,是指當(dāng)系統(tǒng)資源不足以應(yīng)對高流量的時候,為了保證有限的資源能夠正常服務(wù)匣摘,按照預(yù)設(shè)的規(guī)則店诗,對系統(tǒng)進行流量限制。預(yù)設(shè)的規(guī)則中音榜,核心指標(biāo)可能是 QPS庞瘸、總并發(fā)數(shù)、并發(fā)線程數(shù)赠叼,甚至是 IP 白名單擦囊,根據(jù)這些指標(biāo)預(yù)設(shè)的值來決定是否對后續(xù)的請求進行攔截违霞。

常見的限流算法有四種:計數(shù)器算法、滑動窗口算法瞬场、漏桶算法买鸽、令牌桶算法

計數(shù)器算法贯被,也稱為固定窗口算法眼五,比較簡單粗暴,就是在固定的時間周期內(nèi)(即時間窗口)累加訪問次數(shù)彤灶,當(dāng)達到設(shè)定的閥值時看幼,觸發(fā)限流策略,比如拒絕請求幌陕。下一個周期開始時诵姜,進行清零,重新計數(shù)苞轿。這個算法雖然簡單茅诱,但存在一個嚴(yán)重的問題,那就是臨界問題搬卒。假設(shè) 1 分鐘內(nèi)服務(wù)器的負載能力為 100瑟俭,因此一個周期的訪問量限制在 100,然而在第一個周期的最后 1 秒(0:59)和下一個周期的開始 1 秒(1:00)時間段內(nèi)契邀,分別涌入了 100 的訪問量摆寄,雖然沒有超過每個周期的限制量,但是整體上 2 秒內(nèi)已達到 200 的訪問量坯门,已遠超過服務(wù)器的負載能力微饥。如下圖所示:

image

滑動窗口算法,就能降低臨界問題的影響古戴,它的基本原理就是將一個時間窗口進行分割欠橘,比如將 1 分鐘的時間窗口分割成 6 格,則每格代表 10 秒鐘现恼,且每一格都有自己獨立的計數(shù)器肃续。每過 10 秒鐘,就把整個 1 分鐘的時間窗口往右滑動 1 格叉袍。而時間窗口內(nèi)的總計數(shù)始锚,則是將該窗口內(nèi)的所有格子的計數(shù)總和出來的。如下圖所示:

image

那么喳逛,再來看看剛才的臨界問題瞧捌。0:59 的 100 個請求會落在灰色的格子里,而 1:00 到達的請求則落在橘黃色的格子里。當(dāng)時間到達 1:00 時姐呐,時間窗口會往右移一格殿怜,而這時,整個窗口的總計數(shù)其實已經(jīng)達到了 100皮钠,所以稳捆,1:00 之后到達的請求其實就會觸發(fā)限流策略了。由此可見麦轰,當(dāng)滑動窗口的格子劃分得越多乔夯,那么滑動窗口的滾動就越平滑,限流的統(tǒng)計就會越精確款侵。不過末荐,滑動窗口算法依然無法應(yīng)對細時間粒度的突發(fā)流量,對流量的整形效果在細時間粒度上不夠平滑新锈。

漏桶算法也簡單甲脏,我們可以把系統(tǒng)看成一個水桶,進來的請求理解為往桶里注水妹笆,處理請求就是桶中的水流出块请。水桶有固定容量,如果滿了就溢出拳缠。不管注入水(請求進入)的快慢如何墩新,只按照恒定的速率出水(處理請求)。因為桶容量是不變的窟坐,保證了整體的速率海渊。不過,也因為速率是固定的哲鸳,所以應(yīng)對突發(fā)流量時就顯得效率低下了臣疑。Java 自帶的信號量組件 Semaphore 就是典型的基于漏桶算法實現(xiàn)的。

令牌桶算法應(yīng)該算是最靈活的限流算法了徙菠,基本原理直接看下圖:

image

令牌桶算法可以在運行時控制和調(diào)整數(shù)據(jù)處理的速率讯沈,一旦需要提高速率,則按需提高放入桶中的令牌的速率婿奔。一般會定時(比如100毫秒)往桶中增加一定數(shù)量的令牌缺狠,有些變種算法則實時的計算應(yīng)該增加的令牌的數(shù)量。因此脸秽,令牌桶就可以應(yīng)對突發(fā)流量了。不過蝴乔,其實現(xiàn)相對也更復(fù)雜一些记餐。Google Guava 的 RateLimiter 組件就是采用令牌桶算法實現(xiàn)的。

在實際應(yīng)用中薇正,尤其在分布式系統(tǒng)中片酝,使用最廣泛的組件應(yīng)屬 Sentinel囚衔,它的定位就是面向分布式服務(wù)架構(gòu)的高可用流量控制組件。Sentinel 提供的主要功能不僅是限流雕沿,也提供了熔斷降級练湿、系統(tǒng)負載保護。對多語言的支持方面审轮,除了 Java肥哎,也支持了 Go 和 C++。另外疾渣,限流方面篡诽,Sentinel 除了支持單機限流,也支持集群限流榴捡。

而具體到我們的交易系統(tǒng)中杈女,應(yīng)該在哪些地方做限流呢?主要就是對接口做限流吊圾,而我們的接口可以分為幾大類:管理端 API达椰、客戶端 API、開放 API项乒、服務(wù)內(nèi)部 API啰劲。管理端 API 基本不會有突發(fā)流量的產(chǎn)生,所以也沒必要做限流板丽〕释鳎客戶端 API 和開放 API 則需要做限流,但兩者的限流規(guī)則應(yīng)該不一樣埃碱,對開放 API 的限流規(guī)則應(yīng)該嚴(yán)格一些猖辫,因為更容易被攻擊。服務(wù)內(nèi)部 API 在目前階段也可以不做限流砚殿,一般微服務(wù)的規(guī)模比較大啃憎,某些服務(wù)的調(diào)用方比較多的時候需要做限流;或者其他一些場景導(dǎo)致下游出現(xiàn)突發(fā)流量的時候似炎,比如上游調(diào)用方多線程并發(fā)跑定時任務(wù)調(diào)用下游服務(wù)的接口辛萍,這種情況下為了防止接口被過度調(diào)用,就需要對每個調(diào)用方進行細粒度的訪問限流羡藐。

所以贩毕,我們就先給客戶端 API 和開放 API 加限流,那么仆嗦,就需要在客戶端 API 網(wǎng)關(guān)和開放 API 網(wǎng)關(guān)集成限流組件辉阶,組件的選型就直接用 Sentinel。這兩個 API 網(wǎng)關(guān)應(yīng)該都是多實例部署的,所以分別需要做集群限流谆甜。部署方式采用獨立部署 Sentinel 服務(wù)端的方式垃僚,且每個網(wǎng)關(guān)實例需要引入 Sentinel 客戶端依賴。

限流規(guī)則的粒度方面规辱,除了需要限制集群整體的訪問頻率谆棺,還需要限制某類接口甚至某個具體接口的訪問頻率。網(wǎng)關(guān)層的限流只能做到粗粒度的集群整體的限流罕袋,以及按不同路由名稱進行限流改淑。而具體到某個接口的,則只能在業(yè)務(wù)層的微服務(wù)進行限流了炫贤,所以還需要給對應(yīng)的微服務(wù)集成限流組件客戶端溅固。具體接口層面,應(yīng)該對下單請求進行限流兰珍,而限流策略可以用勻速器方式侍郭,對應(yīng)的則是漏桶算法。

至此掠河,關(guān)于限流方面的內(nèi)容亮元,就講這么多了。

五唠摹、 服務(wù)熔斷

服務(wù)熔斷主要是應(yīng)對服務(wù)雪崩的一種自我保護機制爆捞,當(dāng)下游的目標(biāo)服務(wù)因為某種原因突然變得不可用或響應(yīng)過慢,上游服務(wù)為了保證自己整體服務(wù)的可用性勾拉,不再繼續(xù)調(diào)用目標(biāo)服務(wù)煮甥,直接返回,快速釋放資源藕赞。如果目標(biāo)服務(wù)情況好轉(zhuǎn)則恢復(fù)調(diào)用成肘。

對熔斷機制的設(shè)計,業(yè)內(nèi)基本上都是采用 熔斷器模式來實現(xiàn)斧蜕,Martin Fowler 在博文 《CircuitBreaker》 中對此設(shè)計進行了比較詳細的說明双霍。熔斷器主要有三種狀態(tài):

  • closed:關(guān)閉狀態(tài),讓請求通過的默認狀態(tài)批销。如果請求錯誤率低于閾值洒闸,則狀態(tài)保持不變【浚可能出現(xiàn)的錯誤是超過最大并發(fā)數(shù)和超時錯誤丘逸。
  • open:當(dāng)熔斷器打開的時候,所有的請求都會被標(biāo)記為失敗掀宋。這是故障快速失敗機制深纲,而不需要等待超時時間完成羞反。
  • half open:半開狀態(tài)時,會定期的嘗試發(fā)起請求來確認系統(tǒng)是否恢復(fù)囤萤。如果恢復(fù)了永乌,熔斷器將轉(zhuǎn)為關(guān)閉狀態(tài)或者保持打開松靡。

這三種狀態(tài)如下圖所示進行轉(zhuǎn)換:

image
  • 最開始處于 closed 狀態(tài),一旦檢測到錯誤率到達一定閾值箩言,便轉(zhuǎn)為 open 狀態(tài)唆途;
  • 這時候會有個 reset timeout富雅,到了這個時間了,會轉(zhuǎn)移到 half open 狀態(tài)肛搬;
  • 嘗試放行一部分請求到目標(biāo)服務(wù)没佑,一旦檢測成功便回歸到 closed 狀態(tài),即恢復(fù)服務(wù)温赔;

檢測錯誤率的實現(xiàn)原理也比較簡單蛤奢,主要就是在一個滑動時間窗口內(nèi),統(tǒng)計下調(diào)用目標(biāo)服務(wù)接口的總請求數(shù)和錯誤的請求數(shù)陶贼,一旦錯誤率達到設(shè)置的閥值啤贩,就觸發(fā)熔斷。另外拜秧,在這個滑動時間窗口內(nèi)痹屹,應(yīng)該還有個最小請求數(shù)的設(shè)置,比如 10s 內(nèi)至少要有 20 次請求枉氮,如果沒達到最小請求數(shù)志衍,就算失敗率達到了閥值也不觸發(fā)熔斷,否則聊替,很大可能會造成誤殺楼肪。

Sentinel 提供的熔斷策略則有三種,除了上面說的錯誤率方式佃牛,即異常比例方式淹辞,還提供了另外兩種統(tǒng)計方式:慢調(diào)用比例異常數(shù)。這三種方式的官方描述如下:

  • 慢調(diào)用比例 (SLOW_REQUEST_RATIO):選擇以慢調(diào)用比例作為閾值俘侠,需要設(shè)置允許的慢調(diào)用 RT(即最大的響應(yīng)時間)象缀,請求的響應(yīng)時間大于該值則統(tǒng)計為慢調(diào)用。當(dāng)單位統(tǒng)計時長(statIntervalMs)內(nèi)請求數(shù)目大于設(shè)置的最小請求數(shù)目爷速,并且慢調(diào)用的比例大于閾值央星,則接下來的熔斷時長內(nèi)請求會自動被熔斷。經(jīng)過熔斷時長后熔斷器會進入探測恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài))惫东,若接下來的一個請求響應(yīng)時間小于設(shè)置的慢調(diào)用 RT 則結(jié)束熔斷莉给,若大于設(shè)置的慢調(diào)用 RT 則會再次被熔斷毙石。
  • 異常比例 (ERROR_RATIO):當(dāng)單位統(tǒng)計時長(statIntervalMs)內(nèi)請求數(shù)目大于設(shè)置的最小請求數(shù)目,并且異常的比例大于閾值颓遏,則接下來的熔斷時長內(nèi)請求會自動被熔斷徐矩。經(jīng)過熔斷時長后熔斷器會進入探測恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來的一個請求成功完成(沒有錯誤)則結(jié)束熔斷叁幢,否則會再次被熔斷滤灯。異常比率的閾值范圍是 [0.0, 1.0],代表 0% - 100%曼玩。
  • 異常數(shù) (ERROR_COUNT):當(dāng)單位統(tǒng)計時長內(nèi)的異常數(shù)目超過閾值之后會自動進行熔斷鳞骤。經(jīng)過熔斷時長后熔斷器會進入探測恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來的一個請求成功完成(沒有錯誤)則結(jié)束熔斷黍判,否則會再次被熔斷豫尽。

在我們的項目中,依然采用 Sentinel 作為熔斷器組件顷帖,且對同步調(diào)用的每一層微服務(wù)都添加熔斷保護美旧,包括網(wǎng)關(guān)層、業(yè)務(wù)邏輯層贬墩、數(shù)據(jù)訪問層陈症。而異步調(diào)用的服務(wù)則無需增加熔斷保護,這主要就是指撮合引擎震糖。

而關(guān)于限流和熔斷的區(qū)別录肯,用一張圖就明白了:

image

限流和熔斷都是為了保護當(dāng)前服務(wù)自身的可用性,但限流是為了防止上游服務(wù)調(diào)用量過大從而壓垮當(dāng)前服務(wù)吊说,熔斷則是為了避免下游服務(wù)出現(xiàn)故障時引發(fā)級聯(lián)故障论咏。

六、服務(wù)降級

我所理解的服務(wù)降級其實是一個更大的概念颁井,存在多種降級方式厅贪,可以根據(jù)不同場景選擇不同的降級方式,限流和熔斷實際上也是應(yīng)對兩種不同場景的降級方式雅宾。

從概念上來說养涮,所謂的服務(wù)降級,是當(dāng)服務(wù)器壓力劇增的情況下眉抬,根據(jù)當(dāng)前業(yè)務(wù)情況及流量對一些服務(wù)和頁面進行策略性的屏蔽或降低服務(wù)質(zhì)量贯吓,以此釋放服務(wù)器資源以保證核心任務(wù)的正常運行。

從使用場景來說蜀变,當(dāng)整個微服務(wù)架構(gòu)整體的負載超出了預(yù)設(shè)的上限閾值或即將到來的流量預(yù)計將會超過預(yù)設(shè)的閾值時悄谐,為了保證重要或基本的服務(wù)能正常運行,我們可以將一些不重要不緊急的服務(wù)或任務(wù)進行服務(wù)的延遲使用暫停使用库北。

服務(wù)降級的方式或策略其實有多種爬舰,除了限流和熔斷们陆,常用的還有以下這些:

  • 關(guān)閉次要服務(wù):在服務(wù)壓力過大時,關(guān)閉非核心功能的服務(wù)情屹,避免核心功能被拖垮坪仇。比如,淘寶雙11活動當(dāng)天垃你,訂單量激增烟很,為了保證核心的交易業(yè)務(wù)的高可用,就會暫時關(guān)閉非核心的退貨服務(wù)蜡镶。
  • 丟棄部分請求:對于一些老請求——即從接收到處理的時間已經(jīng)超過了一定時間(比如1s)的請求,可以直接丟棄恤筛。還可以根據(jù)請求的優(yōu)先級官还,有選擇性地丟棄那些優(yōu)先級低的請求《咎常或者隨機丟棄一定比例的請求望伦。
  • 讀降級:對于讀一致性要求不高的場景,在服務(wù)和數(shù)據(jù)庫壓力過大時煎殷,可以不讀數(shù)據(jù)庫屯伞,降級為只讀緩存數(shù)據(jù),以這種方式來減小數(shù)據(jù)庫壓力豪直,提高服務(wù)的吞吐量劣摇。
  • 寫降級:在服務(wù)壓力過大時,可以將同步寫轉(zhuǎn)為異步寫弓乙,來減小服務(wù)壓力并提高吞吐量末融。既然把同步改成了異步也就意味著降低了數(shù)據(jù)一致性,保證數(shù)據(jù)最終一致即可暇韧。
  • 屏蔽寫入:很多高并發(fā)場景下勾习,查詢請求都會走緩存,這時數(shù)據(jù)庫的壓力主要是寫入壓力懈玻。所以對于某些不重要的服務(wù)巧婶,在服務(wù)和數(shù)據(jù)庫壓力過大時,可以關(guān)閉寫入功能涂乌,只保留查詢功能艺栈,這樣可以明顯減小數(shù)據(jù)庫壓力。
  • 數(shù)據(jù)冗余:服務(wù)調(diào)用者可以冗余它所依賴服務(wù)的數(shù)據(jù)湾盒。當(dāng)依賴的服務(wù)故障時眼滤,服務(wù)調(diào)用者可以直接使用冗余數(shù)據(jù)。

以上列出來的只是部分降級方式而已历涝,并沒有涵蓋所有情況诅需。實際上漾唉,關(guān)于服務(wù)降級的方式和策略,并沒有什么定式堰塌,也沒有標(biāo)準(zhǔn)可言赵刑。不過,所有的降級方案都要以滿足業(yè)務(wù)需求為前提场刑,都是為了提高系統(tǒng)的可用性般此,保證核心功能正常運行。

從分類上來說牵现,可以把服務(wù)降級分為手動降級自動降級兩大類铐懊。手動降級應(yīng)用較多,主要通過開關(guān)的方式開啟或關(guān)閉降級瞎疼。自動降級科乎,比如限流和熔斷就屬于這一類。手動降級大多也可以做成自動的方式贼急,可根據(jù)各種系統(tǒng)指標(biāo)配置閾值茅茂,當(dāng)相應(yīng)指標(biāo)達到閾值時則自動開啟降級。不過太抓,在很多場景下空闲,由于業(yè)務(wù)比較復(fù)雜,指標(biāo)太多走敌,自動降級實現(xiàn)起來難度比較大碴倾,而且也容易出錯。所以在考慮做自動降級之前一定要充分做好評估掉丽,相應(yīng)的自動降級方案也要考慮周全影斑。

因為降級的概念比較大,且沒有標(biāo)準(zhǔn)机打,所以只能根據(jù)實際場景需求選擇對應(yīng)合適的降級方式或策略去實現(xiàn)矫户。

七、 負載均衡

在微服務(wù)架構(gòu)中残邀,負載均衡也是必須使用的技術(shù)皆辽,通過它來實現(xiàn)系統(tǒng)的高可用和集群擴容等功能。當(dāng)然芥挣,如果目標(biāo)服務(wù)只有一個實例驱闷,那其實就無需添加負載均衡了。

負載均衡主要分兩種:服務(wù)端負載均衡客戶端負載均衡空免。我們平時所說的負載均衡通常指的是服務(wù)端負載均衡空另,可通過硬件設(shè)備或軟件來實現(xiàn),硬件如 F5蹋砚、Array 等扼菠,其優(yōu)點就是功能強大摄杂、性能強大、穩(wěn)定性高循榆,但缺點就是價格昂貴且可擴展性差析恢,所以更多還是使用軟件,軟件主要用 LVS秧饮、Nginx映挂、HAproxy 等。而系統(tǒng)內(nèi)部不同服務(wù)之間的負載則用客戶端負載均衡盗尸,SpringCloud Ribbon 就是基于客戶端的負載均衡組件柑船。

服務(wù)端負載均衡主要應(yīng)用在系統(tǒng)外部請求和網(wǎng)關(guān)層之間,常用的還分為四層負載均衡七層負載均衡泼各。

四層負載均衡工作在 OSI 模型的傳輸層鞍时,主要做轉(zhuǎn)發(fā),它在接收到客戶端的請求之后历恐,會通過修改數(shù)據(jù)包的地址信息將請求轉(zhuǎn)發(fā)到應(yīng)用服務(wù)器。實際應(yīng)用中专筷,大部分項目都是采用 LVS作為四層負載均衡器弱贼,包括 BAT 等大廠,也都是 LVS 的重度使用者磷蛹。LVS 具備可靠性吮旅、高性能、可擴展性和可操作性的特點味咳,從而以低廉的成本實現(xiàn)最優(yōu)的性能庇勃。

七層負載均衡,也稱為內(nèi)容交換槽驶,主要通過報文中的真正有意義的應(yīng)用層內(nèi)容责嚷,再加上負載均衡器設(shè)置的服務(wù)器選擇方式(即負載均衡算法),決定最終選擇的內(nèi)部服務(wù)器掂铐。七層負載均衡的好處罕拂,就是使得整個網(wǎng)絡(luò)更智能化,可以根據(jù) URL 或請求參數(shù)路由到不同的服務(wù)器全陨。工具的選型方面爆班,使用最廣泛的當(dāng)屬 Nginx,Nginx 除了做負載均衡還可以做靜態(tài) Web 服務(wù)器辱姨、緩存服務(wù)器柿菩、反向代理服務(wù)器等。

服務(wù)端負載均衡要做到高可用雨涛,常用的方案是做兩層負載枢舶,第一層用 LVS+Keepalive懦胞,第二層用 Nginx。兩層的負載至少都是雙機熱備祟辟,避免單點故障医瘫。第一層的負載需要綁定一個公網(wǎng) VIP,一般旧困,域名解析也是解析到這個 VIP醇份。

客戶端負載均衡應(yīng)用在微服務(wù)系統(tǒng)內(nèi)部,實現(xiàn)上下游服務(wù)之間的負載均衡吼具。不同于服務(wù)端負載均衡是將下游的服務(wù)器列表存儲在獨立的負載均衡服務(wù)器里僚纷,客戶端負載均衡則是將下游的服務(wù)器列表保存在上游服務(wù)里,而且下游服務(wù)的集群服務(wù)器列表是從注冊中心獲取并存儲的拗盒,再根據(jù)實現(xiàn)的負載均衡算法選定對應(yīng)的服務(wù)器實例進行請求的下發(fā)怖竭。

客戶端負載均衡最關(guān)鍵的還是負載均衡算法,算法有很多陡蝇,常用的有:隨機法痊臭、加權(quán)隨機法、輪詢法登夫、加權(quán)輪詢法广匙、一致性Hash法、最小連接法等恼策。

  • 隨機法:將請求隨機分配到各臺服務(wù)器鸦致,適合于所有服務(wù)器都有相同的資源配置并且平均服務(wù)請求相對均衡的情況。當(dāng)請求量很大的時候涣楷,請求分散的均衡性最好分唾。如果請求量不大,則可能會出現(xiàn)請求集中在某些服務(wù)器的情況狮斗。
  • 加權(quán)隨機法:即給每臺服務(wù)器配置權(quán)重值绽乔,權(quán)重值高的則接收到請求的概率就會較高,適合于服務(wù)器的資源配置不一樣的場景碳褒。
  • 輪詢法:就是將請求按順序輪流分發(fā)到每個服務(wù)器迄汛,和隨機法一樣,適合于服務(wù)器資源配置一樣的情況骤视,請求量不大的時候也適用鞍爱。
  • 加權(quán)輪詢法:和加權(quán)隨機法一樣,不同資源配置的服務(wù)器會配置不同的權(quán)重值专酗,權(quán)重值高的被輪詢到的概率也高睹逃。
  • 一致性Hash法:主要是為了讓相同參數(shù)的請求總是發(fā)給同一臺服務(wù)器,比如同個 IP 的請求。
  • 最小連接法:將請求分配到當(dāng)前連接數(shù)最少的服務(wù)器上沉填,可以盡可能地提高服務(wù)器的利用效率疗隶,但實現(xiàn)比較復(fù)雜,需要監(jiān)控服務(wù)器的請求連接數(shù)翼闹。

實際的線上業(yè)務(wù)有時候比較復(fù)雜斑鼻,單純采用任何一種負載均衡算法都無法滿足需求,所以還會采用多種算法的組合猎荠。

八坚弱、 鏈路追蹤

微服務(wù)架構(gòu)系統(tǒng),每個用戶請求往往涉及多個服務(wù)关摇,且不同服務(wù)可能由不同團隊開發(fā)荒叶,可能使用不同編程語言實現(xiàn),還可能布在了橫跨多個數(shù)據(jù)中心的幾千臺服務(wù)器上输虱。在這種背景下些楣,就需要一些能幫助理解系統(tǒng)行為、分析性能問題的工具宪睹,且在發(fā)生故障的時候能夠快速定位和解決問題愁茁,這工具就是分布式追蹤系統(tǒng),也稱為 APM(Application Performance Monitor) 系統(tǒng)亭病。

最早的分布式追蹤系統(tǒng)可以說就是 Google Dapper 了鹅很,Google 在 2010 年發(fā)表了《Dapper - a Large-Scale Distributed Systems Tracing Infrastructure》論文介紹了這個系統(tǒng)。雖然 Dapper 系統(tǒng)沒有開源命贴,但受該論文的啟發(fā)道宅,之后不斷有團隊研發(fā)出新的分布式追蹤系統(tǒng)食听,比如阿里的 EagleEye胸蛛、Twitter 的 Zipkin、大眾點評的 CAT樱报、京東的 Hydra葬项、韓國的 PinPoint,Uber 的 Jaeger迹蛤,還有由華為吳昕研發(fā)并在 2017 年加入 Apache 孵化器的 SkyWalking民珍,等等。不過盗飒,這些名單中嚷量,EagleEye 沒有開源,CAT 和 Hydra 早已停止維護逆趣。

另外蝶溶,還有一個開源項目不得不提,那就是 OpenTracing。由于不同的分布式追蹤系統(tǒng)的 API 不兼容抖所,那如果需要切換追蹤系統(tǒng)就需要做很大的改動梨州,為了解決這個問題,就誕生了 OpenTracing田轧。OpenTracing 并不是一個具體的分布式追蹤實現(xiàn)系統(tǒng)暴匠,而只是一個輕量級的標(biāo)準(zhǔn)化層,它位于應(yīng)用程序/類庫追蹤或日志分析程序之間傻粘,請看下圖:

+-------------+  +---------+  +----------+  +------------+
| Application |  | Library |  |   OSS    |  |  RPC/IPC   |
|    Code     |  |  Code   |  | Services |  | Frameworks |
+-------------+  +---------+  +----------+  +------------+
       |              |             |             |
       |              |             |             |
       v              v             v             v
  +------------------------------------------------------+
  |                     OpenTracing                      |
  +------------------------------------------------------+
     |                |                |               |
     |                |                |               |
     v                v                v               v
+-----------+  +-------------+  +-------------+  +-----------+
|  Tracing  |  |   Logging   |  |   Metrics   |  |  Tracing  |
| System A  |  | Framework B |  | Framework C |  | System D  |
+-----------+  +-------------+  +-------------+  +-----------+
復(fù)制代碼

OpenTracing 正在為全球的分布式追蹤每窖,提供統(tǒng)一的概念和數(shù)據(jù)標(biāo)準(zhǔn)。OpenTracing 通過提供平臺無關(guān)抹腿、廠商無關(guān)的 API岛请,使得開發(fā)人員能夠方便地添加(或更換)追蹤系統(tǒng)的實現(xiàn)。其支持的語言已經(jīng)包括了 Go警绩、Java崇败、JavaScript、Python肩祥、Ruby后室、PHP、C++混狠、C#岸霹、Objective-C。兼容 OpenTracing 的 APM 也包括了 Jaeger将饺、SkyWalking贡避,還有其他項目,如 LightStep予弧、Instana刮吧、Datadog、Elastic APM 等掖蛤。

那么杀捻,分布式追蹤系統(tǒng)這么多,目前也沒有一枝獨大蚓庭,選型其實不太好做致讥。我這里只提供一點我的見解。首先器赞,我會傾向于選擇兼容 OpenTracing 的垢袱,畢竟 OpenTracing 已經(jīng)越來越受到開源和商業(yè)團隊的追捧。其次港柜,我會考慮社區(qū)的活躍度请契,優(yōu)先選擇活躍度高的,這從 Github 上的 Star 數(shù)就可以看出來。結(jié)合這兩點姚糊,最后的選擇只剩下 Jaeger 和 SkyWalking贿衍,兩者都支持了多種語言,包括 Java救恨、Go贸辈、C++ 等,也支持集成到服務(wù)網(wǎng)格 Istio + Envoy肠槽。要說差異點的話擎淤,可能 Jaeger 更多用于 Go 系,而 SkyWalking 則主要用于 Java 系秸仙。

九嘴拢、總結(jié)

服務(wù)治理的話題其實很大,內(nèi)容還有很多寂纪,不同人的理解還不同席吴,小小一篇文章只能講到一些皮毛。服務(wù)注冊與發(fā)現(xiàn)捞蛋、服務(wù)配置孝冒、服務(wù)限流、服務(wù)熔斷拟杉、服務(wù)降級庄涡、負載均衡、鏈路追蹤搬设,我們只講到了這 7 塊的內(nèi)容穴店,因為篇幅所限,每一塊也并沒有太深入拿穴,但對于指導(dǎo)實踐來說泣洞,還是能達到目標(biāo)的。

原文鏈接:https://juejin.cn/post/6922751400577335304

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贞言,一起剝皮案震驚了整個濱河市斜棚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖瓢棒,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件根蟹,死亡現(xiàn)場離奇詭異,居然都是意外死亡启具,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來规肴,“玉大人,你說我怎么就攤上這事⊥先校” “怎么了删壮?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長兑牡。 經(jīng)常有香客問我央碟,道長,這世上最難降的妖魔是什么均函? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任亿虽,我火速辦了婚禮,結(jié)果婚禮上苞也,老公的妹妹穿的比我還像新娘洛勉。我一直安慰自己,他們只是感情好如迟,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布收毫。 她就那樣靜靜地躺著,像睡著了一般殷勘。 火紅的嫁衣襯著肌膚如雪牛哺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天劳吠,我揣著相機與錄音引润,去河邊找鬼。 笑死痒玩,一個胖子當(dāng)著我的面吹牛淳附,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蠢古,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼奴曙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了草讶?” 一聲冷哼從身側(cè)響起洽糟,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎堕战,沒想到半個月后坤溃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡嘱丢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年薪介,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片越驻。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡汁政,死狀恐怖道偷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情记劈,我是刑警寧澤勺鸦,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站目木,受9級特大地震影響祝旷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘶窄,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一怀跛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柄冲,春花似錦吻谋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至戒祠,卻和暖如春骇两,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姜盈。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工低千, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馏颂。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓示血,卻偏偏與公主長得像,于是被迫代替她去往敵國和親救拉。 傳聞我的和親對象是個殘疾皇子难审,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

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