程序员过关斩将--应对高并发系统有没有通用的解决方案呢?
靈魂拷問:
應(yīng)對高并發(fā)系統(tǒng)有沒有一些通用的解決方案呢?
這些方案解決了什么問題呢?
這些方案有那些優(yōu)勢和劣勢呢?
對性能孜孜不倦的追求是互聯(lián)網(wǎng)技術(shù)不斷發(fā)展的根本驅(qū)動力,從最初的大型機(jī)到現(xiàn)在的微型機(jī),在本質(zhì)上也是為了性能而生。軟件系統(tǒng)也存在類似的現(xiàn)象,一個系統(tǒng)從最初的少量訪問請求到后期的大并發(fā)請求,這都需要我們對性能的提升提供一系列解決方案。像最初的淘寶,也僅僅是一個外包做出來的產(chǎn)品,隨著業(yè)務(wù)的不斷發(fā)展,淘寶的并發(fā)量指數(shù)級增加,同時對系統(tǒng)提出了嚴(yán)峻的挑戰(zhàn),這才逐步造就了現(xiàn)在淘寶這樣可以支撐數(shù)千萬人同時在線的高并發(fā)系統(tǒng)。
提起應(yīng)對高并發(fā),每個人都或多或少可以說出幾種解決方案,高并發(fā)系統(tǒng)的設(shè)計魅力在于我們能夠憑借程序員的聰明才智設(shè)計巧妙的方案,從而應(yīng)對巨大流量的沖擊。從目前已知的方案中,大體可以歸納為以下幾種
提升單機(jī)性能
盡可能的提升單機(jī)的性能是一個永恒的話題,無論是采用分布式還是其他方案,單機(jī)性能的提高,對于一個系統(tǒng)來說只有益處。拿編程語言來說,c或者c++語言編寫的程序理論上會比java ,net,Python寫的程序要高效,當(dāng)然這需要建立在程序正常運(yùn)行的情況下。提升單機(jī)性能最簡單粗暴的方式就是提升硬件性能,舉一個簡單例子:假如數(shù)據(jù)庫DB的服務(wù)器內(nèi)存為8G,隨著數(shù)據(jù)量的增加,你會發(fā)現(xiàn)有些sql執(zhí)行會慢慢的變慢,原因是數(shù)據(jù)庫的索引或者數(shù)據(jù)在內(nèi)存中完全存放不下,需要回寫磁盤,有些查詢在內(nèi)存中并不能命中,造成了一些sql會在磁盤中查詢數(shù)據(jù),這個時候如果把服務(wù)器的內(nèi)存增加到16G,你會發(fā)現(xiàn)這些慢sql居然憑空消失了,這是硬件提升性能的一個典型案例。
對于運(yùn)行的程序也是同樣的道理,盡可能的把程序優(yōu)化到極致,也許單機(jī)就可以達(dá)到別人分布式部署的性能效果,當(dāng)然這需要我們在編寫代碼的時候仔細(xì)構(gòu)思。
“無論什么時候,我覺得提升單機(jī)性能都有必要
橫向擴(kuò)展
當(dāng)一個單機(jī)系統(tǒng)無法抵抗巨大流量沖擊的時候,最簡單有效的解決方案之一便是橫向擴(kuò)展,橫向擴(kuò)展是指把巨大的流量分割為數(shù)個比較小的流量,從而解決高并發(fā)系統(tǒng)的性能問題,本質(zhì)上,橫向擴(kuò)展屬于分而治之的理論,屬于分布式的概念范疇。
舉一個很簡單的例子,假設(shè)目前單機(jī)處理請求數(shù)為200/s,當(dāng)每秒的請求數(shù)到達(dá)1000的時候,單臺機(jī)器肯定會遇到瓶頸,這個時候如果處理請求的服務(wù)器增加到5臺,甚至更多,這樣便輕松解決了性能問題。當(dāng)然,能否方便的橫向擴(kuò)展還要看具體的系統(tǒng)設(shè)計,如果系統(tǒng)是無狀態(tài)的,理論上橫向擴(kuò)展是沒問題的,但是一些有狀態(tài)的服務(wù),可能會涉及到狀態(tài)的遷移等工作,這也是為什么很多架構(gòu)師提倡無狀態(tài)服務(wù)的一個原因。
一個應(yīng)用程序的橫向擴(kuò)展可以通過負(fù)載均衡來實(shí)現(xiàn),像阿里云的SLB服務(wù),nginx的反向代理功能,這些都可以很方便實(shí)現(xiàn)應(yīng)用程序的橫向擴(kuò)展。但是,像數(shù)據(jù)庫比如mysql,這樣的DB系統(tǒng),無限制的橫向擴(kuò)展可能只是一個目標(biāo)。大多數(shù)DB采用的主從或者多主多從來解決橫向擴(kuò)展問題,主節(jié)點(diǎn)負(fù)責(zé)寫操作,從節(jié)點(diǎn)負(fù)責(zé)讀操作,當(dāng)然這里涉及到主從同步的機(jī)制,主從同步的延遲等問題,有興趣的同學(xué)可以去深入研究一下。
image那什么時候該選擇橫向擴(kuò)展呢?一般來講,在系統(tǒng)的設(shè)計之初便會考慮橫向擴(kuò)展,因為這種方案足夠簡單,可以用堆砌硬件來解決的問題就不是問題。現(xiàn)在我敢說90%以上的系統(tǒng)在第一版上線的時候就做了類似負(fù)載均衡的部署方案,其中有很多就利用了nginx的反向代理功能。
image當(dāng)然橫向擴(kuò)展并非沒有負(fù)面影響,和單機(jī)系統(tǒng)一樣,橫向擴(kuò)展也要考慮某個節(jié)點(diǎn)down掉的問題,所以監(jiān)控和健康檢查是現(xiàn)在一個系統(tǒng)必備的手段,而且在系統(tǒng)設(shè)計之初便會在整體架構(gòu)之中。就像我前幾篇的文章所說,橫向擴(kuò)展既然屬于分布式范疇,必然需要考慮分布式系統(tǒng)需要考慮的問題:
分布式系統(tǒng)的問題
緩存
除了上面所說的橫向擴(kuò)展方案,另外一種行之有效并且足夠簡單的便是緩存方案。這一點(diǎn)毋庸置疑,緩存可以遍布在一個系統(tǒng)的各個角落,從操作系統(tǒng)到瀏覽器,從cpu到磁盤,從數(shù)據(jù)庫到消息隊列,任何稍微復(fù)雜的服務(wù)和組件中都有緩存的影子。
緩存為什么可以大幅度提高性能的性能呢?這還需要從系統(tǒng)的瓶頸來說,在客戶端一個請求的生命周期中,這個請求的響應(yīng)時間嚴(yán)重受限于最慢的那個環(huán)節(jié),這類似于木桶效應(yīng)(一個木桶可以存的水量,取決于最短那個木板)。
舉一個很簡單的例子:當(dāng)客戶端請求商城的一個商品信息的時候,請求經(jīng)過http協(xié)議到達(dá)服務(wù)器的某個端口,服務(wù)端程序把請求解包然后去請求數(shù)據(jù)庫,數(shù)據(jù)庫不單單在另外一臺服務(wù)器上,而且還需要從磁盤中加載數(shù)據(jù),所謂的DB緩存沒有命中。在這整個過程中,請求磁盤的過程是最慢的,普通磁盤是由機(jī)械手臂,磁頭,轉(zhuǎn)軸,盤片組成,磁盤在查詢數(shù)據(jù)的時候,磁頭是需要花費(fèi)很長時間累尋道的,當(dāng)然SSD的速度要比普通磁盤快的多,但是相比較內(nèi)存還是要慢幾個量級。而我們最想要的流程是這樣的:當(dāng)一個請求到達(dá)服務(wù)端的時候能盡快的從某個設(shè)備上取出信息,然后返給客戶端,這個設(shè)備絕不可能是磁盤,這個設(shè)備在速度和容量上比較均衡,它應(yīng)該是內(nèi)存。
“緩存在語義上要豐富很多,我們可以把任何可以降低響應(yīng)時間的中間存儲都稱之為緩存。比如CPU的一級緩存,二級緩存,三級緩存,瀏覽器的緩存等。緩存主要解決了上下游設(shè)備速度不匹配的問題
image程序界有一句古話:把數(shù)據(jù)放在離用戶最近的地方才是最快的。CDN本質(zhì)上就是做的這件事。對于緩存而言,我們經(jīng)常會聽到瀏覽器緩存,進(jìn)程內(nèi)緩存,進(jìn)程外緩存等概念。目前針對于服務(wù)端一般的緩存策略為采用第三方kv存儲設(shè)備,比如redis,Memcache等。當(dāng)然在對性能極其苛刻的系統(tǒng)中,我還是推薦使用進(jìn)程內(nèi)緩存,具體可見之前的推文:
高并發(fā)下為什么更喜歡進(jìn)程內(nèi)緩存
異步
談到異步,必須要說下同步,同步調(diào)用是指調(diào)用方要阻塞等待被調(diào)用方執(zhí)行完畢才可以返回。系統(tǒng)現(xiàn)在普遍都會采用多線程的方式來提供系統(tǒng)的吞吐量(多進(jìn)程的方式現(xiàn)在很少,但不代表沒有,比如:nodejs,nginx),在同步這種方式下,如果被調(diào)用方的響應(yīng)時間過長,會造成調(diào)用方的線程長時間處于等待狀態(tài),線程的利用率大幅度降低,線程對于系統(tǒng)來說,是很昂貴的資源,創(chuàng)建大量的線程去應(yīng)對高并發(fā)是不明智的,不僅僅浪費(fèi)了內(nèi)存,而且會加大線程上下文cpu切換的成本。
一個高吞吐量的系統(tǒng),理論上所有的線程都要時時刻刻在工作,而且把cpu資源壓榨到最多。對于一個IO密集型操作來說,采用異步方式可以大大提高系統(tǒng)吞吐量。異步不需要等待被調(diào)用方執(zhí)行完成就可以執(zhí)行其他的邏輯,在被調(diào)用方執(zhí)行完畢之后通過通知回調(diào)的方式反饋給調(diào)用方。
“異步本質(zhì)上是一種編程思想,一種編程模型。他提高的是系統(tǒng)整體的吞吐量,但是請求的響應(yīng)時間對比同步方式來說會略微加大。
像平時用的最多的消息隊列,在模型上也屬于異步編程模型。調(diào)用方會把消息丟到隊列中,然后直接返回去執(zhí)行其他業(yè)務(wù),被調(diào)用方接收到消息然后進(jìn)行處理,然后根據(jù)具體的業(yè)務(wù)看是否需要給予結(jié)果回復(fù)。有不少秒殺系統(tǒng)會采用消息隊列進(jìn)行流量削峰,這是異步帶來的優(yōu)勢之一。
image關(guān)于異步更加詳細(xì)的介紹可以查看之前的推文:
問世間異步為何物?
在這里我需要多說一句:異步并不是沒有代價,在多數(shù)情況下,采用異步會比同步方式編寫更多的代碼,而且查找bug會花費(fèi)更多的時間。但是對于一個高并發(fā)系統(tǒng)來說,異步帶來的益處還是值得的,前提是你正確應(yīng)用了異步。
●程序員修神之路--為什么我會了SOA,你們還要逼我學(xué)微服務(wù)?
●程序員過關(guān)斬將--數(shù)據(jù)庫的樂觀鎖和悲觀鎖并非真實(shí)的鎖
●程序員修神之路--設(shè)計一套RPC框架并非易事
●程序員過關(guān)斬將--要想獲取我的用戶信息,就得按照規(guī)矩來
●程序員過關(guān)斬將--更加優(yōu)雅的Token認(rèn)證方式JWT
●程序員過關(guān)斬將--cookie和session的關(guān)系其實(shí)很簡單
●程序員修神之路--用NOSql給高并發(fā)系統(tǒng)加速
●程序員修神之路--高并發(fā)系統(tǒng)設(shè)計負(fù)載均衡架構(gòu)
●程序員過關(guān)斬將--你為什么還在用存儲過程?
●程序員修神之路--問世間異步為何物?
●程序員修神之路--提高網(wǎng)站的吞吐
長按添加菜菜好友
關(guān)注后回復(fù):“大禮包”和“福利”,領(lǐng)取驚喜
總結(jié)
以上是生活随笔為你收集整理的程序员过关斩将--应对高并发系统有没有通用的解决方案呢?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Power Automate生产现场实例
- 下一篇: .NET5.0 单文件发布打包操作深度剖