高并發(fā)軟件系統(tǒng)的密碼

公眾號(hào) 碼磚雜役
公眾號(hào) 碼磚雜役
通常,數(shù)據(jù)庫(kù)單機(jī)每秒也就能抗住幾千這個(gè)量級(jí),而做邏輯處理的服務(wù)單臺(tái)每秒抗幾萬(wàn)、甚至幾十萬(wàn)都有可能,而消息隊(duì)列等中間件單機(jī)每秒處理個(gè)幾萬(wàn)沒問(wèn)題,所以我們經(jīng)常聽到每秒處理數(shù)百萬(wàn)、數(shù)千萬(wàn)的消息中間件集群,而像阿某的API網(wǎng)關(guān),每日百億請(qǐng)求也有可能。

# 0、引言

軟件系統(tǒng)有三個(gè)追求:高性能、高并發(fā)、高可用,俗稱三高。三者既有區(qū)別也有聯(lián)系,門門道道很多,全面討論需要三天三夜,本篇討論高并發(fā)。

高并發(fā)(High Concurrency)。并發(fā)是操作系統(tǒng)領(lǐng)域的一個(gè)概念,指的是一段時(shí)間內(nèi)多任務(wù)流交替執(zhí)行的現(xiàn)象,后來(lái)這個(gè)概念被泛化,高并發(fā)用來(lái)指大流量、高請(qǐng)求的業(yè)務(wù)情景,比如春運(yùn)搶票,電商雙十一,秒殺大促等場(chǎng)景。

很多程序員每天忙著搬磚,平時(shí)接觸不到高并發(fā),哪天受不了跑去面試,還常常會(huì)被面試官上檔次的高并發(fā)問(wèn)題直接KO,其實(shí)吧,高并發(fā)系統(tǒng)也不高深,我保證任何一個(gè)智商在線的看過(guò)這篇文章后,都能戰(zhàn)勝恐懼,重拾生活的信心。

本文先介紹高并發(fā)系統(tǒng)的度量指標(biāo),然后講述高并發(fā)系統(tǒng)的設(shè)計(jì)思路,再梳理高并發(fā)的關(guān)鍵技術(shù),最后結(jié)合作者的經(jīng)驗(yàn)做一些延伸探討。

# 1、高并發(fā)的度量指標(biāo)

既然是高并發(fā)系統(tǒng),那并發(fā)一定要高,不然就名不副實(shí)。并發(fā)的指標(biāo)一般有QPS、TPS、IOPS,這幾個(gè)指標(biāo)都是可歸為系統(tǒng)吞吐率,QPS越高系統(tǒng)能hold住的請(qǐng)求數(shù)越多,但光關(guān)注這幾個(gè)指標(biāo)不夠,我們還需要關(guān)注RT,即響應(yīng)時(shí)間,也就是從發(fā)出request到收到response的時(shí)延,這個(gè)指標(biāo)跟吞吐往往是此消彼長(zhǎng)的,我們追求的是一定時(shí)延下的高吞吐。

比如有100萬(wàn)次請(qǐng)求,99萬(wàn)次請(qǐng)求都在10毫秒內(nèi)響應(yīng),其他次數(shù)10秒才響應(yīng),平均時(shí)延不高,但時(shí)延高的用戶受不了,所以,就有了**TP90/TP99指標(biāo)**,這個(gè)指標(biāo)不是求平均,而是把時(shí)延從小到大排序,取排名90%/99%的時(shí)延,這個(gè)指標(biāo)越大,對(duì)慢請(qǐng)求越敏感。

除此之外,有時(shí)候,我們也會(huì)關(guān)注可用性指標(biāo),這可歸到穩(wěn)定性。

一般而言,用戶感知友好的高并發(fā)系統(tǒng),時(shí)延應(yīng)該控制在250毫秒以內(nèi)。

什么樣的系統(tǒng)才能稱為高并發(fā)?這個(gè)不好回答,因?yàn)樗Q于系統(tǒng)或者業(yè)務(wù)的類型。不過(guò)我可以告訴你一些眾所周知的指標(biāo),這樣能幫助你下次在跟人扯淡的時(shí)候稍微靠點(diǎn)兒譜,不至于貽笑大方。

