你覺(jué)得這玩意能叫高可用嗎?
一、前言
高可用(High availability,即 HA)的主要目的是為了保障「業(yè)務(wù)的連續(xù)性」,即在用戶眼里,業(yè)務(wù)永遠(yuǎn)是正常(或者說(shuō)基本正常)對(duì)外提供服務(wù)的。高可用主要是針對(duì)架構(gòu)而言,那么要做好高可用,就要首先設(shè)計(jì)好架構(gòu),第一步我們一般會(huì)采用分層的思想將一個(gè)龐大的 IT 系統(tǒng)拆分成為應(yīng)用層,中間件,數(shù)據(jù)存儲(chǔ)層等獨(dú)立的層,每一層再拆分成為更細(xì)粒度的組件,第二步就是讓每個(gè)組件對(duì)外提供服務(wù),畢竟每個(gè)組件都不是孤立存在的,都需要互相協(xié)作,對(duì)外提供服務(wù)才有意義。
要保證架構(gòu)的高可用,就要保證架構(gòu)中所有組件以及其對(duì)外暴露服務(wù)都要做高可用設(shè)計(jì),任何一個(gè)組件或其服務(wù)沒(méi)做高可用,都意味著系統(tǒng)存在風(fēng)險(xiǎn)。
那么這么多組件該怎么做高可用設(shè)計(jì)呢,其實(shí)任何組件要做高可用,都離不開(kāi)「冗余」和「自動(dòng)故障轉(zhuǎn)移」,眾所周知單點(diǎn)是高可用的大敵,所以組件一般是以集群(至少兩臺(tái)機(jī)器)的形式存在的,這樣只要某臺(tái)機(jī)器出現(xiàn)問(wèn)題,集群中的其他機(jī)器就可以隨時(shí)頂替,這就是「冗余」。簡(jiǎn)單計(jì)算一下,假設(shè)一臺(tái)機(jī)器的可用性為 90%,則兩臺(tái)機(jī)器組成的集群可用性為 1-0.1*0.1 = 99%,所以顯然冗余的機(jī)器越多,可用性越高。
但光有冗余還不夠,如果機(jī)器出現(xiàn)問(wèn)題,需要人工切換的話也是費(fèi)時(shí)費(fèi)力,而且容易出錯(cuò),所以我們還需要借助第三方工具(即仲裁者)的力量來(lái)實(shí)現(xiàn)「自動(dòng)」的故障轉(zhuǎn)移,以達(dá)到實(shí)現(xiàn)近實(shí)時(shí)的故障轉(zhuǎn)移的目的,近實(shí)時(shí)的故障轉(zhuǎn)移才是高可用的主要意義。
怎樣的系統(tǒng)可以稱之為高可用呢,業(yè)界一般用幾個(gè)九來(lái)衡量系統(tǒng)的可用性,如下:
一般實(shí)現(xiàn)兩個(gè) 9 很簡(jiǎn)單,畢竟每天宕機(jī) 14 分鐘已經(jīng)嚴(yán)重影響業(yè)務(wù)了,這樣的公司遲早歇菜,大廠一般要求 4 個(gè) 9,其他要求嚴(yán)苛的業(yè)務(wù)要達(dá)到五個(gè)九以上,比如如果因?yàn)橐粋€(gè)電腦的故障導(dǎo)致所有列車停駛,那么就會(huì)有數(shù)以萬(wàn)計(jì)的人正常生活受到阻礙,這種情況就要求五個(gè)九以上。
接下來(lái)我們就來(lái)一起看看架構(gòu)中的各個(gè)組件如何借助「冗余」和「自動(dòng)故障轉(zhuǎn)移」來(lái)實(shí)現(xiàn)高可用。
二、互聯(lián)網(wǎng)架構(gòu)剖析
目前多數(shù)互聯(lián)網(wǎng)都會(huì)采用微服務(wù)架構(gòu),常見(jiàn)架構(gòu)如下:
可以看到架構(gòu)主要分以下幾層
- 接入層:主要由 F5 硬件或 LVS 軟件來(lái)承載所有的流量入口
- 反向代理層:Nginx,主要負(fù)責(zé)根據(jù) url 來(lái)分發(fā)流量,限流等
- 網(wǎng)關(guān):主要負(fù)責(zé)流控,風(fēng)控,協(xié)議轉(zhuǎn)換等
- 站點(diǎn)層:主要負(fù)責(zé)調(diào)用會(huì)員,促銷等基本服務(wù)來(lái)裝配 json 等數(shù)據(jù)并返回給客戶端
- 基礎(chǔ) service:其實(shí)與站點(diǎn)層都屬于微服務(wù),是平級(jí)關(guān)系,只不過(guò)基礎(chǔ) service 屬于基礎(chǔ)設(shè)施,能被上層的各個(gè)業(yè)務(wù)層 server 調(diào)用而已
- 存儲(chǔ)層:也就是 DB,如 MySQL,Oracle 等,一般由基礎(chǔ) service 調(diào)用返回給站點(diǎn)層
- 中間件:ZK,ES,Redis,MQ 等,主要起到加速訪問(wèn)數(shù)據(jù)等功能,在下文中我們會(huì)簡(jiǎn)單介紹下各個(gè)組件的作用
如前所述,要實(shí)現(xiàn)整體架構(gòu)的高可用,必須要實(shí)現(xiàn)每一層組件的高可用,接下來(lái)我們就來(lái)分別看一下每一層的組件都是如何實(shí)現(xiàn)高可用的。
三、接入層&反向代理層
這兩層的高可用都和 keepalived 有關(guān),所以我們結(jié)合起來(lái)一起看
對(duì)外,兩個(gè) LVS 以主備的形式對(duì)外提供服務(wù),注意只有 master 在工作(即此時(shí)的 VIP 在 master 上生效),另外一個(gè) backup 在 master 宕機(jī)之后會(huì)接管 master 的工作,那么 backup 怎么知道 master 是否正常呢,答案是通過(guò) keepalived,在主備機(jī)器上都裝上 keepalived 軟件,啟動(dòng)后就會(huì)通過(guò)心跳檢測(cè)彼此的健康狀況,一旦 master 宕機(jī),keepalived 會(huì)檢測(cè)到,從而 backup 自動(dòng)轉(zhuǎn)成 master 對(duì)外提供服務(wù),此時(shí) VIP 地址(即圖中的 115.204.94.139)即在 backup 上生效,也就是我們常說(shuō)的「IP漂移」,通過(guò)這樣的方式即解決了 LVS 的高可用。
keepalived 的心跳檢測(cè)主要通過(guò)發(fā)送 ICMP 報(bào)文,或者利用 TCP 的端口連接和掃描檢測(cè)來(lái)檢測(cè)的,同樣的,它也可以用來(lái)檢測(cè) Nginx 暴露的端口,這樣的話如果某些 Nginx 不正常 Keepalived 也能檢測(cè)到并將其從 LVS 能轉(zhuǎn)發(fā)的服務(wù)列表中剔出。Nginx也能通過(guò)端口檢測(cè)服務(wù)健康狀態(tài)。
借用 keepalived 這個(gè)第三方工具,同時(shí)實(shí)現(xiàn)了 LVS 和 Nginx 的高可用,同時(shí)在出現(xiàn)故障時(shí)也可以將宕機(jī)情況發(fā)送到對(duì)應(yīng)開(kāi)發(fā)人員的郵箱以讓他們及時(shí)收到通知處理,確實(shí)很方便,Keepalived 應(yīng)用廣泛,下文我們會(huì)看到它也可以用在 MySQL 上來(lái)實(shí)現(xiàn) MySQL 的高可用。
四、微服務(wù)
接下來(lái)我們?cè)賮?lái)看一下「網(wǎng)關(guān)」,「站點(diǎn)層」,「基礎(chǔ)服務(wù)層」,這三者一般就是我們所說(shuō)的微服務(wù)架構(gòu)組件,當(dāng)然這些微服務(wù)組件還需要通過(guò)一些 RPC 框架如 Dubbo 來(lái)支撐才能通信,所以微服務(wù)要實(shí)現(xiàn)高可用,就意味著 dubbo 這些 RPC 框架也要提供支撐微服務(wù)高可用的能力,我們就以 dubbo 為例來(lái)看下它是如何實(shí)現(xiàn)高可用的。
我們先來(lái)簡(jiǎn)單地看下 dubbo 的基本架構(gòu):
思路也很簡(jiǎn)單,首先是 Provider(服務(wù)提供者)向 Registry(注冊(cè)中心,如 ZK 或 Nacos 等)注冊(cè)服務(wù),然后 Consumer(服務(wù)消費(fèi)者)向注冊(cè)中心訂閱和拉取 Provider 服務(wù)列表,獲取服務(wù)列表后,Consumer 就可以根據(jù)其負(fù)載均衡策略選擇其中一個(gè) Provider 來(lái)向其發(fā)出請(qǐng)求,當(dāng)其中某個(gè) Provider 不可用(下線或者因?yàn)?GC 阻塞等)時(shí),會(huì)被注冊(cè)中心及時(shí)監(jiān)聽(tīng)(通過(guò)心跳機(jī)制)到,也會(huì)及時(shí)推送給 Consumer,這樣 Consumer 就能將其從可用的 Provider 列表中剔除,也就實(shí)現(xiàn)了故障的自動(dòng)轉(zhuǎn)移,不難看出,注冊(cè)中心就起到了類似 keepalived 的作用。
五、中間件
我們?cè)賮?lái)看下這些中間件如 ZK,Redis等是如何實(shí)現(xiàn)高可用的呢?
1、ZK
上一節(jié)微服務(wù)中我們提到了注冊(cè)中心,那我們就以 ZK(ZooKeeper)為例來(lái)看看它的高可用是如何實(shí)現(xiàn)的,先來(lái)看下它的整體架構(gòu)圖如下:
Zookeeper 中的主要角色如下
1)Leader:即領(lǐng)導(dǎo)者,在集群中只有一個(gè) Leader,主要承擔(dān)了以下的功能
- 事務(wù)請(qǐng)求的唯一調(diào)度和處理者,保證集群事務(wù)處理的順序性,所有 Follower 的寫(xiě)請(qǐng)求都會(huì)轉(zhuǎn)給 Leader 執(zhí)行,用來(lái)保證事務(wù)的一致性
- 集群內(nèi)部各服務(wù)器的調(diào)度者:處理好事務(wù)請(qǐng)求后,會(huì)將數(shù)據(jù)廣播同步到各個(gè) Follower,統(tǒng)計(jì) Follower 寫(xiě)入成功的數(shù)量,超過(guò)半數(shù) Follower 寫(xiě)入成功,Leader 就會(huì)認(rèn)為寫(xiě)請(qǐng)求提交成功,通知所有的 Follower commit 這個(gè)寫(xiě)操作,保證事后哪怕是集群崩潰恢復(fù)或者重啟,這個(gè)寫(xiě)操作也不會(huì)丟失。
2)Follower:
- 處理客戶端非事務(wù)請(qǐng)求、轉(zhuǎn)發(fā)事務(wù)請(qǐng)求給 leader 服務(wù)器
- 參與事物請(qǐng)求 Proposal 的投票(需要半數(shù)以上服務(wù)器通過(guò)才能通知 leader commit 數(shù)據(jù); Leader 發(fā)起的提案,要求 Follower 投票)
- 參與 Leader 選舉的投票
畫(huà)外音:Zookeeper 3.0 之后新增了一種 Observer 的角色,不過(guò)與此處討論的 ZK 高可用關(guān)系不是很大,為了簡(jiǎn)化問(wèn)題,所以省略。
可以看到由于只有一個(gè) Leader,很顯然,此 Leader 存在單點(diǎn)隱患,那么 ZK 是怎么解決此問(wèn)題的呢,首先 Follower 與 Leader 會(huì)用心跳機(jī)制保持連接,如果 Leader 出現(xiàn)問(wèn)題了(宕機(jī)或者因?yàn)?FullGC 等原因無(wú)法響應(yīng)),F(xiàn)ollower 就無(wú)法感知到 Leader 的心跳,就會(huì)認(rèn)為 Leader 出問(wèn)題了,于是它們就會(huì)發(fā)起投票選舉,最終在多個(gè) Follower 中選出一個(gè) Leader 來(lái)(這里主要用到了 Zookeeper Atomic Broadcast,即 ZAB 協(xié)議,它是為 ZK 專門設(shè)計(jì)的一種支持崩潰恢復(fù)的一致性協(xié)議),選舉的細(xì)節(jié)不是本文重點(diǎn),就不在此詳述了。
除了 ZAB 協(xié)議,業(yè)界上常用的還有 Paxos,Raft 等協(xié)議算法,也可以用在 Leader 選舉上,也就是是在分布式架構(gòu)中,這些協(xié)議算法承擔(dān)了“第三者”也就是仲裁者的作用,以承擔(dān)故障的自動(dòng)轉(zhuǎn)移。
2、Redis
Redis 的高可用需要根據(jù)它的部署模式來(lái)看看,主要分為「主從模式」和「Cluster 分片模式」兩種。
1)主從模式
先來(lái)看一下主從模式,架構(gòu)如下:
主從模式即一主多從(一個(gè)或者多個(gè)從節(jié)點(diǎn)),其中主節(jié)點(diǎn)主要負(fù)責(zé)讀和寫(xiě),然后會(huì)將數(shù)據(jù)同步到多個(gè)從節(jié)點(diǎn)上,Client 也可以對(duì)多個(gè)從節(jié)點(diǎn)發(fā)起讀請(qǐng)求,這樣可以減輕主節(jié)點(diǎn)的壓力,但和 ZK 一樣,由于只有一個(gè)主節(jié)點(diǎn),存在單點(diǎn)隱患,所以必須引入第三方仲裁者的機(jī)制來(lái)判定主節(jié)點(diǎn)是否宕機(jī)以及在判定主節(jié)點(diǎn)宕機(jī)后快速選出某個(gè)從節(jié)點(diǎn)來(lái)充當(dāng)主節(jié)點(diǎn)的角色,這個(gè)第三方仲裁者在 Redis 中我們一般稱其為「哨兵」(sentinel),當(dāng)然哨兵進(jìn)程本身也有可能掛掉,所以為了安全起見(jiàn),需要部署多個(gè)哨兵(即哨兵集群)。
這些哨兵通過(guò) gossip(流言) 協(xié)議來(lái)接收關(guān)于主服務(wù)器是否下線的信息,并在判定主節(jié)點(diǎn)宕機(jī)后使用 Raft 協(xié)議來(lái)選舉出新的主節(jié)點(diǎn)。
2)Cluster 分片集群
主從模式看似完美,但存在以下幾個(gè)問(wèn)題:
- 主節(jié)點(diǎn)寫(xiě)的壓力難以降低:因?yàn)橹挥幸粋€(gè)主節(jié)點(diǎn)能接收寫(xiě)請(qǐng)求,如果在高并發(fā)的情況下,寫(xiě)請(qǐng)求如果很高的話可能會(huì)把主節(jié)點(diǎn)的網(wǎng)卡打滿,造成主節(jié)點(diǎn)對(duì)外無(wú)法服務(wù)
- 主節(jié)點(diǎn)的存儲(chǔ)能力受到單機(jī)存儲(chǔ)容量的限制:因?yàn)椴还苁侵鞴?jié)點(diǎn)還是從節(jié)點(diǎn),存儲(chǔ)的都是全量緩存數(shù)據(jù),那么隨著業(yè)務(wù)量的增長(zhǎng),緩存數(shù)據(jù)很可能直線上升,直到達(dá)到存儲(chǔ)瓶頸
- 同步風(fēng)暴:因?yàn)閿?shù)據(jù)都是從 master 同步到 slave 的,如果有多個(gè)從節(jié)點(diǎn)的話,master 節(jié)點(diǎn)的壓力會(huì)很大
為了解決主從模式的以上問(wèn)題,分片集群應(yīng)運(yùn)而生,所謂分片集群即將數(shù)據(jù)分片,每一個(gè)分片數(shù)據(jù)由相應(yīng)的主節(jié)點(diǎn)負(fù)責(zé)讀寫(xiě),這樣的話就有多個(gè)主節(jié)點(diǎn)來(lái)分擔(dān)寫(xiě)的壓力,并且每個(gè)節(jié)點(diǎn)只存儲(chǔ)部分?jǐn)?shù)據(jù),也就解決了單機(jī)存儲(chǔ)瓶頸的問(wèn)題,但需要注意的是每個(gè)主節(jié)點(diǎn)都存在單點(diǎn)問(wèn)題,所以需要針對(duì)每個(gè)主節(jié)點(diǎn)做高可用,整體架構(gòu)如下:
原理也很簡(jiǎn)單,在 Proxy 收到 client 執(zhí)行的 redis 的讀寫(xiě)命令后,首先會(huì)對(duì) key 進(jìn)行計(jì)算得出一個(gè)值,如果這個(gè)值落在相應(yīng) master 負(fù)責(zé)的數(shù)值范圍(一般將每個(gè)數(shù)字稱為槽,Redis 一共有 16384 個(gè)槽)之內(nèi),那就把這條 redis 命令發(fā)給對(duì)應(yīng)的 master 去執(zhí)行,可以看到每個(gè) master 節(jié)點(diǎn)只負(fù)責(zé)處理一部分的 redis 數(shù)據(jù),同時(shí)為了避免每個(gè) master 的單點(diǎn)問(wèn)題,也為其配備了多個(gè)從節(jié)點(diǎn)以組成集群,當(dāng)主節(jié)點(diǎn)宕機(jī)時(shí),集群會(huì)通過(guò) Raft 算法來(lái)從從節(jié)點(diǎn)中選舉出一個(gè)主節(jié)點(diǎn)。
3、ES
再來(lái)看一下 ES 是如何實(shí)現(xiàn)高可用的,在 ES 中,數(shù)據(jù)是以分片(Shard)的形式存在的,如下圖所示,一個(gè)節(jié)點(diǎn)中索引數(shù)據(jù)共分為三個(gè)分片存儲(chǔ):
但只有一個(gè)節(jié)點(diǎn)的話,顯然存在和 Redis 的主從架構(gòu)一樣的單點(diǎn)問(wèn)題,這個(gè)節(jié)點(diǎn)掛了,ES 也就掛了,所以顯然需要?jiǎng)?chuàng)建多個(gè)節(jié)點(diǎn)。
一旦創(chuàng)建了多個(gè)節(jié)點(diǎn),分片(圖中 P 為主分片,R 為副本分片)的優(yōu)勢(shì)就體現(xiàn)出來(lái)了,可以將分片數(shù)據(jù)分布式存儲(chǔ)到其它節(jié)點(diǎn)上,極大提升了數(shù)據(jù)的水平擴(kuò)展能力,同時(shí)每個(gè)節(jié)點(diǎn)都能承擔(dān)讀寫(xiě)請(qǐng)求,采用負(fù)載均衡的形式避免了單點(diǎn)的讀寫(xiě)壓力。
ES 的寫(xiě)機(jī)制與 Redis 和 MySQL 的主從架構(gòu)有些差別(后兩者的寫(xiě)都是直接向 master 節(jié)點(diǎn)發(fā)起寫(xiě)請(qǐng)求,而 ES 則不是),所以這里稍微解釋一下 ES 的工作原理:
首先說(shuō)下節(jié)點(diǎn)的工作機(jī)制,節(jié)點(diǎn)(Node)分為主節(jié)點(diǎn)(Master Node)和從結(jié)點(diǎn)(Slave Node),主節(jié)點(diǎn)的主要職責(zé)是負(fù)責(zé)集群層面的相關(guān)操作,管理集群變更,如創(chuàng)建或刪除索引,跟蹤哪些節(jié)點(diǎn)是集群的一部分,并決定哪些分片分配給相關(guān)的節(jié)點(diǎn),主節(jié)點(diǎn)也只有一個(gè),一般通過(guò)類 Bully 算法來(lái)選舉出來(lái),如果主節(jié)點(diǎn)不可用了,則其他從節(jié)點(diǎn)也可以通過(guò)此算法來(lái)選舉以實(shí)現(xiàn)集群的高可用,任何節(jié)點(diǎn)都可以接收讀寫(xiě)請(qǐng)求以達(dá)到負(fù)載均衡的目的。
再說(shuō)一下分片的工作原理,分片分為主分片(Primary Shard,即圖中 P0,P1,P2)和副本分片(Replica Shard,即圖中 R0,R1,R2),主分片負(fù)責(zé)數(shù)據(jù)的寫(xiě)操作,所以雖然任何節(jié)點(diǎn)可以接收讀寫(xiě)請(qǐng)求,但如果此節(jié)點(diǎn)接收的是寫(xiě)請(qǐng)求并且沒(méi)有寫(xiě)數(shù)據(jù)所在的主分片話,此節(jié)點(diǎn)會(huì)將寫(xiě)請(qǐng)求調(diào)度到主分片所在的節(jié)點(diǎn)上,寫(xiě)入主分片后,主分片再把數(shù)據(jù)復(fù)制到其他節(jié)點(diǎn)的副本分片上,以有兩個(gè)副本的集群為例,寫(xiě)操作如下:
4、MQ
ES 利用數(shù)據(jù)分片來(lái)提升高可用和水平擴(kuò)展能力的思想也應(yīng)用在其他組件的架構(gòu)設(shè)計(jì)上,我們以 MQ 中的 Kafka 為例再來(lái)看下數(shù)據(jù)分片的應(yīng)用:
Kafka 高可用設(shè)計(jì),圖片來(lái)自《武哥漫談IT》
如上是 Kafka 集群,可以看到每個(gè) Topic 的 Partition 都分布式存儲(chǔ)在其它消息服務(wù)器上,這樣一旦某個(gè) Partition 不可用,可以從 follower 中選舉出 leader 繼續(xù)服務(wù),不過(guò)與 ES 中的數(shù)據(jù)分片不同的是,follower Partition 屬于冷備,也就是說(shuō)在正常情況下不會(huì)對(duì)外服務(wù),只有在 leader 掛掉之后從 follower 中選舉出 leader 后它才能對(duì)外提供服務(wù)。
六、存儲(chǔ)層
接下來(lái)我們?cè)賮?lái)看一下最后一層,存儲(chǔ)層(DB),這里我們以 MySQL 為例來(lái)簡(jiǎn)單地討論一下其高可用設(shè)計(jì),其實(shí)大家如果看完了以上的高可用設(shè)計(jì),會(huì)發(fā)現(xiàn) MySQL 的高可用也不過(guò)如此,思想都是類似的,與 Redis 類似,它也分主從和分片(即我們常說(shuō)的分庫(kù)分表)兩種架構(gòu)。
主從的話與 LVS 類似,一般使用 keepalived 的形式來(lái)實(shí)現(xiàn)高可用,如下所示:
如果 master 宕機(jī)了,Keepalived 也會(huì)及時(shí)發(fā)現(xiàn),于是從庫(kù)會(huì)升級(jí)主庫(kù),并且 VIP 也會(huì)“漂移”到原從庫(kù)上生效,所以說(shuō)大家在工程配置的 MySQL 地址一般是 VIP 以保證高可用
數(shù)據(jù)量大了之后就要分庫(kù)分表了,于是就有了多主,就像 Redis 的分片集群一樣,需要針對(duì)每個(gè)主配備多個(gè)從,如下:
之前有讀者問(wèn)分庫(kù)分表之后為啥還要做主從,現(xiàn)在我想大家應(yīng)該都明白了,不是為了解決讀寫(xiě)性能問(wèn)題,主要是為了實(shí)現(xiàn)高可用。
七、總結(jié)
看完了架構(gòu)層面的高可用設(shè)計(jì),相信大家對(duì)高可用的核心思想「冗余」和「自動(dòng)故障轉(zhuǎn)移」會(huì)有更深刻的體會(huì),觀察以上架構(gòu)中的組件你會(huì)發(fā)現(xiàn)冗余的主要原因是因?yàn)橹挥幸恢?,為什么不能有多主呢,也不是不可以,但這樣在分布式系統(tǒng)下要保證數(shù)據(jù)的一致性是非常困難的,尤其是節(jié)點(diǎn)多了的話,數(shù)據(jù)之間的同步更是一大難題,所以多數(shù)組件采用一主的形式,然后再在主和多從之間同步,多數(shù)組件之所以選擇一主本質(zhì)上是技術(shù)上的 tradeoff。
那么做好每個(gè)組件的高可用之后是否整個(gè)架構(gòu)就真的可用了呢,非也,這只能說(shuō)邁出了第一步,在生產(chǎn)上還有很多突發(fā)情況會(huì)讓我們的系統(tǒng)面臨挑戰(zhàn),比如:
- 瞬時(shí)流量問(wèn)題:比如我們可能會(huì)面臨秒殺帶來(lái)的瞬時(shí)流量激增導(dǎo)致系統(tǒng)的承載能力被壓垮,這種情況可能影響日常交易等核心鏈路,所以需要做到系統(tǒng)之間的隔離,如單獨(dú)為秒殺部署一套獨(dú)立的集群
- 安全問(wèn)題:比如 DDOS 攻擊,爬蟲(chóng)頻繁請(qǐng)求甚至刪庫(kù)跑路等導(dǎo)致系統(tǒng)拒絕服務(wù)
- 代碼問(wèn)題:比如代碼 bug 引起內(nèi)存泄露導(dǎo)致 FullGC 導(dǎo)致系統(tǒng)無(wú)法響應(yīng)等
- 部署問(wèn)題:在發(fā)布過(guò)程中如果貿(mào)然中止當(dāng)前正在運(yùn)行的服務(wù)也是不行的,需要做到優(yōu)雅停機(jī),平滑發(fā)布
- 第三方問(wèn)題:比如我們之前的服務(wù)依賴第三方系統(tǒng),第三方可能出問(wèn)題導(dǎo)致影響我們的核心業(yè)務(wù)
- 不可抗力:如機(jī)房斷電,所以需要做好容災(zāi),異地多活,之前我司業(yè)務(wù)就由于機(jī)房故障導(dǎo)致服務(wù)四小時(shí)不可用,損失慘重
所以除了做好架構(gòu)的高可用之外,我們還需要在做好系統(tǒng)隔離,限流,熔斷,風(fēng)控,降級(jí),對(duì)關(guān)鍵操作限制操作人權(quán)限等措施以保證系統(tǒng)的可用。
這里特別提一下降級(jí),這是為了保證系統(tǒng)可用性采取的常用的措施,簡(jiǎn)單舉幾個(gè)例子:
- 我們之前對(duì)接過(guò)一個(gè)第三方資金方由于自身原因借款功能出了問(wèn)題導(dǎo)致無(wú)法借款,這種情況為了避免引起用戶恐慌,于是我們?cè)谟脩羯暾?qǐng)第三方借款的時(shí)候返回了一個(gè)類似「為了提升你的額度,資金方正在系統(tǒng)升級(jí)」這樣的文案,避免了客訴。
- 在流媒體領(lǐng)域,當(dāng)用戶觀看直播出現(xiàn)嚴(yán)重卡頓時(shí),很多企業(yè)的第一選擇不是查 log 排查問(wèn)題,而是為用戶自動(dòng)降碼率。因?yàn)楸绕甬?huà)質(zhì)降低,卡得看不了顯然會(huì)讓用戶更痛苦。
- 雙十一零點(diǎn)高峰期,我們把用戶的注冊(cè)登錄等非核心功能給停掉了,以保證下單等核心流程的順利。
另外我們最好能做到事前防御,在系統(tǒng)出問(wèn)題前把它扼殺在搖籃里,所以我們需要做單元測(cè)試,做全鏈路壓測(cè)等來(lái)發(fā)現(xiàn)問(wèn)題,還需要針對(duì) CPU,線程數(shù)等做好監(jiān)控,當(dāng)其達(dá)到我們?cè)O(shè)定的域值時(shí)就觸發(fā)告警以讓我們及時(shí)發(fā)現(xiàn)修復(fù)問(wèn)題(我司之前就碰到過(guò)一個(gè)類似的生產(chǎn)事故復(fù)盤大家可以看一下),此外在做好單元測(cè)試的前提下,依然有可能因?yàn)榇a的潛在 bug 引起線上問(wèn)題,所以我們需要在關(guān)鍵時(shí)間(比如雙十一期間)封網(wǎng)(也就是不讓發(fā)布代碼)
此外我們還需要在出事后能快速定位問(wèn)題,快速回滾,這就需要記錄每一次的發(fā)布時(shí)間,發(fā)布人等,這里的發(fā)布不僅包括工程的發(fā)布,還包括配置中心等的發(fā)布。
畫(huà)外音:上圖是我司的發(fā)布記錄,可以看到有代碼變更,回滾等,這樣如果發(fā)現(xiàn)有問(wèn)題的話可以一鍵回滾。
最后我們以一張圖來(lái)總結(jié)一下高可用的常見(jiàn)手段: