高并發(fā)和高可用的一點思考

大數據

指導原則

書中所列舉的,里有一些可能并不是原則,而是技巧。我理解的原則如下:

高并發(fā)原則:

無狀態(tài)設計:因為有狀態(tài)可能涉及鎖操作,鎖又可能導致并發(fā)的串行化。保持合理的粒度:無論拆分還是服務化,其實就是服務粒度控制,控制粒度為了分散請求提高并發(fā),或為了從管理等角度提高可操性。緩存、隊列、并發(fā)等技巧在高并發(fā)設計上可供參考,但需依場景使用。

高可用原則:

系統(tǒng)的任何發(fā)布必須具有可回滾能力。系統(tǒng)任何外部依賴必須準確衡量是否可降級,是否可無損降級,并提供降級開關。系統(tǒng)對外暴露的接口必須配置好限流,限流值必須盡量準確可靠。

業(yè)務設計原則:

安全性:防抓取,防刷單、防表單重復提交,等等等等。at least 消費,應考慮是否采用冪等設計業(yè)務流程動態(tài)化,業(yè)務規(guī)則動態(tài)化系統(tǒng)owner負責制、人員備份制、值班制系統(tǒng)文檔化后臺操作可追溯

以上原則只是大千世界中的一小部分,讀者應當在工作學習中點滴積累。

高可用

我們先說高可用的本質訴求:高可用就是抵御不確定性,保證系統(tǒng)724小時健康服務*。關于高可用,我們其實面對的問題就是對抗不確定性,這個不確定性來自四面八方。比如大地震,會導致整個機房中斷,如何應對?比如負責核心系統(tǒng)的工程師離職了,如何應對?再比如下游接口掛了,如何應對?系統(tǒng)磁盤壞了,數據面臨丟失風險,如何應對?我想關于上述問題的應對方式,大家在工作中或多或少都有所了解,而這個不確定性的處理過程,就是容災,其不同的‘災難’,對應不同的容災級別。

為了對抗這些不同級別的不確定性,就要付出不同級別的成本,因此可用性也應是有標準的。這標準就是大家常說的N個9。隨著N的增加,成本也相應增加,那如何在達到業(yè)務需要的可用性的基礎上,盡量節(jié)省成本?這也是一個值得思考的話題。除此之外,100%減去這N個9就說所謂的平均故障時間(MTBF),很多人只關心那些9,而忽略了故障處理時間,這是不該的:你的故障處理速度越快,系統(tǒng)的可用性才有可能越高。

上面扯了一些可用性概念上的東西,下面來說一下技巧。開濤的書中沒有對可用性技巧做出一個分類,我這里則嘗試使用‘事情’來分個類。這里的‘事’就是故障,分為:事前(故障發(fā)生以前)、事發(fā)(故障發(fā)生到系統(tǒng)或人感知到故障)、事中(故障發(fā)生到故障處理這段時間)、事后(故障結束之后)。

按照上述分類,不同的階段應有著不同的技巧:

事前:副本、隔離、配額、提前預案、探知事發(fā):監(jiān)控、報警事中:降級、回滾、應急預案,failXXX系列事后:復盤、思考、技改

事前

副本技術

大自然是副本技術當之無愧的集大成者,無論是冰河時代,還是隕石撞擊地球所帶來的毀滅性打擊,物種依然綿綿不絕的繁衍,這便是基因復制的作用。副本是對抗不確定性的有力武器,把副本技術引入計算機系統(tǒng),也會帶來高可用性的提升。無狀態(tài)服務集群便是副本的一個應用,因為沒有狀態(tài),便可水平伸縮,而這些無狀態(tài)服務器之間需要一層代理來統(tǒng)一調度管理,這便有了反向代理。當代理通過心跳檢測機制檢測到有一臺機器出現問題時,就將其下線,其他‘副本’機器繼續(xù)提供服務;存儲領域也是經常使用副本技術的,比如OB的三地三中心五副本技術等,mysql主備切換,rabbitMQ的鏡像隊列,磁盤的RAID技術,各種nosql中的分區(qū)副本,等等等等,數不勝數,幾乎所有保證高可用的系統(tǒng)都有冗余副本存在。

隔離技術

