天天看點

高并發系統設計:從入門到入贅(一)

作者:TPEngineer

一、為什麼要學習高并發系統設計

大廠面試必考高并發系統設計。當你去面試時,面試官會要求你有高并發設計經驗,有的面試官會詢問你的系統在遭遇百萬并發時可能有哪些瓶頸點,以及有什麼優化思路等問題,為的就是檢驗你是否真的了解這方面的内容。

公司業務流量平穩,也遇到一些高并發的需求場景。就拿電商系統中的下單流程設計技術方案為例。在每秒隻有一次調用的系統中,你隻需要關注業務邏輯本身就好了:查詢庫存是否充足,如果充足,就可以到資料庫中生成訂單,成功後鎖定庫存,然後進入支付流程。

這個流程非常清晰,實作也簡單,但如果要做一次秒殺的活動,配合一些營運的推廣,你會發現下單操作的調用量可能達到每秒 10000 次!如果請求全部通過,那麼就要同時生成 10000 次訂單,資料庫能否扛住?如果扛不住,我們要如何做?這些問題都可能出現,并讓之前的方案不再适用,此時你就需要設計新的方案。

除此之外,同樣是緩存的使用,在低并發下你隻需要了解基本的使用方式,但在高并發場景下你需要關注緩存命中率,如何應對緩存穿透,如何避免雪崩,如何解決緩存一緻性等問題,這就增加了設計方案的複雜度,對設計者能力的要求也會更高。

是以,為了避免遇到問題時手忙腳亂,你有必要提前儲備足夠多的高并發知識,進而具備随時應對可能出現的高并發需求場景的能力。

高并發系統的通用設計方法是什麼?

我們知道,高并發系統設計的魅力就在于我們能夠憑借自己的聰明才智設計巧妙的方案,進而抵抗巨大流量的沖擊,帶給使用者更好的使用體驗。這些方案好似能操縱流量,讓流量更加平穩得被系統中的服務群組件處理。

從古至今,長江和黃河流域水患不斷,遠古時期,大禹曾拓寬河道,清除淤沙讓流水更加順暢;都江堰作為史上最成功的的治水案例之一,用引流将岷江之水分流到多個支流中,以分擔水流壓力;三門峽和葛洲壩通過建造水庫将水引入水庫先存儲起來,然後再想辦法把水庫中的水緩緩地排出去,以此提高下遊的抗洪能力。

而我們在應對高并發大流量時也會采用類似“抵禦洪水”的方案,歸納起來共有三種方法。橫向擴充(Scale-out):分而治之是一種常見的高并發系統設計方法,采用分布式部署的方式把流量分流開,讓每個伺服器都承擔一部分并發和流量。緩存:使用緩存來提高系統的性能,就好比用“拓寬河道”的方式抵抗高并發大流量的沖擊。異步:在某些場景下,未處理完成之前,我們可以讓請求先傳回,在資料準備好之後再通知請求方,這樣可以在機關時間内處理更多的請求。簡單介紹了這三種方法之後,我再詳細地帶你了解一下,這樣當你在設計高并發系統時就可以有考慮的方向了。

橫向擴充(Scale-out)

我們将類似追逐摩爾定律不斷提升 CPU 性能的方案叫做 Scale-up(縱向擴充),把類似 CPU 多核心的方案叫做 Scale-out,這兩種思路在實作方式上是完全不同的。Scale-up,通過購買性能更好的硬體來提升系統的并發處理能力,比方說目前系統 4 核 4G 每秒可以處理 200 次請求,那麼如果要處理 400 次請求呢?很簡單,我們把機器的硬體提升到 8 核 8G(硬體資源的提升可能不是線性的,這裡僅為參考)。Scale-out,則是另外一個思路,它通過将多個低性能的機器組成一個分布式叢集來共同抵禦高并發流量的沖擊。沿用剛剛的例子,我們可以使用兩台 4 核 4G 的機器來處理那 400 次請求。

那麼什麼時候選擇 Scale-up,什麼時候選擇 Scale-out 呢?一般來講,在我們系統設計初期會考慮使用 Scale-up 的方式,因為這種方案足夠簡單,所謂能用堆砌硬體解決的問題就用硬體來解決,但是當系統并發超過了單機的極限時,我們就要使用 Scale-out 的方式。

Scale-out 雖然能夠突破單機的限制,但也會引入一些複雜問題。比如,如果某個節點出現故障如何保證整體可用性?當多個節點有狀态需要同步時,如何保證狀态資訊在不同節點的一緻性?如何做到使用方無感覺的增加和删除節點?等等。其中每一個問題都涉及很多的知識點,我會在後續展開。

使用緩存提升性能

緩存遍布在系統設計的每個角落,從作業系統到浏覽器,從資料庫到消息隊列,任何略微複雜的服務群組件中,你都可以看到緩存的影子。我們使用緩存的主要作用是提升系統的通路性能,那麼在高并發的場景下,就可以支撐更多使用者的同時通路。

那麼為什麼緩存可以大幅度提升系統的性能呢?我們知道資料是放在持久化存儲中的,一般的持久化存儲都是使用磁盤作為存儲媒體的,而普通磁盤資料由機械手臂、磁頭、轉軸、盤片組成,盤片又分為磁道、柱面和扇區,盤片構造圖我放在下面了。

盤片是存儲媒體,每個盤片被劃分為多個同心圓,資訊都被存儲在同心圓之中,這些同心圓就是磁道。在磁盤工作時盤片是在高速旋轉的,機械手臂驅動磁頭沿着徑向移動,在磁道上讀取所需要的資料。我們把磁頭尋找資訊花費的時間叫做尋道時間。

