觀《億級流量網站架構核心技術》有感

本文的架子參考張開套的《億級流量網站架構核心技術》這本書分爲四個部分:指導原則,高可用,高併發,實踐案例。這篇文章說一說前三個部分,大部份內容都是我本身的思考,書只做爲參考。java

  • 指導原則
  • 高可用
    • 事前
      • 副本技術
      • 隔離技術
      • 配額技術
      • 探知技術
      • 預案
    • 事發
      • 監控和報警
    • 事中
      • 降級
      • 回滾
      • failXXX系列
    • 過後
  • 高併發
    • 提升處理速度
      • 緩存
      • 異步
    • 增長處理人手
      • 多線程
      • 擴容

指導原則

書中所列舉的,裏有一些可能並非原則,而是技巧。我理解的原則以下:mysql

高併發原則:web

  1. 無狀態設計:由於有狀態可能涉及鎖操做,鎖又可能致使併發的串行化。
  2. 保持合理的粒度:不管拆分仍是服務化,其實就是服務粒度控制,控制粒度爲了分散請求提升併發,或爲了從管理等角度提升可操性。
  3. 緩存、隊列、併發等技巧在高併發設計上可供參考,但需依場景使用。

高可用原則:算法

  1. 系統的任何發佈必須具備可回滾能力。
  2. 系統任何外部依賴必須準確衡量是否可降級,是否可無損降級,並提供降級開關。
  3. 系統對外暴露的接口必須配置好限流,限流值必須儘可能準確可靠。

業務設計原則:sql

  1. 安全性:防抓取,防刷單、防表單重複提交,等等等等。
  2. at least 消費,應考慮是否採用冪等設計
  3. 業務流程動態化,業務規則動態化
  4. 系統owner負責制、人員備份制、值班制
  5. 系統文檔化
  6. 後臺操做可追溯

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

高可用

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

爲了對抗這些不一樣級別的不肯定性,就要付出不一樣級別的成本,所以可用性也應是有標準的。這標準就是你們常說的N個9。隨着N的增長,成本也相應增長,那如何在達到業務須要的可用性的基礎上,儘可能節省成本?這也是一個值得思考的話題。除此以外,100%減去這N個9就說所謂的平均故障時間(MTBF),不少人只關心那些9,而忽略了故障處理時間,這是不應的:你的故障處理速度越快,系統的可用性纔有可能越高。緩存

上面扯了一些可用性概念上的東西,下面來講一下技巧。開濤的書中沒有對可用性技巧作出一個分類,我這裏則嘗試使用‘事情’來分個類。這裏的‘事’就是故障,分爲:事前(故障發生之前)、事發(故障發生到系統或人感知到故障)、事中(故障發生到故障處理這段時間)、過後(故障結束以後)。安全

按照上述分類,不一樣的階段應有着不一樣的技巧:性能優化

  1. 事前:副本、隔離、配額、提早預案、探知
  2. 事發:監控、報警
  3. 事中:降級、回滾、應急預案,failXXX系列
  4. 過後:覆盤、思考、技改

事前

副本技術

大天然是副本技術當之無愧的集大成者,不管是冰河時代,仍是隕石撞擊地球所帶來的毀滅性打擊,物種依然綿綿不絕的繁衍,這即是基因複製的做用。副本是對抗不肯定性的有力武器,把副本技術引入計算機系統,也會帶來高可用性的提高。無狀態服務集羣即是副本的一個應用,由於沒有狀態,即可水平伸縮,而這些無狀態服務器之間須要一層代理來統一調度管理,這便有了反向代理。當代理經過心跳檢測機制檢測到有一臺機器出現問題時,就將其下線,其餘‘副本’機器繼續提供服務;存儲領域也是常用副本技術的,好比OB的三地三中心五副本技術等,mysql主備切換,rabbitMQ的鏡像隊列,磁盤的RAID技術,各類nosql中的分區副本,等等等等,數不勝數,幾乎全部保證高可用的系統都有冗餘副本存在。

隔離技術

書上提到了不少種隔離:線程隔離、進程隔離、集羣隔離、機房隔離、讀寫隔離、動靜隔離、爬蟲隔離、熱點隔離、硬件資源隔離。在我看來,這些隔離其實就是一種,即資源隔離,不管線程、進程、硬件、機房、集羣都是一種資源;動態資源和靜態資源也不過是資源的一種分類;熱點隔離也便是熱點資源和非熱點資源的隔離;讀寫隔離不過僅僅是資源的使用方式而已,相同的兩份資源,一份用來寫,一份用來讀。所以,隔離的本質,其實就是對資源的獨立保護。由於每一個資源都獲得了獨立的保護,其中一個資源出了問題,不會影響到其餘資源,這就提升了總體服務的可用性。人類使用隔離術也由來已久了,從農業養殖,到股票投資,甚相當犯人的監獄,都能找到隔離術的影子。