書上提到了很多種隔離:線程隔離、進程隔離、集群隔離、機房隔離、讀寫隔離、動靜隔離、爬蟲隔離、熱點隔離、硬件資源隔離。在我看來,這些隔離其實就是一種,即資源隔離,無論線程、進程、硬件、機房、集群都是一種資源;動態(tài)資源和靜態(tài)資源也不過是資源的一種分類;熱點隔離也即是熱點資源和非熱點資源的隔離;讀寫隔離不過僅僅是資源的使用方式而已,相同的兩份資源,一份用來寫,一份用來讀。因此,隔離的本質,其實就是對資源的獨立保護。因為每個資源都得到了獨立的保護,其中一個資源出了問題,不會影響到其他資源,這就提高了整體服務的可用性。人類使用隔離術也由來已久了,從農業(yè)養(yǎng)殖,到股票投資,甚至關犯人的監(jiān)獄,都能找到隔離術的影子。

配額技術

配額技術通過限制資源供給來保護系統(tǒng),從而提高整體可用性。限流是配額技術的一種,它通過調節(jié)入口流量水位上線,來避免供給不足所導致的服務宕機。限流分為集群限流和單機限流,集群限流需要分布式基礎設施配合,單機限流則不需要。大部分業(yè)務場景使用單機限流足以,特殊場景(類秒殺等)下的限流則需限制整個集群。除此之外,限流這里我們還需要考慮幾點:

如何設置合理的限流值?限流值的設定是需要經過全鏈路壓測、妥善評估CPU容量、磁盤、內存、IO等指標與流量之間的變化關系(不一定線性關系)、結合業(yè)務預估和運維經驗后,才能確定。對于被限流的流量如何處理?有幾種處理方式,其一直接丟棄,用溫和的文案提醒用戶;其二,靜默,俗稱的無損降級,用緩存內容刷新頁面;其三,蓄洪,異步回血,這一般用于事務型場景。會不會導致誤殺?單機限流會導致誤殺,尤其當負載不均衡的情況下,很容易出現誤殺;單機限流值設定過小也容易出現誤殺的情況。

探知技術

其只用于探知系統(tǒng)當前可用性能力,無法切實提高系統(tǒng)可用性,做不好甚至還會降低系統(tǒng)可用性。壓測和演練和最常見的探知技術 。壓測分為全鏈路壓測和單鏈路壓測,全鏈路壓測用于像雙十一大促活動等,需要各上下游系統(tǒng)整體配合,單鏈路壓測一般驗證功能或做簡單的單機壓測提取性能指標。全鏈路壓測的一般過程是:壓測目標設定和評估,壓測改造,壓測腳本編寫部署,壓測數據準備,小流量鏈路驗證,通知上下游系統(tǒng)owner,壓測預熱,壓測,壓測結果評估報告,性能優(yōu)化。以上過程反復迭代,直到達到壓測目標為止;演練一般按規(guī)模劃分:比如城市級別的容災演練,機房級別的容災演練,集群規(guī)模的容災演練(DB集群,緩存集群,應用集群等),單機級別的故障注入,預案演練等。演練的作用無需過多強調,但演練一般發(fā)生在凌晨,也需要各系統(tǒng)owner配合排錯,著實累人,一般都是輪班去搞。

預案

預案一般分為提前預案(事前)和應急預案(事中)。提前預案提前執(zhí)行,比如將系統(tǒng)臨時從高峰模式切換成節(jié)能模式;應急預案關鍵時刻才執(zhí)行,主要用于止血,比如一鍵容災切換等。預案技術一般要配合開關使用,推預案一般也就是推開關了。除此之外,預案也可和限流、回滾、降級等相結合,并可以作為一個定期演練項目。

事發(fā)

事發(fā)是指當故障發(fā)生了到系統(tǒng)或人感知到故障準備處理的這段時間,核心訴求即是如何快速、準確的識別故障。

監(jiān)控和報警

一般出現故障的時候,老板大多會有三問:為什么才發(fā)現?為什么才解決?影響有多大?即使故障影響面較大,如果能迅速止血,在做復盤的時候多少能挽回一些面子,相反如果處理不及時,即使小小的故障,都可能讓你丟了飯碗。越早識別故障,就能越早解決問題,而這眼睛便是監(jiān)控和報警了。監(jiān)控報警耳熟能詳,這里不多贅述。

事中

事中是指當故障發(fā)生時,為了保證系統(tǒng)可用性,我們可以或必須做的事情。分為降級、回滾、應急預案(見上文,這里不多數了),faillXXX系列。