高并發系統設計:從入門到入贅(一)

普通磁盤的尋道時間是 10ms 左右,而相比于磁盤尋道花費的時間,CPU 執行指令和記憶體尋址的時間都在是 ns(納秒)級别,從千兆網卡上讀取資料的時間是在μs(微秒)級别。是以在整個計算機體系中,磁盤是最慢的一環,甚至比其它的元件要慢幾個數量級。是以,我們通常使用以記憶體作為存儲媒體的緩存,以此提升性能。

當然,緩存的語義已經豐富了很多,我們可以将任何降低響應時間的中間存儲都稱為緩存。緩存的思想遍布很多設計領域,比如在作業系統中 CPU 有多級緩存,檔案有 Page Cache 緩存,你應該有所了解。

異步處理

異步也是一種常見的高并發設計方法,我們在很多文章和演講中都能聽到這個名詞,與之共同出現的還有它的反義詞:同步。比如,分布式服務架構 Dubbo 中有同步方法調用和異步方法調用,IO 模型中有同步 IO 和異步 IO。

那麼什麼是同步,什麼是異步呢?以方法調用為例,同步調用代表調用方要阻塞等待被調用方法中的邏輯執行完成。這種方式下,當被調用方法響應時間較長時,會造成調用方長久的阻塞,在高并發下會造成整體系統性能下降甚至發生雪崩。異步調用恰恰相反,調用方不需要等待方法邏輯執行完成就可以傳回執行其他的邏輯,在被調用方法執行完畢後再通過回調、事件通知等方式将結果回報給調用方。

異步調用在大規模高并發系統中被大量使用,比如我們熟知的 12306 網站。當我們訂票時,頁面會顯示系統正在排隊,這個提示就代表着系統在異步處理我們的訂票請求。在 12306 系統中查詢餘票、下單和更改餘票狀态都是比較耗時的操作,可能涉及多個内部系統的互相調用,如果是同步調用就會像 12306 剛剛上線時那樣,高峰期永遠不可能下單成功。

而采用異步的方式,後端處理時會把請求丢到消息隊列中,同時快速響應使用者,告訴使用者我們正在排隊處理,然後釋放出資源來處理更多的請求。訂票請求處理完之後,再通知使用者訂票成功或者失敗。處理邏輯後移到異步處理程式中,Web 服務的壓力小了,資源占用的少了,自然就能接收更多的使用者訂票請求,系統承受高并發的能力也就提升了。

高并發系統設計:從入門到入贅(一)

既然我們了解了這三種方法,那麼是不是意味着在高并發系統設計中,開發一個系統時要把這些方法都用上呢?羅馬不是一天建成的,系統的設計也是如此。不同量級的系統有不同的痛點,也就有不同的架構設計的側重點。如果都按照百萬、千萬并發來設計系統,電商一律向淘寶看齊,IM 全都學習微信和 QQ,那麼這些系統的命運一定是滅亡。

因為淘寶、微信的系統雖然能夠解決同時百萬、千萬人同時線上的需求,但其内部的複雜程度也遠非我們能夠想象的。盲目地追從隻能讓我們的架構複雜不堪,最終難以維護。就拿從單體架構往服務化演進來說,淘寶也是在經曆了多年的發展後,發現系統整體的擴充能力出現問題時,開始啟動服務化改造項目的。

我之前也踩過一些坑,參與的一個智能家居項目在初始階段就采用了服務化的架構,但由于當時人力有限,團隊技術積累不足,是以在實際項目開發過程中,發現無法駕馭如此複雜的架構,也出現了問題難以定位、系統整體性能下降等多方面的問題,甚至連系統當機了都很難追查到根本原因,最後不得不把服務做整合,回歸到簡單的單體架構中。

是以我建議一般系統的演進過程應該遵循下面的思路:

  • 最簡單的系統設計滿足業務需求和流量現狀,選擇最熟悉的技術體系。
  • 随着流量的增加和業務的變化,修正架構中存在問題的點,如單點問題,橫向擴充問題,性能無法滿足需求的元件。在這個過程中,選擇社群成熟的、團隊熟悉的元件幫助我們解決問題,在社群沒有合适解決方案的前提下才會自己造輪子。
  • 當對架構的小修小補無法滿足需求時,考慮重構、重寫等大的調整方式以解決現有的問題。

以淘寶為例,當時在業務從 0 到 1 的階段是通過購買的方式快速搭建了系統。而後,随着流量的增長,淘寶做了一系列的技術改造來提升高并發處理能力,比如資料庫存儲引擎從 MyISAM 遷移到 InnoDB,資料庫做分庫分表,增加緩存,啟動中間件研發等。

當這些都無法滿足時就考慮對整體架構做大規模重構,比如說著名的“五彩石”項目讓淘寶的架構從單體演進為服務化架構。正是通過逐漸的技術演進,淘寶才進化出如今承擔過億 QPS 的技術架構。是以,高并發系統的演進應該是循序漸進,以解決系統中存在的問題為目的和驅動力的。

橫向擴充、緩存和異步這三種方法可以在做方案設計時靈活地運用,但它不是具體實施的方案,而是三種思想,在實際運用中會千變萬化。就拿 Scale-out 來說,資料庫一主多從、分庫分表、存儲分片都是它的實際應用方案。而我們需要注意的是,在應對高并發大流量的時候,系統是可以通過增加機器來承擔流量沖擊的,至于要采用什麼樣的方案還是要具體問題具體分析。

思考時間

高并發系統演進是一個漸進的過程,并非一蹴而就的,你在實際工作中,在系統演進過程中積累了哪些經驗又踩到了哪些坑呢?歡迎在留言區與我一同交流。

繼續閱讀