配額技術

配額技術經過限制資源供給來保護系統,從而提升總體可用性。限流是配額技術的一種,它經過調節入口流量水位上線,來避免供給不足所致使的服務宕機。限流分爲集羣限流和單機限流,集羣限流須要分佈式基礎設施配合,單機限流則不須要。大部分業務場景使用單機限流足以,特殊場景(類秒殺等)下的限流則需限制整個集羣。除此以外,限流這裏咱們還須要考慮幾點:

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

探知技術

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

預案

預案通常分爲提早預案(事前)和應急預案(事中)。提早預案提早執行,好比將系統臨時從高峯模式切換成節能模式;應急預案關鍵時刻才執行,主要用於止血,好比一鍵容災切換等。預案技術通常要配合開關使用,推預案通常也就是推開關了。除此以外,預案也可和限流、回滾、降級等相結合,並能夠做爲一個按期演練項目。

事發

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

監控和報警

通常出現故障的時候,老闆大多會有三問:爲何才發現?爲何才解決?影響有多大?即便故障影響面較大,若是能迅速止血,在作覆盤的時候多少能挽回一些面子,相反若是處理不及時,即便小小的故障,均可能讓你丟了飯碗。越早識別故障,就能越早解決問題,而這眼睛即是監控和報警了。監控報警耳熟能詳,這裏很少贅述。

事中

事中是指當故障發生時,爲了保證系統可用性,咱們能夠或必須作的事情。分爲降級、回滾、應急預案(見上文,這裏很少數了),faillXXX系列。

降級

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

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

回滾

當執行某種變動出現故障時,最爲穩妥和有效的辦法就是回滾。雖然回滾行之有效,但並不簡單,由於回滾有一個大前提:變動必須具備可回滾性。而讓某一種變動具備可回滾的特性,是要耗費很大力氣的。索性的是,大部分基礎服務已經幫咱們封裝好了這一特性,好比DB的事務回滾(DB事務機制),代碼庫回滾(GIT的文件版本控制),發佈回滾(發佈系統支持)等等。咱們在平常變動操做的時候,必需要肯定你的操做是否可回滾,並盡力保證全部變動都可回滾。若是不能回滾,是否能夠進行熱更新(好比發佈應用到app store)或最終一致性補償等額外手段保證系統高可用。

failXXX系列

當出現下游調用失敗時,咱們通常有幾種處理方式:

  1. failretry,即失敗重試,須要配合退避時間,不然立刻重試不必定會有效果。
  2. failover,即所謂的故障轉移。好比調用下游a接口失敗,那麼RPC的負載均衡器將會調用a接口提供方的其餘機器進行重試;在好比數據庫x掛了,應用自適應容災將對x庫的調用切換到y庫調用,此y庫便可以是faillover庫(流水型業務),也能夠備庫(狀態型業務)。
  3. failsafe,即靜默,通常下游鏈路是弱依賴的時候,能夠採用failsafe,便可和failover相結合,好比failover了3次仍是失敗,那麼執行failsafe。
  4. failfast,當即報錯,failfast主要讓工程師快速的感知問題所在,並及時進行人工干預。
  5. failback,延遲補償(回血),通常能夠採用消息隊列或定時掃描等。

上面的1,2,4是屬於重試策略,即書中《超時與重試》章節所講到的重試。重試有個問題:退避間隔是多少?重試幾回?通常在下游臨時抖動的狀況下,很短期內就能夠恢復;但當下遊徹底不可用,那麼頗有可能重試多少次都不會成功,反而會對下游形成了更大的壓力,那這種狀況就應當作用熔斷了。因此正確設定重試次數、選擇退避時間等都是須要仔細思考的。咱們在來講一下超時,超時只是一種預防機制,不是故障應對策略,其主要爲了防止請求堆積——資源都用於等待下游請求返回了。堆積的後果自不用多說,重要的是如何選擇正確的超時時間?書上只說了鏈路每一個部分超時時間怎麼配置,殊不知道應配置多少,這是不夠全面的。

過後

覆盤、思考、技改。很少贅述。

高併發