降級

降級的內涵豐富,我們只從鏈路角度去思考。降級的本質是棄車保帥,通過臨時舍棄部分功能,保證系統(tǒng)整體可用性。降級雖然從整體上看系統(tǒng)仍然可用,但由于取舍的關系,那么可知所有的降級一定是有損的。不可能有真正的無損降級,而常說的無損降級指的是用戶體驗無損。降級一定發(fā)生在層與層之間(上下游),要么a層臨時性不調用b層,這叫做熔斷,要么a層臨時調用c層(c層合理性一定<b層),這叫備用鏈路。無論是哪一種方式,都會面臨一個問題:如何確定什么時候降級,什么時候恢復?一般有兩種方式,其一是人工確認,通過監(jiān)控報警等反饋機制,人工識別故障,推送降級,待故障恢復后在手動回滾;其二是自適應識別,最常用的指標有超時時間、錯誤次數、限值流等等,當達到閾值時自動執(zhí)行降級,恢復時自動回滾。這兩種方式無需對比,它們都是經常采用的高可用技巧。除此之外,我們還要注意降級和強弱依賴的關系。強弱依賴表示的是鏈路上下游之間的依賴關系,是’是否可降級‘的一種專業(yè)表述。

我們再來看書中的一些降級的例子:①讀寫降級,實際上是存儲層和應用層之間的降級,采用備用鏈路切換方式,損失了一致性;②功能降級,將部分功能關閉,實際上是應用層和功能模塊層之間的降級,采用熔斷方式,損失了部分功能。③爬蟲降級,實際上是搜索引擎爬蟲和應用系統(tǒng)之間的降級,采用備用鏈路切換方式,將爬蟲引導到靜態(tài)頁面,損失是引擎索引的建立和頁面收錄。

回滾

當執(zhí)行某種變更出現故障時,最為穩(wěn)妥和有效的辦法就是回滾。雖然回滾行之有效,但并不簡單,因為回滾有一個大前提:變更必須具有可回滾性。而讓某一種變更具有可回滾的特性,是要耗費很大力氣的。索性的是,大部分基礎服務已經幫我們封裝好了這一特性,比如DB的事務回滾(DB事務機制),代碼庫回滾(GIT的文件版本控制),發(fā)布回滾(發(fā)布系統(tǒng)支持)等等。我們在日常變更操作的時候,必須要確定你的操作是否可回滾,并盡力保證所有變更均可回滾。如果不能回滾,是否可以進行熱更新(比如發(fā)布應用到app store)或最終一致性補償等額外手段保證系統(tǒng)高可用。

failXXX系列

當出現下游調用失敗時,我們一般有幾種處理方式:

failretry,即失敗重試,需要配合退避時間,否則馬上重試不一定會有效果。failover,即所謂的故障轉移。比如調用下游a接口失敗,那么RPC的負載均衡器將會調用a接口提供方的其他機器進行重試;在比如數據庫x掛了,應用自適應容災將對x庫的調用切換到y(tǒng)庫調用,此y庫即可以是faillover庫(流水型業(yè)務),也可以備庫(狀態(tài)型業(yè)務)。failsafe,即靜默,一般下游鏈路是弱依賴的時候,可以采用failsafe,即可和failover相結合,比如failover了3次還是失敗,那么執(zhí)行failsafe。failfast,立即報錯,failfast主要讓工程師快速的感知問題所在,并及時進行人工干預。failback,延遲補償(回血),一般可以采用消息隊列或定時掃描等。

上面的1,2,4是屬于重試策略,即書中《超時與重試》章節(jié)所講到的重試。重試有個問題:退避間隔是多少?重試幾次?一般在下游臨時抖動的情況下,很短時間內就可以恢復;但當下游完全不可用,那么很有可能重試多少次都不會成功,反而會對下游造成了更大的壓力,那這種情況就應當做用熔斷了。所以正確設定重試次數、選擇退避時間等都是需要仔細思考的。我們在來說一下超時,超時只是一種預防機制,不是故障應對策略,其主要為了防止請求堆積——資源都用于等待下游請求返回了。堆積的后果自不用多說,重要的是如何選擇正確的超時時間?書上只說了鏈路每個部分超時時間怎么配置,卻不知道應配置多少,這是不夠全面的。

事后

復盤、思考、技改。不多贅述。

高并發(fā)