通常,數(shù)據(jù)庫(kù)單機(jī)每秒也就能抗住幾千這個(gè)量級(jí),而做邏輯處理的服務(wù)單臺(tái)每秒抗幾萬(wàn)、甚至幾十萬(wàn)都有可能,而消息隊(duì)列等中間件單機(jī)每秒處理個(gè)幾萬(wàn)沒問(wèn)題,所以我們經(jīng)常聽到每秒處理數(shù)百萬(wàn)、數(shù)千萬(wàn)的消息中間件集群,而像阿某的API網(wǎng)關(guān),每日百億請(qǐng)求也有可能。

# 2、高并發(fā)的設(shè)計(jì)思路

高并發(fā)的設(shè)計(jì)思路有兩個(gè)方向:

1. 垂直方向擴(kuò)展,也叫豎向擴(kuò)展

2. 水平方向擴(kuò)展,也叫橫向擴(kuò)展

## 垂直方向:提升單機(jī)能力

提升單機(jī)處理能力又可分為硬件和軟件兩個(gè)方面:

- 硬件方向,很好理解,花錢升級(jí)機(jī)器,更多核更高主頻更大存儲(chǔ)空間更多帶寬

- 軟件方向,包括用各快的數(shù)據(jù)結(jié)構(gòu),改進(jìn)架構(gòu),應(yīng)用多線程、協(xié)程,以及上性能優(yōu)化各種手段,但這玩意兒天花板低,就像提升個(gè)人產(chǎn)出一樣,996、007、最多24 X 7。

## 水平方向:分布式集群

為了解決分布式系統(tǒng)的復(fù)雜性問(wèn)題,一般會(huì)用到**架構(gòu)分層和服務(wù)拆分**,通過(guò)分層做**隔離**,通過(guò)微服務(wù)**解耦**。

這個(gè)理論上沒有上限,只要做好層次和服務(wù)劃分,加機(jī)器擴(kuò)容就能滿足需求,但實(shí)際上并非如此,一方面分布式會(huì)增加系統(tǒng)復(fù)雜性,另一方面集群規(guī)模上去之后,也會(huì)引入一堆新問(wèn)題。

因?yàn)榇怪毕虻南拗?,所以,我們通常更關(guān)注水平擴(kuò)展,高并發(fā)系統(tǒng)的實(shí)施也主要圍繞水平方向展開。

# 3、高并發(fā)的關(guān)鍵技術(shù)

玩具式的網(wǎng)絡(luò)服務(wù)程序,用戶可以直連服務(wù)器,甚至不需要數(shù)據(jù)庫(kù),直接寫磁盤文件。但春運(yùn)購(gòu)票系統(tǒng)顯然不能這么做,它肯定扛不住這個(gè)壓力,那一般的高并發(fā)系統(tǒng)是怎么做呢?比如某寶這樣的正經(jīng)系統(tǒng)是怎么處理高并發(fā)的呢?

其實(shí)大的思路都差不多,層次劃分 + 功能劃分??梢园褜哟蝿澐掷斫鉃樗椒较虻膭澐?,而功能劃分理解為垂直方向的劃分。

首先,用戶不能直連服務(wù)器,要做分布式就要解決“分”的問(wèn)題,有多個(gè)服務(wù)實(shí)例就需要做負(fù)載均衡,有不同服務(wù)類型就需要服務(wù)發(fā)現(xiàn)。

## 集群化:負(fù)載均衡

負(fù)載均衡就是把負(fù)載(request)均衡分配到不同的服務(wù)實(shí)例,利用集群的能力去對(duì)抗高并發(fā),負(fù)載均衡是服務(wù)集群化的實(shí)施要素,它分3種:

DNS負(fù)載均衡,客戶端通過(guò)URL發(fā)起網(wǎng)絡(luò)服務(wù)請(qǐng)求的時(shí)候,會(huì)去DNS服務(wù)器做域名解釋,DNS會(huì)按一定的策略(比如就近策略)把URL轉(zhuǎn)換成IP地址,同一個(gè)URL會(huì)被解釋成不同的IP地址,這便是DNS負(fù)載均衡,它是一種粗粒度的負(fù)載均衡,它只用URL前半部分,因?yàn)镈NS負(fù)載均衡一般采用就近原則,所以通常能降低時(shí)延,但DNS有cache,所以也會(huì)更新不及時(shí)的問(wèn)題。

