高可用並非一套總體解決方案,而是由諸多環節組成,一環扣一環,鬼知道爲了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。前端
在定義什麼是高可用,能夠先定義下什麼是不可用,一個網站的內容最終呈如今用戶面前須要通過若干個環節,而其中只要任何一個環節出現了故障,均可能致使網站頁面不可訪問,這個也就是網站不可用的狀況。java
參考維基百科,看看維基怎麼定義高可用mysql
系統無中斷地執行其功能的能力,表明系統的可用性程度,是進行系統設計時的準則之一。nginx
這個難點或是重點在於「無中斷」,要作到 7 x 24 小時無中斷無異常的服務提供。redis
一套對外提供服務的系統是須要硬件,軟件相結合,可是咱們的軟件會有bug,硬件會慢慢老化,網絡老是不穩定,軟件會愈來愈複雜和龐大,除了硬件軟件在本質上沒法作到「無中斷」,外部環境也可能致使服務的中斷,例如斷電,地震,火災,光纖被挖掘機挖斷,這些影響的程度可能更大。算法
在業界有一套比較出名的評定網站可用性的指標,經常使用N個9來量化可用性,能夠直接映射到網站正常運行時間的百分比上sql
描述 | N個9 | 可用性級別 | 年度停機時間 |
---|---|---|---|
基本可用 | 2個9 | 99% | 87.6小時 |
較高可用 | 3個9 | 99% | 8.8小時 |
具有故障自動恢復能力可用 | 4個9 | 99.99% | 53分鐘 |
極高可用 | 5個9 | 99.999% | 5分鐘 |
以前就任的一家互聯網公司也是按照這個指標去界定可用性,不過在執行的過程當中也碰到了一些問題,例如,有一些服務的升級或數據遷移明明能夠在深夜停機或停服務進行,然而考慮到之後的報告要顯示出咱們的系統達到了多少個9的高可用,而放棄停服務這種簡單的解決方案,例如停機2個小時,就永遠也達不到4個9。然而在一些高併發的場合,例如在秒殺或拼團,雖然服務中止了幾分鐘,可是這個對整個公司業務的影響多是很是重大的,分分鐘丟失的訂單多是一個龐大的數量。因此N個9來量化可用性其實也得考慮業務的狀況。docker
高可用是一個比較複雜的命題,基本上在全部的處理中都會涉及到高可用,全部在設計高可用方案也涉及到了方方面面,這中間將會出現的細節是多種多樣的,因此咱們須要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下咱們手裏有多少張牌。數據庫
每個訪問可能都會有多個服務組成而成,每一個機器每一個服務均可能出現問題,因此第一個考慮到的就是每一個服務必須不止一份能夠是多份,所謂多份一致的服務就是服務的冗餘,這裏說的服務泛指了機器的服務,容器的服務,還有微服務自己的服務。後端
在機器服務層面須要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘 ,例如是否全部機器是否有分別部署在不一樣機房,若是在同一個機房是否作到了部署在不一樣的機櫃,若是是docker容器是否部署在分別不一樣的物理機上面。 採起的策略其實也仍是根據服務的業務而定,因此須要對服務進行分級評分,從而採起不一樣的策略,不一樣的策略安全程度不一樣,伴隨這的成本也是不一樣,安全等級更高的服務可能還不止考慮不一樣機房,還須要把各個機房所處的區域考慮進行,例如,兩個機房不要處在同一個地震帶上等等
服務的冗餘會要求咱們能夠隨時對服務進行擴容或者縮容,有可能咱們會從2臺機器變成3臺機器,想要對服務進行隨時隨地的擴縮容,就要求咱們的服務是一個無狀態化,所謂無狀態化就是每一個服務的服務內容和數據都是一致的。
例如,從咱們的微服務架構來看,咱們總共分水平劃分了好幾個層,正由於咱們每一個層都作到了無狀態,因此在這個水平架構的擴張是很是的簡單。
假設,咱們須要對網關進行擴容,咱們只須要增長服務就能夠,而不須要去考慮網關是否存儲了一個額外的數據。
網關不保存任何的session數據,不提供會形成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。
這個是目前主流的方案,服務自己儘量提供邏輯的服務,將數據的一致性保證集中式處理,這樣就能夠把「狀態」抽取出來,讓網關保持一個「無狀態」
這裏僅僅是舉了網關的例子,在微服務只基本全部的服務,都應該按照這種思路去作,若是服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。
以前上面說的服務冗餘,能夠簡單的理解爲計算的高可用,計算高可用只須要作到無狀態既可簡單的擴容縮容,可是對於須要存儲數據的系統來講,數據自己就是有狀態。
跟存儲與計算相比,有一個本質的差異:
將數據從一臺機器搬到另外一臺機器,須要通過線路進行傳輸
網絡是不穩定的,特別是跨機房的網絡,ping的延時多是幾十幾百毫秒,雖然毫秒對於人來講幾乎沒有什麼感受,可是對於高可用系統來講,就是本質上的不一樣,這意味着整個系統在某個時間點上,數據確定是不一致的。按照「數據+邏輯=業務」的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。舉個例子
不管是正常狀況下的傳輸延時,仍是異常狀況下的傳輸中斷,都會致使系統的數據在某個時間點出現不一致,而數據的不一致又會致使業務出現問題,可是若是數據不作冗餘,系統的高可用沒法保證
因此,存儲高可用的難點不在於怎麼備份數據,而在於如何減小或者規避數據不一致對業務形成的影響
分佈式領域中有一個著名的CAP定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時知足「一致性,可用性,分區容錯性」,最多隻能知足2個,其中分區容錯在分佈式中是必須的,就意味着,咱們在作架構設計時必須結合業務對一致性和可用性進行取捨。
存儲高可用方案的本質是將數據複製到多個存儲設備中,經過數據冗餘的方式來現實高可用,其複雜度主要呈如今數據複製的延遲或中斷致使數據的不一致性,咱們在設計存儲架構時必須考慮到一下幾個方面:
主從複製是最多見的也是最簡單的存儲高可用方案,例如Mysql,redis等等
其架構的優勢就是簡單,主機複製寫和讀,而從機只負責讀操做,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操做也能夠保證讀業務的順利進行。
缺點就是客戶端必須感知主從關係的存在,將不一樣的操做發送給不一樣的機器進行處理,並且主從複製中,從機器負責讀操做,可能由於主從複製時延大,出現數據不一致性的問題。
剛說了主從切換存在兩個問題: 1.主機故障寫操做沒法進行 2.須要人工將其中一臺從機器升級爲主機
爲了解決這個兩個問題,咱們能夠設計一套主從自動切換的方案,其中設計到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。
1.主機狀態檢測
須要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操做不可執行,讀操做是否不可執行,將其進行彙總,交給切換決策
2.切換決策
肯定切換的時間決策,什麼狀況下從機就應該升級爲主機,是進程不存在,是寫操做不可這行,連續檢測多少失敗次就進行切換。應該選擇哪個從節點升級爲主節點,通常來講或應該選同步步驟最大的從節點來進行升級。切換是自動切換仍是半自動切換,經過報警方式,讓人工作一次確認。
3.數據丟失和數據衝突 數據寫到主機,尚未複製到從機主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保CP或AP
還要考慮一個數據衝突的問題,這個問題在mysql中大部分是由自增主鍵引發,就算不考慮自增主鍵會引發數據衝突的問題,其實自增主鍵還要引發不少的問題,這裏不細說,避免使用自增主鍵。
上述的數據冗餘能夠經過數據的複製來進行解決,可是數據的擴張須要經過數據的分片來進行解決(若是在關係型數據庫是分表)。
HDFS , mongoDB 的sharding 模式也基本是基於這種分片的模式去實現,咱們在設計分片主要考慮到的點是:
在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多存在失敗的風險也就越大,若是在業務容許的狀況下,用戶調用只給用戶必需要的結果,而不是須要同步的結果能夠放在另外的地方異步去操做,這就減小了超時的風險也把複雜業務進行拆分減低複雜度。
固然異步化的好處是很是多,例如削封解耦等等,這裏只是從可用的角度出發。
異步化大體有這三種的實現方式:
什麼是柔性化,想象一個場景,咱們的系統會給每一個下單的用戶增長他們下單金額對應的積分,當一個用戶下單完畢後,咱們給他增長積分的服務出現了問題,這個時候,咱們是要取消掉這個訂單仍是先讓訂單經過,積分的問題經過從新或者報警來處理呢?
所謂的柔性化,就是在咱們業務中容許的狀況下,作不到給予用戶百分百可用的經過降級的手段給到用戶儘量多的服務,而不是非得每次都交出去要麼100分或0分的答卷。
怎麼去作柔性化,更多實際上是對業務的理解和判斷,柔性化更可能是一種思惟,須要對業務場景有深刻的瞭解。
在電商訂單的場景中,下單,扣庫存,支付是必定要執行的步驟,若是失敗則訂單失敗,可是加積分,發貨,售後是能夠柔性處理,就算出錯也能夠經過日誌報警讓人工去檢查,不必爲加積分損失整個下單的可用性
兜底是可能咱們常常談論的是一種降級的方案,方案是用來實施,可是這裏兜底可能更可能是一種思想,更多的是一種預案,每一個操做均可以犯錯,咱們也能夠接受犯錯,可是每一個犯錯咱們都必須有一個兜底的預案,這個兜底的預案其實就是咱們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。
舉個例子:
例如咱們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,咱們不該該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,作到更加柔性化,這時候能夠選擇獲取以前沒有失敗接口的緩存數據,若是沒有則能夠獲取通用商品不用個性化推薦,若是也沒有能夠讀取一些靜態文字進行展現。
因爲咱們架構進行了分層,分紅APP,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。既然有代碼和人員架構的劃分層級,那麼每一層都必須有這樣的思想:包容下一層的錯誤,爲上一層提供儘量無措的服務。
舉個例子:
商品的美圓售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層若是直接進行除,確定就拋出 java.lang.ArithmeticException: / by zero,本着咱們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證咱們這一層對上一次儘量的做出最大努力肯定的服務。
相信負載均衡這個話題基本已經深刻每一個作微服務開發或設計者的人心,負載均衡的實現有硬件和軟件,硬件有F5,A10等機器,軟件有LVS,nginx,HAProxy等等,負載均衡的算法有 random , RoundRobin , ConsistentHash等等。
nginx 根據給定好的負載均衡算法進行調度,當請求到tomcat1,nginx發現tomcat1出現鏈接錯誤(節點失效),nginx會根據必定的機制將tomcat1從調用的負載列表中清除,在下一次請求,nginx不會分配請求到有問題的tomcat1上面,會將請求轉移到其餘的tomcat之上。
nginx默認判斷節點失效是以connect refuse和timeout爲標準,在對某個節點進行fails累加,當fails大於max_fails時,該節點失效。
當某個節點失敗的次數大於max_fails時,但不超過fail_timeout,nginx將不在對該節點進行探測,直到超過失效時間或者全部的節點都失效,nginx會對節點進行從新探測。
在使用ZK做爲註冊中心時,故障的發現是由Zk去進行發現,業務邏輯層經過watch的心跳機制將本身註冊到zk上,網關對zk進行訂閱就能夠知道有多少能夠調用的列表。當業務邏輯層在重啓或者被關閉時就會跟zk斷了心跳,zk會更新可調用列表。
使用zk做爲負載均衡的協調器,最大的問題是zk對於服務是否可用是基於pingpong的方式,只要服務心跳存在,zk就認爲服務是處在於可用狀態,可是服務若是處在於假死的狀態,zk是無從得知的。這個時候,業務邏輯服務是否真正可用只可以由網關知道。
爲什麼會牽出冪等設計的問題,主要是由於負載均衡的failover策略,就是對失敗的服務會進行重試,通常來講,若是是讀操做的服務,重複執行也不會出問題,但想象一下,若是是一個建立訂單減庫存的操做,第一次調用也tomcat1超時,再從新調用了tomcat2,這個時候咱們都不能確認超時調用的tomcat1是否真的被調用,有可能根本就調用不成功,有可能已經調用成功可是由於某些緣由返回超時而已,因此,很大程度這個接口會被調用2次。若是咱們沒有保證冪等性,就有可能一個訂單致使了減小2次的庫存。
所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了屢次,其致使的結果都是同樣的。
先來說講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間經過rpc框架通訊,整個系統發生故障的機率隨着系統規模的增加而增加,一個小的故障通過鏈路的傳遞放大,有可能會形成更大的故障。
限流跟高可用的關係是什麼,假定咱們的系統最多隻能承受500我的的併發訪問,但整個時候忽然增長到1000我的進來,一會兒就把整個系統給壓垮了,原本還有500我的能享受到咱們系統的服務,忽然間變成了全部人都沒法獲得服務,與其讓1000人都不法獲得服務,不如就讓500我的獲得服務,拒絕掉另外500我的。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。
熔斷跟高可用的關係是什麼,上面說了微服務是一個錯綜複雜的調用鏈關係,假設 模塊A 調用 模塊B , 模塊B 又調用了 模塊C , 模塊C 調用了 模塊D,這個時候,模塊D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被 模塊D 給拖垮,A 等B,B等C,C等D,並且A B C D的資源被鎖死得不到釋放,若是流量大的話還容易引發雪崩。熔斷,主動丟棄 模塊D 的調用,並在功能上做出一些降級才能保證到咱們系統的健壯性。 熔斷是對模塊的隔離,是保證了最大功能的可用性。
服務模塊與服務模塊之間有着千絲萬縷的關係,但服務模塊在業務中各有權重,例如訂單模塊多是一家電商公司的重中之重,若是出問題將會直接影響整個公司的營收,而一個後臺的查詢服務模塊可能也重要,但它的重要等級絕對是沒有像訂單這麼重要。因此,在作服務治理時,必須明確各個服務模塊的重要等級,這樣才能更好的作好監控,分配好資源。這個在各個公司有各個公司的一個標準,例如在電商公司,肯定服務的級別可能會更加傾向對用用戶請求數和營收相關的做爲指標。
服務級別 | 服務模塊 |
---|---|
一級服務 | 支付系統 訂單服務 商品服務 用戶服務 發佈系統 ... |
二級服務 | 消息服務 權限系統 CRM系統 積分系統 BI系統 評論系統 ... |
三級服務 | 後臺日誌系統 |
可能真正的劃分要比這個更爲複雜,必須根據具體業務去定,這個能夠從平時服務模塊的訪問量和流量去預估,每每更重要的模塊也會提供更多的資源,因此不只要對技術架構瞭如指掌,還要對公司各類業務形態瞭然於心才能夠。
服務分級不只僅在故障界定起到重要主要,並且決定了服務監控的力度,服務監控在高可用中起到了一個保障的做用,它不只能夠保留服務奔潰的現場以等待往後覆盤,更重要的是它能夠起到一個先知,先行判斷的角色,不少時候能夠預先判斷危險,防範於未然。
服務監控是微服務治理的一個重要環節,監控系統的完善程度直接影響到咱們微服務質量的好壞,咱們的微服務在線上運行的時候有沒有一套完善的監控體系能去了解到它的健康狀況,對整個系統的可靠性和穩定性是很是重要,可靠性和穩定性是高可用的一個前提保證。
服務的監控更可能是對於風險的預判,在出現不可用之間就提早的發現問題,若是系統獲取監控報警系統能自我修復則能夠將錯誤消滅在無形,若是系統發現報警沒法自我修復則能夠通知人員提前進行接入。
一個比較完善的微服務監控體系須要涉及到哪些層次,以下圖,大體能夠劃分爲五個層次的監控
例如網絡,交換機,路由器等低層設備,這些設備的可靠性穩定性就直接影響到上層服務應用的穩定性,因此須要對網絡的流量,丟包狀況,錯包狀況,鏈接數等等這些基礎設施的核心指標進行監控。
涵蓋了物理機,虛擬機,操做系統這些都是屬於系統級別監控的方面,對幾個核心指標監控,如cpu使用率,內存佔用率,磁盤IO和網絡帶寬狀況
例如對url訪問的性能,訪問的調用數,訪問的延遲,還有對服務提供性能進行監控,服務的錯誤率,對sql也須要進行監控,查看是否有慢sql,對與cache來講,須要監控緩存的命中率和性能,每一個服務的響應時間和qps等等
比方說一個電商網站,須要關注它的用戶登陸狀況,註冊狀況,下單狀況,支付狀況,這些直接影響到實際觸發的業務交易狀況,這個監控能夠提供給運營和公司高管他們需須要關注的數據,直接可能對公司戰略產生影響。
用戶經過瀏覽器,客戶端打開練到到咱們的服務,那麼在用戶端用戶的體驗是怎麼樣,用戶端的性能是怎麼樣,有沒有產生錯誤,這些信息也是須要進行監控並記錄下來,若是沒有監控,有可能用戶的由於某些緣由出錯或者性能問題形成體驗很是的差,而咱們並無感知,這裏麪包括了,監控用戶端的使用性能,返回碼,在哪些城市地區他們的使用狀況是怎麼樣,還有運營商的狀況,包括電信,聯通用戶的鏈接狀況。咱們須要進一步去知道是否有哪些渠道哪些用戶接入的時候存在着問題,包括咱們還須要知道客戶端使用的操做系統瀏覽器的版本。
出了那麼多張牌,出牌只是術,真正的道仍是得靜下心來看看整個服務高可用的本質是什麼,隨着微服務架構的相互調用愈來愈複雜,環節只會愈來愈多,只有創建清晰的架構和層次才能理清楚每一個環節高可用的保障,保持簡單。
從手段看高可用:主要使用的技術手段是服務和數據的冗餘備份和失效轉移,一組服務或一組數據都能在多節點上,之間相互備份,當一臺機器宕機或出現問題的時候,能夠從當前的服務切換到其餘可用的服務,不影響系統的可用性,也不會致使數據丟失。
從架構看高可用:保持簡單的架構,目前多數網站採用的是比較經典的分層架構,應用層,服務層,數據層。應用層是處理一些業務邏輯,服務層提供一些數據和業務緊密相關服務,數據層負責對數據進行讀寫,簡單的架構可使應用層,服務層能夠保持無狀態化進行水平擴展,這個屬於計算高可用,相比計算高可用,在數據層思考的高可用則屬於數據高可用,數據高可用相比計算高可用須要考慮到數據的一致性問題會更加的複雜,這個時候CAP理論在裏面會發揮關鍵的做用,到底是選擇AP或CP,這個得根據業務去選擇模型。
從硬件看高可用:首先得確認硬件老是可能壞的,網絡老是不穩定的。解決它的方法也是一個服務器不夠就來多幾個,一個機櫃不夠就來幾個,一個機房不夠就來幾個。
從軟件看高可用:軟件的開發不嚴謹,發佈不規範也是致使各類不可用出現,經過控制軟件開發過程質量監控,經過測試,預發佈,灰度發佈等手段也是減小不可用的措施。
從治理看高可用:一個系統在線上跑的好好的,但咱們也不能確保它在下一秒會不會出現不可用狀態,將服務規範化,事前作好服務分割,作好服務監控,預判不可用的出現,在不可用出現以前發現問題,解決問題。
【注:文章部份內容參考 李雲華《從0開始學架構》楊波老師《微服務》】