如果僅是追求高可用性,這其實并不難做,試想如果一年只有一個人訪問你的系統(tǒng),只要這一個人訪問成功,那你系統(tǒng)的‘’可用性‘就是100%了??涩F實是,隨著業(yè)務的發(fā)展,請求量會越來越高,進而各種系統(tǒng)資源得以激活,那潛在風險也會慢慢的暴露出來。因此,做系統(tǒng)的難點之一便是:如何在高并發(fā)的條件下,保證系統(tǒng)的高可用。上文已經說了一些保證高可用的技巧,這節(jié)將結合開濤的書,說說高并發(fā)。

大數據

上圖是我們生活中常見的一個場景——排隊購物。收銀員就是我們的服務,每一個在隊列中的顧客都是一個請求。我們的本質訴求是讓盡可能多的人都在合理的等待時間內完成消費。如何做到這一點呢?其一是提高收銀員的處理速度,他們處理的越快,單位時間內就能服務更多的顧客;其二是增加人手,一名收銀員處理不過來,我們就雇十名收銀員,十名不夠我們就雇傭一百名(如果不計成本);其三是減少訪問人數,也即分流過濾,將一些人提前過濾掉,或做活動預熱(比如雙十一預熱),在高峰之前先滿足一部分人的需求。因此,想要高并發(fā)無外乎從以下幾個方面入手:

提高處理速度:緩存、異步增加處理人手:多線程(多進程)、擴容減少訪問人數:預處理(本文不涉及)

提高處理速度

緩存

緩存之所以能夠提高處理速度,是因為不同設備的訪問速度存在差異。緩存的話題可以扯幾本書不帶重樣的。從CPU可以一直扯到客戶端緩存,即從最底層一直到扯到最特近用戶的一層,每一層都可能或可以有緩存的存在。我們這里不扯這么多,只說簡單服務端緩存?,F在從幾個不同角度來看一下緩存:

從效果角度。命中率越高越好嗎?10萬個店鋪數據,緩存了1000個,命中率穩(wěn)定100%,那是不是說,有99000個店鋪都是長尾店鋪?緩存效果評估不能單看命中率。從回收策略。如果把緩存當做數據庫一樣的存儲設備去用,那就沒有回收的說法了(除非重啟或者宕機,否則數據依然有效);如果只存儲熱數據,那就有回收和替換的問題?;厥沼袃煞N方式,一種是空間配額,另一種是時間配額。替換也有幾種方式,LRU,FIFO,LFU。從緩存使用模式角度:用戶直接操作緩存和db;用戶直接操作緩存,緩存幫助我們讀寫DbB;從緩存分級角度。java堆內緩存、java堆外緩存、磁盤緩存、分布式緩存,多級緩存。從緩存使用角度。null穿透問題、驚群問題、緩存熱點問題、緩存一致性問題、讀寫擴散問題。。。。。。更新方式。讀更新、寫更新、異步更新。

如果緩存集群涉及到異地多集群部署,再結合大數據量高并發(fā)業(yè)務場景,還會遇到很多更加復雜的問題,這里就不一一列舉了。

異步

異步這里有幾點內涵,其一是將多個同步調用變成異步并發(fā)調用,這樣就將總響應時間由原來的t1+t2+t3+…..+tn變成了max(t1,t2,t3….,tn),這也叫異步編排;其二是在操作系統(tǒng)層面,使用asyc io以提高io處理性能;其三是將請求’轉儲‘,稍后異步進行處理,一般使用隊列中間件。其中的異步編排,可以使用CompletableFuture;異步IO一般框架都做了封裝;而隊列中間件則是最為常用的技術之一,也是我們重點關注的對象。

業(yè)務允許延遲處理,是使用隊列中間件的大前提,即非實時系統(tǒng)或準實時系統(tǒng)更適合使用。主要作用有:異步處理(增加吞吐),削峰蓄洪(保障穩(wěn)定性),數據同步(最終一致性組件),系統(tǒng)解耦(下游無需感知訂閱方)。