硬件負(fù)載均衡,通過(guò)布置特殊的負(fù)載均衡設(shè)備到機(jī)房做負(fù)載均衡,比如F5,這種設(shè)備貴,性能高,可以支撐每秒百萬(wàn)并發(fā),還能做一些安全防護(hù),比如防火墻。

軟件負(fù)載均衡,根據(jù)工作在ISO 7層網(wǎng)絡(luò)模型的層次,可分為四層負(fù)載均衡(比如章文嵩博士的LVS)和七層負(fù)載均衡(NGINX),軟件負(fù)載均衡配置靈活,擴(kuò)展性強(qiáng),阿某云的SLB作為服務(wù)對(duì)外售賣,Nginx可以對(duì)URL的后半部做解釋承擔(dān)API網(wǎng)關(guān)的職責(zé)。

所以,完整的負(fù)載均衡鏈路是 client -> DNS負(fù)載均衡 -> F5 -> LVS/SLB -> NGINX。

不管選擇哪種LB策略,或者組合LB策略,邏輯上,我們都可以視為負(fù)載均衡層,通過(guò)添加負(fù)載均衡層,我們將負(fù)載均勻分散到了后面的服務(wù)集群,具備基礎(chǔ)的高并發(fā)能力,但這只是萬(wàn)里長(zhǎng)征第一步。

## 數(shù)據(jù)庫(kù)層面:分庫(kù)分表+讀寫分離

前面通過(guò)負(fù)載均衡解決了無(wú)狀態(tài)服務(wù)的水平擴(kuò)展問(wèn)題,但我們的系統(tǒng)不全是無(wú)狀態(tài)的,后面通常還有有狀態(tài)的數(shù)據(jù)庫(kù),所以解決了前面的問(wèn)題,存儲(chǔ)有可能成為系統(tǒng)的瓶頸,我們需要對(duì)有狀態(tài)存儲(chǔ)做分片路由。

數(shù)據(jù)庫(kù)的單機(jī)QPS一般不高,也就幾千,顯然滿足不了高并發(fā)的要求。

所以,我們需要做分庫(kù)分表 + 讀寫分離。

就是把一個(gè)庫(kù)分成多個(gè)庫(kù),部署在多個(gè)數(shù)據(jù)庫(kù)服務(wù)上,主庫(kù)承載寫請(qǐng)求,從庫(kù)承載讀請(qǐng)求。從庫(kù)可以掛載多個(gè),因?yàn)楹芏鄨?chǎng)景寫的請(qǐng)求遠(yuǎn)少于讀的請(qǐng)求,這樣就把對(duì)單個(gè)庫(kù)的壓力降下來(lái)了。

如果寫的請(qǐng)求上升就繼續(xù)分庫(kù)分表,如果讀的請(qǐng)求上升就掛更多的從庫(kù),但數(shù)據(jù)庫(kù)天生不是很適合高并發(fā),而且數(shù)據(jù)庫(kù)對(duì)機(jī)器配置的要求一般很高,導(dǎo)致單位服務(wù)成本高,所以,這樣加機(jī)器抗壓力成本太高,還得另外想招。

## 讀多寫少:緩存

緩存的理論依據(jù)是局部性原理。

一般系統(tǒng)的寫入請(qǐng)求遠(yuǎn)少于讀請(qǐng)求,針對(duì)寫少讀多的場(chǎng)景,很適合引入緩存集群。

在寫數(shù)據(jù)庫(kù)的時(shí)候同時(shí)寫一份數(shù)據(jù)到緩存集群里,然后用緩存集群來(lái)承載大部分的讀請(qǐng)求,因?yàn)榫彺婕汉苋菀鬃龅礁咝阅?,所以,這樣的話,通過(guò)緩存集群,就可以用更少的機(jī)器資源承載更高的并發(fā)。

緩存的命中率一般能做到很高,而且速度很快,處理能力也強(qiáng)(單機(jī)很容易做到幾萬(wàn)并發(fā)),是理想的解決方案。