若是僅是追求高可用性,這其實並不難作,試想若是一年只有一我的訪問你的系統,只要這一我的訪問成功,那你係統的‘’可用性‘就是100%了。可現實是,隨着業務的發展,請求量會愈來愈高,進而各類系統資源得以激活,那潛在風險也會慢慢的暴露出來。所以,作系統的難點之一即是:如何在高併發的條件下,保證系統的高可用。上文已經說了一些保證高可用的技巧,這節將結合開濤的書,說說高併發。

說到這裏,也給你們推薦一個交流平臺:架構交流羣650385180,裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理、併發編程原理,JVM性能優化這些成爲架構師必備的知識體系。還能領取免費的學習資源,相信對於已經工做和遇到技術瓶頸的碼友,在這個羣裏必定有你須要的內容。

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

  1. 提升處理速度:緩存、異步
  2. 增長處理人手:多線程(多進程)、擴容
  3. 減小訪問人數:預處理(本文不涉及)

提升處理速度

緩存

緩存之因此可以提升處理速度,是由於不一樣設備的訪問速度存在差別。緩存的話題能夠扯幾本書不帶重樣的。從CPU能夠一直扯到客戶端緩存,即從最底層一直到扯到最特近用戶的一層,每一層均可能或能夠有緩存的存在。咱們這裏不扯這麼多,只說簡單服務端緩存。如今從幾個不一樣角度來看一下緩存:

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

若是緩存集羣涉及到異地多集羣部署,再結合大數據量高併發業務場景,還會遇到不少更加複雜的問題,這裏就不一一列舉了。

異步

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

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

緩衝隊列:通常使用環形緩衝隊列,控制緩衝區大小。
任務隊列:通常用於任務調度系統,好比線程池等,disrupter
消息隊列:通常意義上的消息中間件,不一樣業務場景須要的中間件能力不一樣,有的須要高吞吐,有的須要支持事務,有的須要支持多客戶端,有的須要支持特定協議等等等等,妄圖開發一個大而全的消息隊列,我的以爲不如提供多種隊列按需選型,以後在統一提供一個通訊中臺,全面整合消息能力。
請求隊列:就是處理請求的隊列,有點像流程引擎,能夠作一些前置後置的入隊出隊處理,好比限流、過濾等等
數據總線隊列:好比canal,datax等數據(異構或同構)同步用的。
優先級隊列:通常大根堆實現
副本隊列:若是隊列支持回放,副本隊列有些冗餘。
鏡像隊列:通常用於作隊列系統的高可用切換的。有時候也跨集羣跨機房作複製,提供更多消費者消費,增長投遞能力。

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

這裏在補充一點關於異步的說明。同步轉異步,能夠提升吞吐量;異步轉同步,能夠增長可靠性。

增長處理人手

多線程

多線程(多進程)技術是‘增長處理人手’技術中最容易想到的,通常咱們也普遍採用。不管是web服務容器、網關、RPC服務端、消息隊列消費和發送端等等都有使用多線程技術。其優勢也無需過多說明。這裏咱們只說一件重要的事情,即線程數的設置問題,若是線程數太高則可能會吃光系統資源,若是太低又沒法發揮多線程優點。通常設置的時候,會參考平均處理時長、併發峯值、平均併發量、阻塞率、最長可容忍響應時間、CPU核心數等等,而後作必定的運算,計算出線程數、core和max,以及阻塞隊列大小。具體算法能夠自行谷歌。

擴容

在無狀態服務下,擴容多是迄今爲止效果最明顯的增長併發量的技巧之一。有臨時性併發問題時,能夠直接提擴容工單,立竿見影。但擴容的最大問題就是成本了,想一想動輒幾萬的實體機,若是隻是爲了支撐一個小時的大促,而日常利用率幾乎爲0,那確實是浪費。所以便有了彈性雲,當須要擴容時,借別人機器(阿里雲)用完再還回去;以及離線在線混部,充分利用資源。

從擴容方式角度講,分爲垂直擴容(scale up)和水平擴容(scale out)。垂直擴容就是增長單機處理能力,懟硬件,但硬件能力畢竟仍是有限;水平擴容說白了就是增長機器數量,懟機器,但隨着機器數量的增長,單應用併發能力並不必定與其呈現線性關係, 此時就可能須要進行應用服務化拆分了。

從數據角度講,擴容能夠分爲無狀態擴容和有狀態擴容。無狀態擴容通常就是指咱們的應用服務器擴容;有狀態擴容通常是指數據存儲擴容,要麼將一份數據拆分紅不一樣的多份,即sharding,要麼就總體複製n份,即副本。sharding遇到的問題就是分片的可靠性,通常作轉移、rehash、分片副本;副本遇到的問題是一致性性,通常作一致性算法,如paxos,raft等。

相關文章
相關標籤/搜索