在高并發(fā)的系統(tǒng)中如何實(shí)現(xiàn)系統(tǒng)的高可用芥玉?方案有很多種蛇摸,大概可以概括為下面幾點(diǎn):
消除單點(diǎn)
集群或者分布式,可以說(shuō)是高可用系統(tǒng)設(shè)計(jì)的最有效方案灿巧,也是消除單點(diǎn)的常用方案赶袄。云原生最核心的優(yōu)勢(shì)是彈性伸縮,通過(guò)橫向擴(kuò)展來(lái)解決應(yīng)用容量的瓶頸抠藕。為了達(dá)到更加精細(xì)化的應(yīng)用彈性饿肺,我們?cè)谙到y(tǒng)設(shè)計(jì)過(guò)程中做了應(yīng)用分層、分布式設(shè)計(jì)盾似、微服務(wù)架構(gòu)設(shè)計(jì)敬辣。
一個(gè)應(yīng)用系統(tǒng)要實(shí)現(xiàn)分布式,所有從流量接入到服務(wù)調(diào)用零院、數(shù)據(jù)存儲(chǔ)溉跃、緩存、消息隊(duì)列告抄、對(duì)象存儲(chǔ)等撰茎,都可以是分布式,這樣每個(gè)環(huán)節(jié)都不存在單點(diǎn)的問(wèn)題打洼,這樣的系統(tǒng)才具備良好的彈性能力以及高可用性龄糊。
無(wú)狀態(tài)化
為了實(shí)現(xiàn)應(yīng)用容量的橫向擴(kuò)縮容逆粹,服務(wù)設(shè)計(jì)為可伸縮且可部署到任意基礎(chǔ)設(shè)施中,前提條件及時(shí)服務(wù)不應(yīng)該為有狀態(tài)的绎签,比如如果服務(wù)器中的session信息只保存到應(yīng)用服務(wù)器枯饿,那么該應(yīng)用就是有狀態(tài)的。
無(wú)狀態(tài)化并不意味著應(yīng)用系統(tǒng)完全沒(méi)有狀態(tài)诡必,而是通過(guò)狀態(tài)外置來(lái)實(shí)現(xiàn)可伸縮部分服務(wù)的無(wú)狀態(tài)化奢方。整個(gè)架構(gòu)分為無(wú)狀態(tài)部分和有狀態(tài)部分,而業(yè)務(wù)邏輯部分往往作為無(wú)狀態(tài)部分爸舒,而將狀態(tài)保存在有狀態(tài)的中間件中蟋字,如緩存、數(shù)據(jù)庫(kù)扭勉、對(duì)象存儲(chǔ)鹊奖、大數(shù)據(jù)平臺(tái)、消息隊(duì)列等涂炎,這就是我們常說(shuō)的狀態(tài)外置忠聚。這樣無(wú)狀態(tài)部分可以很容易地橫向擴(kuò)展。
冪等設(shè)計(jì)
冪等一般針對(duì)后臺(tái)服務(wù)而言唱捣,“服務(wù)冪等性”是指針對(duì)某一服務(wù)的多次調(diào)用两蟀,只要請(qǐng)求的參數(shù)是一樣的,那么服務(wù)返回結(jié)果一定是一致的震缭,且后臺(tái)系統(tǒng)不會(huì)因?yàn)槎啻握{(diào)用而產(chǎn)生任何影響赂毯,比如臟數(shù)據(jù)。
在分布式環(huán)境下拣宰,前端應(yīng)用的一次請(qǐng)求可能會(huì)調(diào)用多個(gè)后臺(tái)服務(wù)党涕,可能會(huì)發(fā)生某些后臺(tái)服務(wù)超時(shí)或者網(wǎng)絡(luò)閃斷等情況。這時(shí)為了保證業(yè)務(wù)的成功巡社,前端應(yīng)用一般會(huì)通過(guò)重試的機(jī)制達(dá)到數(shù)據(jù)的最終一致性膛堤。因此,在云原生分布式微服務(wù)架構(gòu)下晌该,服務(wù)冪等設(shè)計(jì)是作為一種解決應(yīng)用高可用和數(shù)據(jù)一致性的基本實(shí)踐手段肥荔。
一般情況下,保證服務(wù)的冪等性有下面幾種方案:
-
全局唯一id
如果使用全局唯一ID气笙,就是根據(jù)業(yè)務(wù)的操作和內(nèi)容生成一個(gè)全局ID次企,在執(zhí)行行操作前先根據(jù)這個(gè)全局唯ID是否存在怯晕,來(lái)判斷這個(gè)操作是否已經(jīng)執(zhí)行潜圃。如果不存在則把全局ID,存儲(chǔ)到存儲(chǔ)系統(tǒng)中舟茶,比如數(shù)據(jù)庫(kù)谭期、redis等堵第。如果存在則表示該方法已經(jīng)執(zhí)行。分布式鎖是該方案經(jīng)常使用的一種實(shí)現(xiàn)隧出。 -
去重表
這種方法適用于在業(yè)務(wù)中有唯-標(biāo)的插入場(chǎng)景中踏志,比如在以上的支付場(chǎng)景中,如果-一個(gè)訂單只會(huì)支付一次胀瞪,所以訂單ID可以作為唯一標(biāo)識(shí)针余。 這時(shí),我們就可以建一張去重表凄诞, 并且把唯一標(biāo)識(shí)作為唯一 索引圆雁, 在我們實(shí)現(xiàn)時(shí),把創(chuàng)建支付單據(jù)和寫入去去重表帆谍,放在一個(gè)事務(wù)中伪朽,如果重復(fù)創(chuàng)建,數(shù)據(jù)庫(kù)會(huì)拋出唯一約束異常汛蝙,操作就會(huì)回滾烈涮。 -
插入或更新
這種方法插入并且有唯一索引的情況, 比如我們要關(guān)聯(lián)商品品類窖剑,其中商品的ID和品類的ID可以構(gòu)成唯一索引坚洽,并且在數(shù)據(jù)表中也增加了唯一索引。這時(shí)就可以使用InsertOrUpdate操作苛吱。
彈性伸縮
彈性伸縮包括彈性擴(kuò)展和彈性收縮酪术,是實(shí)現(xiàn)應(yīng)用高可用的重要技術(shù)手段。在業(yè)務(wù)高峰期翠储,當(dāng)系統(tǒng)負(fù)載較大時(shí)绘雁,通過(guò)橫向擴(kuò)展新的應(yīng)用節(jié)點(diǎn)或者拉起新的容器來(lái)分?jǐn)傇袎毫?jié)點(diǎn)上的負(fù)載,讓系統(tǒng)平穩(wěn)渡過(guò)前端應(yīng)用高并發(fā)流量的沖擊援所。而在業(yè)務(wù)低峰期庐舟,通過(guò)釋放部分應(yīng)用節(jié)點(diǎn)以提高資源的有效利用率。
彈性伸縮分為手動(dòng)彈性伸縮和自動(dòng)彈性伸縮住拭。手動(dòng)彈性伸縮是運(yùn)維人員通過(guò)觀測(cè)資源的水位或者收到資源告警信息后挪略,人工為應(yīng)用集群添加新的服務(wù)節(jié)點(diǎn)來(lái)解決資源負(fù)載過(guò)高的問(wèn)題。自動(dòng)彈性伸縮則是系統(tǒng)根據(jù)管理員預(yù)先設(shè)置的規(guī)則自動(dòng)觸發(fā)進(jìn)行資源節(jié)點(diǎn)的動(dòng)態(tài)管理滔岳。
容錯(cuò)設(shè)計(jì)
容錯(cuò)性是指軟件檢測(cè)應(yīng)用程序所運(yùn)行的軟件或硬件中發(fā)生錯(cuò)誤并從錯(cuò)誤中恢復(fù)的能力杠娱,通常可以從系統(tǒng)的可靠性谱煤、可用性摊求、可測(cè)性等方面來(lái)衡量。為了消除單點(diǎn)故障刘离,應(yīng)用部署時(shí)采用集群部署室叉、分布式部署睹栖,都是為了把軟硬件故障給應(yīng)用系統(tǒng)帶來(lái)的影響降到最小。容錯(cuò)設(shè)計(jì)分為應(yīng)用茧痕、系統(tǒng)野来、服務(wù)等不同的層面。
容錯(cuò)設(shè)計(jì)還有一個(gè)很重要的思路——冗余設(shè)計(jì)踪旷,通過(guò)一定的額外成本投入換取系統(tǒng)的可靠性提升曼氛,包括資源冗余(防止不可預(yù)期的業(yè)務(wù)增長(zhǎng)對(duì)于系統(tǒng)的壓力)、數(shù)據(jù)冗余(防止核心數(shù)據(jù)異常丟失)令野、架構(gòu)冗余(如雙通信鏈路)搪锣。
異步設(shè)計(jì)
在一定程度上,同步可以看作單線程彩掐,這個(gè)線程請(qǐng)求一個(gè)方法后就等待這個(gè)方法給它回復(fù)构舟,否則它不往下執(zhí)行。異步可以看作多線程的堵幽,請(qǐng)求一個(gè)方法后就不管了狗超,繼續(xù)執(zhí)行其他的方法。在實(shí)現(xiàn)方面朴下,通常把同步的請(qǐng)求通過(guò)消息隊(duì)列轉(zhuǎn)成異步化訂閱處理努咐,以減少系統(tǒng)之間的耦合,避免核心應(yīng)用被非核心應(yīng)用拖垮殴胧。同時(shí)渗稍,消息隊(duì)列起到了很好的削峰填谷的作用,讓瞬間的高并發(fā)請(qǐng)求有一個(gè)緩沖团滥,從而保護(hù)后臺(tái)應(yīng)用系統(tǒng)的平穩(wěn)運(yùn)行竿屹。
緩存設(shè)計(jì)
緩存的主要作用是降低應(yīng)用和數(shù)據(jù)庫(kù)的負(fù)載,提高系統(tǒng)性能和客戶端訪問(wèn)速度灸姊。在架構(gòu)和業(yè)務(wù)設(shè)計(jì)上拱燃,可以考慮將訪問(wèn)量較大、不經(jīng)常修改的(如字典表和系統(tǒng)參數(shù))力惯,或?qū)?shù)據(jù)庫(kù)性能影響較大的查詢的結(jié)果進(jìn)行緩存碗誉,以提高系統(tǒng)整體性能。
動(dòng)靜分離
動(dòng)靜分離是指靜態(tài)頁(yè)面與動(dòng)態(tài)頁(yè)面分開在不同的系統(tǒng)上訪問(wèn)的架構(gòu)設(shè)計(jì)方法父晶,靜態(tài)資源(如html哮缺、js、css甲喝、img等)與后端服務(wù)分離部署尝苇。靜態(tài)資源放在CDN、Nginx等設(shè)施上,訪問(wèn)路徑短茎匠,訪問(wèn)速度快(幾毫秒);動(dòng)態(tài)頁(yè)面訪問(wèn)路徑長(zhǎng)押袍,訪問(wèn)速度相對(duì)較慢(數(shù)據(jù)庫(kù)的訪問(wèn)诵冒、網(wǎng)絡(luò)傳輸、業(yè)務(wù)邏輯計(jì)算)谊惭,需要幾十毫秒甚至幾百毫秒汽馋,對(duì)架構(gòu)擴(kuò)展性的要求更高。
流控降級(jí)
無(wú)論一個(gè)系統(tǒng)的容量預(yù)估做得多么充分圈盔,我們總是無(wú)法避免一些不可預(yù)期的并發(fā)流量的沖擊豹芯。這些流量既可能是正常的業(yè)務(wù)流量,也可能是非法的行為驱敲。流控降級(jí)相當(dāng)于給后端應(yīng)用系統(tǒng)上了一道保險(xiǎn)铁蹈,讓系統(tǒng)具有一定的抗壓能力,被廣泛用于秒殺众眨、消息削峰填谷握牧、集群流量控制、實(shí)時(shí)熔斷等場(chǎng)景中娩梨,從多個(gè)維度保障客戶的業(yè)務(wù)穩(wěn)定性沿腰。
流控降級(jí)包括流控和降級(jí)兩個(gè)概念。流控狈定,即流量控制(flow control)颂龙,根據(jù)流量、并發(fā)線程數(shù)纽什、響應(yīng)時(shí)間等指標(biāo)措嵌,把隨機(jī)到來(lái)的流量調(diào)整成合適的形狀,即流量塑形芦缰,避免應(yīng)用被瞬時(shí)的流量高峰沖垮铅匹,從而保障應(yīng)用的高可用性。熔斷降級(jí)會(huì)在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)(例如調(diào)用超時(shí)或異常比例升高)時(shí)對(duì)這個(gè)資源的調(diào)用進(jìn)行限制饺藤,讓請(qǐng)求快速失敗包斑,避免影響到其他的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤。
健康檢查
應(yīng)用健康檢查是彈性伸縮和彈性自愈的基礎(chǔ)涕俗,傳統(tǒng)的負(fù)載均衡只能根據(jù)IP:port來(lái)進(jìn)行節(jié)點(diǎn)探活罗丰,但無(wú)法處理應(yīng)用假死的情況。應(yīng)用健康檢查是為了確保當(dāng)前節(jié)點(diǎn)的應(yīng)用能夠正常對(duì)外提供服務(wù)再姑,一旦應(yīng)用健康檢查失敗萌抵,管控節(jié)點(diǎn)(如負(fù)載均衡、服務(wù)注冊(cè)中心、K8s管控等)必須及時(shí)把該故障節(jié)點(diǎn)摘除绍填,防止請(qǐng)求再打到故障節(jié)點(diǎn)而導(dǎo)致業(yè)務(wù)失敗霎桅。
快速失敗
面向失敗設(shè)計(jì)原則是所有的外部調(diào)用都有容錯(cuò)處理,我們希望失敗的結(jié)果是可預(yù)期的讨永、經(jīng)過(guò)設(shè)計(jì)的滔驶。系統(tǒng)發(fā)生異常時(shí)能夠快速失敗,然后快速恢復(fù)卿闹,以保證業(yè)務(wù)永遠(yuǎn)在線揭糕,不能讓業(yè)務(wù)半死不活地僵持著。比如Jedis連接池不夠時(shí),直接拋異常返回锻霎,不讓請(qǐng)求卡著著角,占用服務(wù)器資源。
異常監(jiān)控
在一個(gè)高可用的系統(tǒng)中旋恼,很多時(shí)候系統(tǒng)宕機(jī)是一個(gè)漸進(jìn)的結(jié)果吏口,我們可以通過(guò)一些監(jiān)控,持續(xù)監(jiān)控系統(tǒng)的運(yùn)行狀態(tài)冰更,通過(guò)郵件或者信息的方式發(fā)送給運(yùn)維或者開發(fā)人員就可以及時(shí)的避免系統(tǒng)宕機(jī)锨侯。
優(yōu)雅上下線
優(yōu)雅上下線是實(shí)現(xiàn)業(yè)務(wù)7×24小時(shí)不間斷運(yùn)行的重要保障。為了實(shí)現(xiàn)應(yīng)用版本變更的發(fā)布過(guò)程對(duì)在線業(yè)務(wù)的無(wú)感知冬殃,應(yīng)用發(fā)布時(shí)我們一般采用分批發(fā)布的策略囚痴。
優(yōu)雅下線是指應(yīng)用節(jié)點(diǎn)平滑下線,停應(yīng)用之前會(huì)有一段時(shí)間的“靜默期”(如10s)审葬,靜默期內(nèi)負(fù)載均衡不會(huì)再把新的請(qǐng)求打到該節(jié)點(diǎn)深滚,同時(shí)該節(jié)點(diǎn)已經(jīng)接收到的請(qǐng)求能夠正常處理完。通過(guò)這種機(jī)制實(shí)現(xiàn)節(jié)點(diǎn)下線過(guò)程對(duì)業(yè)務(wù)平滑無(wú)感涣觉。