CDN本質(zhì)上就是緩存,被用戶大量訪問(wèn)的靜態(tài)資源緩存在CDN中是目前的通用做法。

### 緩存也有很多需要謹(jǐn)慎處理的問(wèn)題:

1. **一致性問(wèn)題**:(a)更新db成功+更新cache失敗 -> 不一致 (b)更新db失敗+更新cache成功 -> 不一致 (c)更新db成功+淘汰緩存失敗 -> 不一致

2. **緩存穿透**:查詢一定不存在的數(shù)據(jù),會(huì)穿透緩存直接壓到數(shù)據(jù)庫(kù),從而導(dǎo)致緩存失去作用,如果有人利用這個(gè)漏洞,大量查詢一定不存在的數(shù)據(jù),會(huì)對(duì)數(shù)據(jù)庫(kù)造成壓力,甚至打掛數(shù)據(jù)庫(kù)。解決方案:布隆過(guò)濾器 或者 簡(jiǎn)單的方案,查詢不存在的key,也把空結(jié)果寫入緩存(設(shè)置較短的過(guò)期淘汰時(shí)間),從而降低命失

3. **緩存雪崩**:如果大量緩存在一個(gè)時(shí)刻同時(shí)失效,則請(qǐng)求會(huì)轉(zhuǎn)到DB,則對(duì)DB形成壓迫,導(dǎo)致雪崩。簡(jiǎn)單的解決方案是為緩存失效時(shí)間添加隨機(jī)值,降低同一時(shí)間點(diǎn)失效淘汰緩存數(shù),避免集體失效事件發(fā)生

但緩存是針對(duì)讀,如果寫的壓力很大,怎么辦?

## 高寫入:消息中間件

同理,通過(guò)跟主庫(kù)加機(jī)器,耗費(fèi)的機(jī)器資源是很大的,這個(gè)就是數(shù)據(jù)庫(kù)系統(tǒng)的特點(diǎn)所決定的。

相同的資源下,數(shù)據(jù)庫(kù)系統(tǒng)太重太復(fù)雜,所以并發(fā)承載能力就在幾千/s的量級(jí),所以此時(shí)你需要引入別的一些技術(shù)。

比如說(shuō)消息中間件技術(shù),也就是MQ集群,它是非常好的做寫請(qǐng)求異步化處理,實(shí)現(xiàn)**削峰填谷**的效果。

消息隊(duì)列能做**解耦**,在只需要最終一致性的場(chǎng)景下,很適合用來(lái)配合做流控。

假如說(shuō),每秒是1萬(wàn)次寫請(qǐng)求,其中比如5千次請(qǐng)求是必須請(qǐng)求過(guò)來(lái)立馬寫入數(shù)據(jù)庫(kù)中的,但是另外5千次寫請(qǐng)求是可以允許異步化等待個(gè)幾十秒,甚至幾分鐘后才落入數(shù)據(jù)庫(kù)內(nèi)的。

那么此時(shí)完全可以引入消息中間件集群,把允許異步化的每秒5千次請(qǐng)求寫入MQ,然后基于MQ做一個(gè)削峰填谷。比如就以平穩(wěn)的1000/s的速度消費(fèi)出來(lái)然后落入數(shù)據(jù)庫(kù)中即可,此時(shí)就會(huì)大幅度降低數(shù)據(jù)庫(kù)的寫入壓力。

業(yè)界有很多著名的消息中間件,比如ZeroMQ,rabbitMQ,kafka等。

消息隊(duì)列本身也跟緩存系統(tǒng)一樣,可以用很少的資源支撐很高的并發(fā)請(qǐng)求,用它來(lái)支撐部分允許異步化的高并發(fā)寫入是很合適的,比使用數(shù)據(jù)庫(kù)直接支撐那部分高并發(fā)請(qǐng)求要減少很多的機(jī)器使用量。

## 避免擠兌:流控

再?gòu)?qiáng)大的系統(tǒng),也怕流量短事件內(nèi)集中爆發(fā),就像銀行怕擠兌一樣,所以,高并發(fā)另一個(gè)必不可少的模塊就是流控。

流控的關(guān)鍵是流控算法,有4種常見的流控算法。

