所謂高并發(fā),指的是同一時(shí)間可以處理大量的WEB請(qǐng)求,這個(gè)指標(biāo)用來(lái)衡量一個(gè)架構(gòu)的體量和性能。這里的大量如何評(píng)估呢?1000算不算?10000算不算?
對(duì)于中小型的站點(diǎn)來(lái)說(shuō),可能并發(fā)100多就很不錯(cuò)了,但對(duì)于像淘寶這樣的大型站點(diǎn),單憑一個(gè)接口調(diào)用的量就有可能達(dá)到百萬(wàn)的并發(fā)。在雙11這樣的大型活動(dòng)場(chǎng)景里,淘寶的并發(fā)請(qǐng)求數(shù)都能達(dá)到上億次,這樣的體量無(wú)論是在國(guó)內(nèi)還是在國(guó)際都是排在前列的。而本章節(jié)要講述的內(nèi)容是如何設(shè)計(jì)一個(gè)可以承載巨量并發(fā)請(qǐng)求的架構(gòu)。
要想設(shè)計(jì)一個(gè)高并發(fā)的架構(gòu),首先要搞清楚架構(gòu)的分層,因?yàn)槊恳粋€(gè)層面都有可能造成影響高并發(fā)的瓶頸點(diǎn)。找到瓶頸點(diǎn)后,只要把瓶頸點(diǎn)解除,自然會(huì)提升整個(gè)架構(gòu)的并發(fā)處理能力。我們先來(lái)看一個(gè)綜合分層的架構(gòu)圖:
對(duì)于大型網(wǎng)站來(lái)說(shuō)增加CDN這一層是非常有必要的,CDN(Content Delivery Network,內(nèi)容分發(fā)網(wǎng)絡(luò)),它屬于網(wǎng)絡(luò)范疇的一個(gè)技術(shù),它依靠部署在各個(gè)區(qū)域的邊緣服務(wù)器,實(shí)現(xiàn)負(fù)載均衡、內(nèi)容分發(fā)調(diào)度等功能。它使得用戶就近獲取內(nèi)容,降低網(wǎng)絡(luò)堵塞,提供用戶訪問響應(yīng)速度。
來(lái)舉一個(gè)通俗點(diǎn)的例子:小明公司做了了一個(gè)針對(duì)全國(guó)用戶的業(yè)務(wù),服務(wù)器放在了北京,但是深圳用戶在訪問網(wǎng)站的時(shí)候非常卡頓,有時(shí)候甚至訪問不到。經(jīng)排查,造成該問題的原因是深圳用戶所在網(wǎng)絡(luò)到北京的機(jī)房延遲非常大。小明想到了一個(gè)辦法,他在深圳的某機(jī)房假設(shè)了一臺(tái)服務(wù)器,把北京服務(wù)器上的文件傳輸?shù)缴钲诘姆?wù)器上,當(dāng)深圳用戶訪問網(wǎng)站時(shí),讓該用戶直接去訪問深圳的服務(wù)器,而不是訪問北京的服務(wù)器。同理,其他城市也效仿深圳假設(shè)了類似的服務(wù)器,這樣全國(guó)各地的用戶訪問公司業(yè)務(wù)都很順暢了。
例子中的解決方案其實(shí)就是CDN實(shí)現(xiàn)原理,當(dāng)然,真正的CDN技術(shù)要復(fù)雜得多,要考慮很多問題,比如邊緣服務(wù)器的分布、機(jī)房的網(wǎng)絡(luò)、帶寬、服務(wù)器的存儲(chǔ)、智能DNS解析、邊緣服務(wù)器到真實(shí)服務(wù)器之間的網(wǎng)絡(luò)優(yōu)化、靜態(tài)和動(dòng)態(tài)資源的區(qū)分、緩存的優(yōu)化、壓縮、SSL等等問題。關(guān)于這些細(xì)節(jié)技術(shù)我不做過(guò)多解釋,但希望大家能通過(guò)我的描述了解CDN在架構(gòu)中存在的意義。
CDN是處于整個(gè)架構(gòu)體系中最前端的一層,它是直接面對(duì)用戶的,CDN會(huì)把靜態(tài)的請(qǐng)求(圖片、js、css等)直接消化掉,然后把動(dòng)態(tài)的請(qǐng)求往后傳遞。實(shí)際上,一個(gè)網(wǎng)站(比如,淘寶網(wǎng))超過(guò)80%的請(qǐng)求都是靜態(tài)的請(qǐng)求,那也就意味如果前端架設(shè)了CDN,即使并發(fā)1億,也只有2000萬(wàn)到了后端的WEB上。那么你可能會(huì)問,CDN能支持8000萬(wàn)的并發(fā)嗎?這個(gè)主要取決于CDN廠商的實(shí)力,如果他們搞10000個(gè)節(jié)點(diǎn)(即邊緣服務(wù)器),每個(gè)節(jié)點(diǎn)上消化8000并發(fā),如果搞10萬(wàn)個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)只需要消
化800個(gè)并發(fā)而已。然而,一臺(tái)普通的Nginx服務(wù)器(配置2核CPU4G內(nèi)存)輕松處理5萬(wàn)個(gè)并發(fā)(前提是做過(guò)優(yōu)化,并且處理的請(qǐng)求是靜態(tài)請(qǐng)求、或者只是轉(zhuǎn)發(fā)請(qǐng)求)。
這一層,其實(shí)就是一個(gè)反向代理(或者叫做分發(fā)器),它的主要作用是把用戶的請(qǐng)求按照預(yù)設(shè)的算法發(fā)送給它后面的WEB服務(wù)器。該層在實(shí)現(xiàn)上大致分為兩類:四層和七層(網(wǎng)絡(luò)OSI七層模型),Nginx的負(fù)載均衡就屬于七層,而LVS屬于四層。從吞吐量上來(lái)分析,四層的負(fù)載均衡更有優(yōu)勢(shì)。
所以,要想實(shí)現(xiàn)高并發(fā),負(fù)載均衡這一層必須要使用四層技術(shù),其中LVS就是一款不錯(cuò)的開源負(fù)載均衡軟件。LVS有三種實(shí)現(xiàn)模式:
在這種模式下,負(fù)載均衡器上有設(shè)置iptables nat表的規(guī)則,實(shí)現(xiàn)了把用戶的請(qǐng)求數(shù)據(jù)包轉(zhuǎn)發(fā)到后端的Real Server(即WEB
Server)上,而且還要把WEB Server的響應(yīng)數(shù)據(jù)傳遞給用戶,這樣負(fù)載均衡器很容易成為一個(gè)瓶頸,當(dāng)并發(fā)量很大時(shí),一定會(huì)
影響整個(gè)架構(gòu)的性能。
LVS的DR模式和NAT不一樣,負(fù)載均衡器只需要分發(fā)用戶的請(qǐng)求,而WEB Server的返回?cái)?shù)據(jù)并不通過(guò)負(fù)載均衡器傳遞,數(shù)據(jù)直
接由WEB Server自己處理。這樣就解決了NAT模式的瓶頸問題。但是,DR模式有一個(gè)要求:負(fù)載均衡器和WEB Server必須在同一個(gè)內(nèi)部網(wǎng)絡(luò)(要求在相同的廣播域內(nèi)),這是因?yàn)镈R模式下,數(shù)據(jù)包的目的MAC地址被修改為了WEB Server的MAC地址。
LVS的IP Tunnel模式和DR模式類似,負(fù)載均衡器只需要分發(fā)用戶的請(qǐng)求,而WEB Server的返回?cái)?shù)據(jù)并不通過(guò)負(fù)載均衡器傳遞,數(shù)據(jù)直接由WEB Server自己處理。這樣就解決了NAT模式的瓶頸問題。和DR模式不同的是,IP Tunnel模式不需要保證分發(fā)器和Real Server在同一個(gè)網(wǎng)絡(luò)環(huán)境,因?yàn)檫@種模式下,它會(huì)把數(shù)據(jù)包的目的IP地址更改為Real Server的IP地址。這種模式,可以實(shí)現(xiàn)跨機(jī)房、跨地域的負(fù)載均衡。
對(duì)于以上三種模式來(lái)說(shuō),IP Tunnl模式更適合用在高并發(fā)的場(chǎng)景下。但有一點(diǎn)需要注意,這臺(tái)作為負(fù)載均衡器的服務(wù)器無(wú)論是自身的網(wǎng)卡性能,還是它所處的網(wǎng)絡(luò)環(huán)境里的網(wǎng)絡(luò)設(shè)備都有很高的要求。
可能你會(huì)有疑問,這臺(tái)負(fù)載均衡器終究只是一個(gè)入口,一臺(tái)機(jī)器頂多支撐10萬(wàn)并發(fā),對(duì)于1000萬(wàn)、2000萬(wàn)的并發(fā)怎么實(shí)現(xiàn)?答案是:疊加!一臺(tái)10萬(wàn),100臺(tái)就是1000萬(wàn),200臺(tái)就是2000萬(wàn)……
還有個(gè)問題,如何讓一個(gè)域名(如,www.google.com)訪問這200臺(tái)負(fù)載均衡器?請(qǐng)思考一下上一小節(jié)的CDN技術(shù),它就可以讓一個(gè)域名指向到成千上萬(wàn)的邊緣服務(wù)器上。沒錯(cuò),智能DNS解析可以把全國(guó)甚至世界各地的請(qǐng)求智能地解析到最優(yōu)的邊緣服務(wù)器上。當(dāng)然,DNS也可以不用智能,大不了直接添加幾百條A記錄唄,最終也會(huì)把用戶的請(qǐng)求均衡地分發(fā)到這幾百個(gè)節(jié)點(diǎn)上。
如果最前端使用了CDN,那么在WEB這一層處理的請(qǐng)求絕大多數(shù)為動(dòng)態(tài)的請(qǐng)求。什么是動(dòng)態(tài)的請(qǐng)求?除了靜態(tài)的就是動(dòng)態(tài)的,那什么是靜態(tài)的?前面提到過(guò)的圖片、js、css、html、音頻、視頻等等都屬于靜態(tài)資源,當(dāng)然另外還有太多,大家可以參考第一篇文章《HTTP掃盲》的MIME Type。
再來(lái)說(shuō)這個(gè)動(dòng)態(tài),你可以這樣理解:凡是涉及到數(shù)據(jù)庫(kù)存取操作的請(qǐng)求都屬于動(dòng)態(tài)請(qǐng)求。比如,一個(gè)網(wǎng)站需要注冊(cè)用戶才可以正常訪問里面的內(nèi)容,你注冊(cè)的用戶信息(用戶名、密碼、手機(jī)號(hào)、郵箱等)存入到了數(shù)據(jù)庫(kù)里,每次你登錄該網(wǎng)站,都需要到數(shù)據(jù)庫(kù)里查詢用戶名和密碼,來(lái)驗(yàn)證你輸入的是否是正確的。
如果到了WEB這一層全都是動(dòng)態(tài)的請(qǐng)求的話,那么并發(fā)量的多少主要取決于WEB層后端的DB層或者Cache層。也就是說(shuō)要想提升WEB層服務(wù)器的并發(fā)性能,必須首先要提升DB層或者Cache層的并發(fā)性能。
我們不妨來(lái)一個(gè)假設(shè):要求架構(gòu)能支撐1000萬(wàn)并發(fā)(動(dòng)態(tài)),假設(shè)單臺(tái)WEB Server支撐1000并發(fā),則需要1萬(wàn)臺(tái)服務(wù)器。實(shí)際生產(chǎn)環(huán)境中,單臺(tái)機(jī)器支撐1000并發(fā)已經(jīng)非常厲害啦,至少在我的運(yùn)維生涯里,單臺(tái)WEB Server最大動(dòng)態(tài)并發(fā)量并沒有達(dá)到過(guò)這么大。
我提供一組數(shù)據(jù),你自然就可以估算出并發(fā)量。在這我拿PHP的應(yīng)用舉例:一個(gè)PHP的網(wǎng)站,單個(gè)PHP-FPM進(jìn)程耗費(fèi)內(nèi)存在2M-20M(假設(shè)耗費(fèi)內(nèi)存10M),1000個(gè)并發(fā)也就意味著同時(shí)有1000個(gè)PHP-FPM進(jìn)程,耗費(fèi)內(nèi)存為1000*10M=10G,再加上留給系統(tǒng)1G內(nèi)存,所以1000并發(fā)至少需要11G內(nèi)存。
按照上面的估算,2000并發(fā)則需要21G內(nèi)存,10000并發(fā)則需要101G內(nèi)存,這個(gè)僅僅是理論值。實(shí)際上,并發(fā)量不僅跟內(nèi)存有關(guān)系,跟CPU同樣也有關(guān)系。如果服務(wù)器有4核CPU,則理論上僅僅支持4個(gè)進(jìn)程同時(shí)占用CPU計(jì)算,也就是說(shuō)僅能支持4個(gè)并發(fā)。當(dāng)然,CPU計(jì)算那么快,進(jìn)程會(huì)來(lái)回切換排隊(duì)占用CPU,這樣能夠?qū)崿F(xiàn)即使只有4核CPU,依然能夠支持幾百甚至上千的并發(fā)。但無(wú)論如何,CPU的核數(shù)越大,該服務(wù)器能支撐的并發(fā)也就越大。
對(duì)于高并發(fā)的架構(gòu),WEB Server必然會(huì)做負(fù)載均衡集群,單臺(tái)WEB Server的配置通常會(huì)選擇4核8G這樣的配置(這個(gè)配置,最好是根據(jù)自己業(yè)務(wù)的特性選擇合適的,畢竟現(xiàn)在大多企業(yè)都使用公有云或者私有云,服務(wù)器的配置可以定制),然后由這樣的機(jī)器來(lái)組成一個(gè)大型集群,最終實(shí)現(xiàn)高并發(fā)的需求。
增加這一層的目的是為了減輕DB層的壓力,Cache層有一個(gè)特點(diǎn):數(shù)據(jù)的讀寫發(fā)生在內(nèi)存里,跟磁盤并沒有關(guān)系。正是因?yàn)檫@個(gè)特點(diǎn),保證了數(shù)據(jù)的讀寫速度非常快。假如沒有Cache層,并發(fā)1000萬(wàn)的動(dòng)態(tài)請(qǐng)求意味著這1000萬(wàn)會(huì)直接透?jìng)鞯紻B層(如MySQL),1000萬(wàn)的并發(fā)就會(huì)造成1000萬(wàn)對(duì)磁盤的讀寫操作。我想大家都明白,磁盤的讀寫速度遠(yuǎn)遠(yuǎn)低于內(nèi)存的讀寫速度,要想支撐1000萬(wàn)并發(fā)讀寫是不現(xiàn)實(shí)的。
當(dāng)然,Cache層主要針對(duì)讀操作,而且它僅僅是緩存一部分DB層的熱數(shù)據(jù)(頻繁讀取的那部分?jǐn)?shù)據(jù))。舉一個(gè)下例子:有一次公司的某個(gè)業(yè)務(wù)臨時(shí)做了一個(gè)推廣活動(dòng),結(jié)果導(dǎo)致訪問量暴漲10倍,原本的服務(wù)器架構(gòu)并不能支撐這么大的量,結(jié)果可想而知。當(dāng)時(shí),我們的解決方案是:把查詢量非常大的數(shù)據(jù)緩存到Memcached里面,然后在沒有增加硬件的情況下順利抗了過(guò)去。可見這一
個(gè)Cache層所起到的作用是多么關(guān)鍵。
可以作為Cache的角色通常是NoSQL,如Memcached、Redis等。在第3章《常見WEB集群架構(gòu)》中我曾提到過(guò)Memcached,架構(gòu)圖如下:
作為Cache角色時(shí),Redis和Memcached用法基本一致。其實(shí),拋開這個(gè)Cache角色,NoSQL也可以獨(dú)立作為DB層,這主要取決于業(yè)務(wù)邏輯是否支持拿NoSQL作為數(shù)據(jù)存儲(chǔ)引擎,畢竟NoSQL的數(shù)據(jù)結(jié)構(gòu)和關(guān)系型數(shù)據(jù)庫(kù)比還是比較簡(jiǎn)單的,有些復(fù)雜場(chǎng)景無(wú)法實(shí)現(xiàn)。但為了實(shí)現(xiàn)高并發(fā),我們可以嘗試同時(shí)使用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)和NoSQL數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)。
既然Memcached和Redis都可以作為Cache角色,那么到底用哪一個(gè)可以支撐更大的并發(fā)量呢?其實(shí)這兩者各有千秋,不能盲目地下結(jié)論說(shuō)哪個(gè)更快或者更好。得根據(jù)你的業(yè)務(wù)選擇適合的服務(wù)。由于Redis屬于單線程,故只能使用單核,而Memcached屬于多線程的,從而可以使用多核,所以在比較上,平均每一個(gè)核上Redis在存儲(chǔ)小數(shù)據(jù)時(shí)比Memcached性能更高。而在100k以
上的數(shù)據(jù)中,Memcached性能要高于Redis,雖然Redis最近也在存儲(chǔ)大數(shù)據(jù)的性能上進(jìn)行優(yōu)化,但是比起Memcached,還是稍有遜色。如果不考慮存儲(chǔ)數(shù)據(jù)大小,肯定Memcached性能更好,畢竟它是多線程的。
另外你需要了解,Memcached的數(shù)據(jù)只能存內(nèi)存,不能存到磁盤,而Redis支持把內(nèi)存的數(shù)據(jù)鏡像一份到磁盤上,而且還可以記錄日志(通過(guò)這個(gè)日志來(lái)獲取數(shù)據(jù))。Memcached只能存簡(jiǎn)單的K-V格式的數(shù)據(jù),而Redis支持更多的數(shù)據(jù)類型(如,list、hash)。
無(wú)論你用哪一種作為Cache,我們都需要為其做一個(gè)高可用負(fù)載均衡集群,這樣才可以滿足高并發(fā)的需求。
可以說(shuō)DB層是整個(gè)架構(gòu)體系中非常關(guān)鍵的一層,也是瓶頸所在。原因無(wú)他,只因它涉及到對(duì)磁盤的讀寫。所以,為了提升性能,對(duì)服務(wù)器磁盤要求很高,至少是15000r/m的SAS硬盤而且需要做RAID10,如果選擇SSD盤更優(yōu)。
最簡(jiǎn)單暴力提升并發(fā)數(shù)量的辦法是服務(wù)器的堆積(即,做負(fù)載均衡集群),但DB層跟WEB層不一樣,它涉及到數(shù)據(jù)存儲(chǔ)到磁盤
里,服務(wù)器可以累加,但是磁盤在累加的同時(shí),如何保證所有的服務(wù)器能讀寫同一份數(shù)據(jù)?這是一個(gè)很大的問題,所以單純的服務(wù)器堆積只適合小規(guī)模的業(yè)務(wù),對(duì)于并發(fā)上千萬(wàn)的業(yè)務(wù)并不適用。并發(fā)量大的站點(diǎn),意味著數(shù)據(jù)量也是非常大的(如,TB級(jí)別),如果單個(gè)數(shù)據(jù)庫(kù)上TB,那一定是一個(gè)災(zāi)難,無(wú)論是讀寫還是備份都將是極大的問題。
那如何解決這個(gè)問題呢?既然大了不行,那就將大的庫(kù)切割成小的庫(kù)即可。你可不要把這個(gè)切割單純地想象成切割文件。我們可以從兩個(gè)維度來(lái)實(shí)現(xiàn)切割。
大型網(wǎng)站為了應(yīng)對(duì)日益復(fù)雜的業(yè)務(wù)場(chǎng)景,通過(guò)使用分而治之的手段將整個(gè)網(wǎng)站業(yè)務(wù)分成不同的產(chǎn)品線,如大型購(gòu)物網(wǎng)站就會(huì)將首頁(yè)、商鋪、訂單、買家、賣家、倉(cāng)儲(chǔ)、物流、售后服務(wù)等拆分成不同的產(chǎn)品項(xiàng),這樣數(shù)據(jù)庫(kù)自然也拆分為了多個(gè)數(shù)據(jù)庫(kù),原來(lái)TB級(jí)的數(shù)據(jù),變成了GB級(jí)。如果覺得還不夠細(xì)化,我們可以繼續(xù)把商鋪進(jìn)一步拆分,比如個(gè)人類的、企業(yè)類的、明星類的、普通類的等等。總之,你可以根據(jù)業(yè)務(wù)特性想到幾百種拆分方法,最終一塊大蛋糕變成了幾十甚至幾百塊小蛋糕,吃起來(lái)就簡(jiǎn)單多了。
業(yè)務(wù)拆分是產(chǎn)品經(jīng)理設(shè)計(jì)的,但是這個(gè)分庫(kù)分表只能是DBA操刀。如果一個(gè)幾千GB的大庫(kù)讀寫很慢的話,但分成1000個(gè)幾GB的小庫(kù)后,讀寫速度一定是有質(zhì)的飛躍。同理,表也是可以像庫(kù)那樣劃分的。分庫(kù)分表需要借助數(shù)據(jù)庫(kù)中間件來(lái)完成。比如MySQL分庫(kù)分表比較好的中間件MyCAT就不錯(cuò)。
有了以上兩個(gè)拆分原則,無(wú)論多大的庫(kù),我們都可以劃分為比較小的庫(kù),這樣即使使用傳統(tǒng)的架構(gòu)依然可以輕松應(yīng)付。最終的DB層架構(gòu)就成了蜂窩狀的一組一組的小單元,每一個(gè)單元獨(dú)立做高可用以及負(fù)載均衡集群。
一個(gè)大型的網(wǎng)站,一定少不了消息隊(duì)列這一層。在前面第3章《常見WEB集群架構(gòu)》一文中就提到過(guò)它,它主要解決的問題是:解耦合、異步處理、流量削峰等。以下三個(gè)應(yīng)用場(chǎng)景曾在第3章出現(xiàn)過(guò),也許你現(xiàn)在看會(huì)有更深層次的體會(huì)。
用戶上傳圖片到服務(wù)器,要求人臉識(shí)別系統(tǒng)識(shí)別該上傳圖片,傳統(tǒng)的做法是:用戶上傳圖片 → 服務(wù)接收到圖片開始識(shí)別圖片 → 系統(tǒng)判斷圖片是否合法 → 反饋給用戶是否成功。這個(gè)要涉及兩個(gè)系統(tǒng):
而使用消息隊(duì)列,流程會(huì)變成這樣:
用戶上傳圖片后,圖片上傳系統(tǒng)將圖片信息寫入消息隊(duì)列,直接返回成功;而人臉識(shí)別系統(tǒng)則定時(shí)從消息隊(duì)列中取數(shù)據(jù),完成對(duì)新增圖片的識(shí)別。
此時(shí)圖片上傳系統(tǒng)并不需要關(guān)心人臉識(shí)別系統(tǒng)是否對(duì)這些圖片信息的處理、以及何時(shí)對(duì)這些圖片信息進(jìn)行處理。事實(shí)上,由于用戶并不需要立即知道人臉識(shí)別結(jié)果,人臉識(shí)別系統(tǒng)可以選擇不同的調(diào)度策略,按照閑時(shí)、忙時(shí)、正常時(shí)間,對(duì)隊(duì)列中的圖片信息進(jìn)行處理。
用戶到一個(gè)網(wǎng)站注冊(cè)賬號(hào),系統(tǒng)需要發(fā)送注冊(cè)郵件并驗(yàn)證短信。傳統(tǒng)的處理流程如下:
這種方式下,需要最終發(fā)送短信驗(yàn)證后再返回給客戶端。
另外一種方式就是異步處理,即注冊(cè)郵件和短信同時(shí)發(fā)送,流程如下:
當(dāng)用戶填寫完注冊(cè)信息并成功寫入消息隊(duì)列后,就可以反回成功的信息給客戶端,從而客戶端不需要再等待系統(tǒng)發(fā)郵件和發(fā)短信,不僅客戶端不用等,而且處理客戶端請(qǐng)求的那個(gè)工作進(jìn)程也不需要等(這個(gè)特性非常重要,它是實(shí)現(xiàn)高并發(fā)的一個(gè)重要手段),這個(gè)就是異步處理的優(yōu)勢(shì)。
很典型的應(yīng)用就是購(gòu)物網(wǎng)站秒殺活動(dòng),一般由于瞬時(shí)訪問量過(guò)大,服務(wù)器接收過(guò)大,會(huì)導(dǎo)致流量暴增,相關(guān)系統(tǒng)無(wú)法處理請(qǐng)求甚至崩潰。而加入消息隊(duì)列后,系統(tǒng)可以從消息隊(duì)列中取數(shù)據(jù),相當(dāng)于消息隊(duì)列做了一次緩沖。
該方法可以讓請(qǐng)求先入消息隊(duì)列,而不是由業(yè)務(wù)處理系統(tǒng)直接處理,極大地減少了業(yè)務(wù)處理系統(tǒng)的壓力。另外隊(duì)列長(zhǎng)度可以做限制,比如隊(duì)列長(zhǎng)度為100,則該系統(tǒng)只能有100人可以秒殺到商品,排在100名后的用戶無(wú)法秒殺到商品,而返回活動(dòng)已結(jié)束或商品已售完的信息。
總之,消息隊(duì)列的引入極大提升了整個(gè)架構(gòu)的并發(fā)能力。從WEB層接收到動(dòng)態(tài)的請(qǐng)求后,Cache層過(guò)濾掉一部分,然后請(qǐng)求逐一地發(fā)送到DB層,在這個(gè)過(guò)程中,查詢時(shí)間很長(zhǎng)的請(qǐng)求可以單獨(dú)摘出來(lái),把它搞到消息隊(duì)列里,這樣WEB層和DB層只處理那種快速有結(jié)果的查詢,并發(fā)量自然很大。而消息隊(duì)列會(huì)慢慢消化掉這些特殊的查詢,或許你有疑問,這種查詢慢的請(qǐng)求也很多怎么
辦?不也同樣影響到并發(fā)量嗎?畢竟最終的查詢到了DB層。不要忘記消息隊(duì)列本身就有削峰的能力,如果有大量的這種查詢,那么就讓它們排好隊(duì)列,慢慢消化,總之不讓它們影響到DB層的正常查詢。
可以提供消息隊(duì)列的服務(wù)有那么多(RabitMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ、Beanstalk、Redis等等),到底選擇哪一種?最好是讓研發(fā)同事來(lái)定吧,只有研發(fā)團(tuán)隊(duì)最了解自己代碼的邏輯架構(gòu),適合自己的才是最好的。事實(shí)上,無(wú)論你用哪一種消息隊(duì)列服務(wù),它都不會(huì)成為整個(gè)架構(gòu)的瓶頸點(diǎn)。當(dāng)然,你最好做一個(gè)分布式的集群,這樣能夠保證它的橫向擴(kuò)容或者縮容。
關(guān)于存儲(chǔ),目前的解決方案我歸類為以下幾種:
就是服務(wù)器自身的磁盤,對(duì)于像DB層這樣關(guān)鍵的角色,我們通常會(huì)用高性能磁盤做RAID10。特點(diǎn):方便維護(hù)、穩(wěn)定、性能非常好、容量有限、擴(kuò)容不方便。
主要有三類:NAS、SAN、DAS。
NAS:類似Linux系統(tǒng)做的NFS服務(wù),它是建立在操作系統(tǒng)層面上的一種共享存儲(chǔ)解決方案,它是一種商業(yè)產(chǎn)品。NAS比較適合小規(guī)模網(wǎng)站。特點(diǎn):容量大、擴(kuò)容不方便、吞吐量一般(受網(wǎng)絡(luò)環(huán)境影響)、穩(wěn)定性好、成本高。
SAN:也是一種商業(yè)的共享存儲(chǔ)解決方案,支持普通網(wǎng)絡(luò)或者光纖接入,比NAS更加底層。特點(diǎn):容量大、擴(kuò)容不方便、性能好(比NAS強(qiáng)很多)、穩(wěn)定性好、成本高昂。
DAS:磁盤陣列,支持RAID,商業(yè)的存儲(chǔ)。特點(diǎn):容量大、擴(kuò)容不方便、不支持共享、性能好、穩(wěn)定性好。
隨著云計(jì)算、大數(shù)據(jù)技術(shù)的日益流行,分布式共享存儲(chǔ)技術(shù)越來(lái)越成熟,無(wú)論是商業(yè)的還是開源的都有不少優(yōu)秀的解決方案。比如,開源的有HDFS、FastDFS、MFS、GlusterFS、Ceph、Swift等。這類存儲(chǔ)有一些共同特點(diǎn):方便擴(kuò)容、容量可以無(wú)限大、性能一般(網(wǎng)絡(luò)會(huì)成為瓶頸)、成本低、穩(wěn)定性好。
本節(jié)的存儲(chǔ)層我也歸類為三大類:WEB層面的存儲(chǔ)(比如存儲(chǔ)代碼、圖片、js、css、視頻、音頻等靜態(tài)文件)、日志、DB層面的存儲(chǔ)(即數(shù)據(jù)庫(kù)的數(shù)據(jù)存儲(chǔ))。
這三類存儲(chǔ),最要命的是DB層的存儲(chǔ),前面我也提到過(guò)DB層很關(guān)鍵,而決定DB層性能的因素中這個(gè)數(shù)據(jù)存儲(chǔ)(磁盤)性能起到?jīng)Q定性作用。解決方案我也提到了,就是“大變小,一變多,自己管自己”。正常情況下巨量的數(shù)據(jù)庫(kù)必然會(huì)使用大容量存儲(chǔ)設(shè)備,這樣最終的結(jié)果是—慢!所以,我們需要分模塊、分庫(kù)分表,最終單臺(tái)機(jī)器的本地磁盤就可以支撐這些巨量的數(shù)據(jù),讀寫速度不會(huì)被網(wǎng)絡(luò)等因素影響。
日志類和WEB層靜態(tài)文件的存儲(chǔ)可以選擇分布式共享存儲(chǔ)解決方案,因?yàn)檫@類的存儲(chǔ)不需要太高的吞吐量,它們所占用的空間比較大,而且會(huì)越來(lái)越大。
當(dāng)你看完以上內(nèi)容后,可能你的心中還是沒有一個(gè)完整的答案,所以這個(gè)總結(jié)很關(guān)鍵!
1)高并發(fā)網(wǎng)站一定會(huì)使用CDN,而且需要把靜態(tài)文件存儲(chǔ)在邊緣服務(wù)器上。
2)負(fù)載均衡一定要使用四層的,比如LVS,如果是LVS,選擇IP Tunnel模式。
3)WEB層把靜態(tài)的請(qǐng)求交給CDN處理,所以只處理動(dòng)態(tài)的請(qǐng)求,要支持橫向擴(kuò)容,可以方便地通過(guò)加機(jī)器來(lái)增加并發(fā)量。
4)增加Cache層,把熱數(shù)據(jù)搞到這一層,減少對(duì)DB層地壓力。對(duì)這一層做分布式集群架構(gòu)設(shè)計(jì),方便擴(kuò)容。
5)增加消息隊(duì)列,實(shí)現(xiàn)解耦合、流量削峰,從而提升整個(gè)架構(gòu)地并發(fā)能力。
6)DB層要通過(guò)拆分業(yè)務(wù)、分庫(kù)分表來(lái)實(shí)現(xiàn)大變小、一變多,對(duì)單獨(dú)模塊做高可用負(fù)載均衡集群,從而提升并發(fā)能力。
7)DB層的存儲(chǔ)使用本地磁盤,日志類、靜態(tài)文件類使用分布式文件存儲(chǔ)。