緩沖隊列:一般使用環(huán)形緩沖隊列,控制緩沖區(qū)大小。
任務隊列:一般用于任務調度系統(tǒng),比如線程池等,disrupter
消息隊列:一般意義上的消息中間件,不同業(yè)務場景需要的中間件能力不同,有的需要高吞吐,有的需要支持事務,有的需要支持多客戶端,有的需要支持特定協(xié)議等等等等,妄圖開發(fā)一個大而全的消息隊列,個人覺得不如提供多種隊列按需選型,之后在統(tǒng)一提供一個通信中臺,全面整合消息能力。
請求隊列:就是處理請求的隊列,有點像流程引擎,可以做一些前置后置的入隊出隊處理,比如限流、過濾等等
數據總線隊列:比如canal,datax等數據(異構或同構)同步用的。
優(yōu)先級隊列:一般大根堆實現
副本隊列:如果隊列支持回放,副本隊列有些冗余。
鏡像隊列:一般用于做隊列系統(tǒng)的高可用切換的。有時候也跨集群跨機房做復制,提供更多消費者消費,增加投遞能力。

隊列的消費端有pull模式或者push模式的選取。pull模式可以控制進度,push模式則實時性更高一些;pull能支持單隊列上的有序,push很難支持。除了消費模式,隊列還有一系列其他問題請參考其他書籍,這里不多說明了。

這里在補充一點關于異步的說明。同步轉異步,可以提高吞吐量;異步轉同步,可以增加可靠性。

增加處理人手

多線程

多線程(多進程)技術是‘增加處理人手’技術中最容易想到的,一般我們也廣泛采用。無論是web服務容器、網關、RPC服務端、消息隊列消費和發(fā)送端等等都有使用多線程技術。其優(yōu)點也無需過多說明。這里我們只說一件重要的事情,即線程數的設置問題,如果線程數過高則可能會吃光系統(tǒng)資源,如果過低又無法發(fā)揮多線程優(yōu)勢。一般設置的時候,會參考平均處理時長、并發(fā)峰值、平均并發(fā)量、阻塞率、最長可容忍響應時間、CPU核心數等等,然后做一定的運算,計算出線程數、core和max,以及阻塞隊列大小。具體算法可以自行谷歌。

擴容

在無狀態(tài)服務下,擴容可能是迄今為止效果最明顯的增加并發(fā)量的技巧之一。有臨時性并發(fā)問題時,可以直接提擴容工單,立竿見影。但擴容的最大問題就是成本了,想想動輒幾萬的實體機,如果只是為了支撐一個小時的大促,而平常利用率幾乎為0,那確實是浪費。因此便有了彈性云,當需要擴容時,借別人機器(阿里云)用完再還回去;以及離線在線混部,充分利用資源。

從擴容方式角度講,分為垂直擴容(scale up)和水平擴容(scale out)。垂直擴容就是增加單機處理能力,懟硬件,但硬件能力畢竟還是有限;水平擴容說白了就是增加機器數量,懟機器,但隨著機器數量的增加,單應用并發(fā)能力并不一定與其呈現線性關系, 此時就可能需要進行應用服務化拆分了。

從數據角度講,擴容可以分為無狀態(tài)擴容和有狀態(tài)擴容。無狀態(tài)擴容一般就是指我們的應用服務器擴容;有狀態(tài)擴容一般是指數據存儲擴容,要么將一份數據拆分成不同的多份,即sharding,要么就整體復制n份,即副本。sharding遇到的問題就是分片的可靠性,一般做轉移、rehash、分片副本;副本遇到的問題是一致性性,一般做一致性算法,如paxos,raft等。

極客網企業(yè)會員

免責聲明:本網站內容主要來自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網站出現的信息,均僅供參考。本網站將盡力確保所提供信息的準確性及可靠性,但不保證有關資料的準確性及可靠性,讀者在使用前請進一步核實,并對任何自主決定的行為負責。本網站對有關資料所引致的錯誤、不確或遺漏,概不負任何法律責任。任何單位或個人認為本網站中的網頁或鏈接內容可能涉嫌侵犯其知識產權或存在不實內容時,應及時向本網站提出書面權利通知或不實情況說明,并提供身份證明、權屬證明及詳細侵權或不實情況證明。本網站在收到上述法律文件后,將會依法盡快聯系相關文章源頭核實,溝通刪除相關內容或斷開相關鏈接。

2017-11-16
高并發(fā)和高可用的一點思考
指導原則 書中所列舉的,里有一些可能并不是原則,而是技巧。我理解的原則如下: 高并發(fā)原則: 無狀態(tài)設計:因為有狀態(tài)可能涉及鎖操作,鎖又可能導致并發(fā)的串行

長按掃碼 閱讀全文