1. **計(jì)數(shù)器算法**(固定窗口):計(jì)數(shù)器算法是使用計(jì)數(shù)器在周期內(nèi)累加訪問(wèn)次數(shù),當(dāng)達(dá)到設(shè)定的限流值時(shí),觸發(fā)限流策略,下一個(gè)周期開始時(shí),進(jìn)行清零,重新計(jì)數(shù),實(shí)現(xiàn)簡(jiǎn)單。計(jì)數(shù)器算法方式限流對(duì)于周期比較長(zhǎng)的限流,存在很大的弊端,有嚴(yán)重的臨界問(wèn)題。

2. **滑動(dòng)窗口算法**:將時(shí)間周期分為N個(gè)小周期,分別記錄每個(gè)小周期內(nèi)訪問(wèn)次數(shù),并且根據(jù)時(shí)間滑動(dòng)刪除過(guò)期的小周期,當(dāng)滑動(dòng)窗口的格子劃分的越多,那么滑動(dòng)窗口的滾動(dòng)就越平滑,限流的統(tǒng)計(jì)就會(huì)越精確。此算法可以很好的解決固定窗口算法的臨界問(wèn)題。

3. **漏桶算法**:訪問(wèn)請(qǐng)求到達(dá)時(shí)直接放入漏桶,如當(dāng)前容量已達(dá)到上限(限流值),則進(jìn)行丟棄(觸發(fā)限流策略)。漏桶以固定的速率進(jìn)行釋放訪問(wèn)請(qǐng)求(即請(qǐng)求通過(guò)),直到漏桶為空。分布式環(huán)境下實(shí)施難度高。

4. **令牌桶算法**:程序以r(r=時(shí)間周期/限流值)的速度向令牌桶中增加令牌,直到令牌桶滿,請(qǐng)求到達(dá)時(shí)向令牌桶請(qǐng)求令牌,如獲取到令牌則通過(guò)請(qǐng)求,否則觸發(fā)限流策略。分布式環(huán)境下實(shí)施難度高。

# 4、高并發(fā)的實(shí)踐經(jīng)驗(yàn)

接入-邏輯-存儲(chǔ)是經(jīng)典的互聯(lián)網(wǎng)后端分層,但隨著業(yè)務(wù)規(guī)模的提高,邏輯層的復(fù)雜度也上升了,所以,針對(duì)邏輯層的架構(gòu)設(shè)計(jì)也出現(xiàn)很多新的技術(shù)和思路,常見的做法包括系統(tǒng)拆分,微服務(wù)。

除此之外,也有很多業(yè)界的優(yōu)秀實(shí)踐,包括某信服務(wù)器通過(guò)協(xié)程(無(wú)侵入,已開源libco)改造,極大的提高了系統(tǒng)的并發(fā)度和穩(wěn)定性,另外,緩存預(yù)熱,預(yù)計(jì)算,批量讀寫(減少IO),池技術(shù)等也廣泛應(yīng)用在實(shí)踐中,有效的提升了系統(tǒng)并發(fā)能力。

另外,構(gòu)建**漏斗型業(yè)務(wù)或者系統(tǒng)**,從客戶端請(qǐng)求到接入層,到邏輯層,到DB層,層層遞減,過(guò)濾掉請(qǐng)求,F(xiàn)ail Fast(盡早發(fā)現(xiàn)盡早過(guò)濾),嘴大屁眼小,哈哈。

漏斗型系統(tǒng)不僅僅是一個(gè)技術(shù)模型,它也可以是一個(gè)**產(chǎn)品思維**,配合產(chǎn)品的用戶分流,邏輯分離,可以構(gòu)建全方位的立體模型。

# 5、小結(jié)

莫讓浮云遮望眼,除去繁華識(shí)真顏。我們不能掌握了大方案,吹完了牛皮,而忽視了編程最本質(zhì)的東西,掌握最基本最核心的編程能力,比如數(shù)據(jù)架構(gòu)和算法,設(shè)計(jì),慣用法,培養(yǎng)技術(shù)的審美,也是很重要的,既要致高遠(yuǎn),又要盡精微。

THEEND

最新評(píng)論(評(píng)論僅代表用戶觀點(diǎn))

更多
暫無(wú)評(píng)論