高併發系統:它的通用設計方法是什麼?
在高併發系統的設計中,面對大流量的挑戰,我們通常需要運用一些巧妙的方案來有效地分流和處理這些流量,從而保證系統的穩定性和用戶體驗。可以通過一個比喻來幫助理解:就像古代治水一樣,我們在高併發系統中採用的策略,也旨在將洪水引流、分擔壓力、提高系統的承載能力。
例如,在古代的治水實踐中,大禹通過拓寬河道清除淤沙,讓水流更加順暢;都江堰則利用引流技術將岷江的水分流到多個支流,從而減少水流的壓力;而三門峽和葛洲壩通過建造水庫來暫時存儲水源,再通過控制水庫的排水來緩解下游的水患。這些治水的思想,實際上在現代高併發系統的設計中也能找到類似的解決方案。
總結起來,處理高併發的流量,我們主要會採取三種策略:
-
橫向擴展(Scale-out):類似於 “分而治之” 的治水方法。通過分佈式部署,將流量分散到不同的服務器或節點上,從而避免單一節點的過載,確保系統的可擴展性和負載均衡。
-
緩存:就像是 “拓寬河道”,緩存是緩解流量衝擊的一種有效方式。通過在系統中緩存熱點數據,可以減少後端系統的壓力,提高響應速度,從而提升用戶體驗。
-
異步處理:這種方式就像是 “提前引流” 或“暫存水源”。在一些場景下,我們可以允許請求先返回,並在數據準備好之後再通知請求方。這種方式能夠有效提高系統的吞吐量,減少高併發時的響應延遲。
這三種策略是高併發系統設計中常見的手段,當然,每種方法背後還有更爲複雜和細化的技術細節,之後會根據具體場景進一步講解。這些策略的靈活運用,可以幫助我們設計出既高效又可靠的高併發系統,確保系統在面對大流量時能夠從容應對。
首先,我們先來了解第一種方法:Scale-out。
Scale-up vs Scale-out
“摩爾定律”由 Intel 創始人之一戈登 · 摩爾在 1965 年提出,最初是指集成電路上晶體管的數量大約每兩年會翻一倍。這一理論後來被 Intel CEO 大衛 · 豪斯用 “18 個月翻一倍” 的說法進一步簡化,並廣泛流傳。摩爾定律主要描述了芯片技術的發展速度,但它也可以延伸到整體硬件性能的提升。從 20 世紀下半葉開始,計算機硬件的性能一直呈現指數級的增長,這一趨勢持續至今。摩爾定律指引下的技術突破,使得我們從最初只有十幾個晶體管的集成電路,到今天每顆芯片上擁有數十億晶體管,芯片廠商在有限的空間內,通過減小晶體管的尺寸,不斷提升硬件性能。
然而,隨着芯片工藝的進步,已有專家預測摩爾定律可能會在未來幾年失效。如今的芯片已經進入了 5nm 製程,進一步減小晶體管尺寸的空間變得非常有限,可能無法繼續以每 18 個月翻倍的速度提升性能。在這種背景下,雙核和多核技術的出現爲延續摩爾定律的理念提供了新的方向。通過將多個 CPU 核心集成到同一芯片上,CPU 的並行處理能力得到了大幅提升,這一思路在高併發系統設計中也得到了應用。
在高併發系統中,類似於摩爾定律不斷提升單機性能的做法,被稱爲 Scale-up(縱向擴展)。而將多個處理單元組合成一個集羣來提升性能,則被稱爲 Scale-out(橫向擴展)。這兩者在實現方式上有着明顯不同。
-
Scale-up(縱向擴展):這種方式類似於提升單個 CPU 的核心數,通過購買更高性能的硬件來提高系統的處理能力。例如,如果一個 4 核 4GB 內存的機器每秒能處理 200 次請求,那麼通過將機器升級爲 8 核 8GB 內存,理論上就能處理更多的請求(儘管硬件提升的性能並非線性增長,這裏只是舉例說明)。Scale-up 的優勢在於其簡單直接,適用於系統初期的擴展。
-
Scale-out(橫向擴展):這種方式通過將多個低性能的機器組合成一個分佈式集羣,共同承擔高併發流量的壓力。例如,使用兩臺 4 核 4GB 內存的機器來處理 400 次請求。這種方法能夠突破單機硬件的性能極限,但也帶來了一些複雜性,比如分佈式系統的管理、負載均衡、數據一致性等問題。
在實際的系統設計中,通常在初期階段選擇 Scale-up,因爲它能夠通過提升單機硬件性能解決問題,操作簡單;但隨着系統併發量的增長,單機的性能瓶頸逐漸顯現,Scale-out 成爲應對更高併發流量的解決方案。儘管 Scale-out 具有更強的擴展性,但也需要解決更復雜的技術挑戰。
說完了 Scale-out,我們再來看看高併發系統設計的另一種方法:緩存。
使用緩存提升性能
Web 2.0 被稱爲 “緩存的時代”,這一點幾乎是公認的。如今,緩存已經滲透到系統設計的各個層面,從操作系統到瀏覽器,從數據庫到消息隊列,任何稍微複雜的服務和組件中都能看到緩存的身影。緩存的主要作用是提高系統的訪問性能,尤其是在高併發場景中,緩存能顯著提升系統的響應速度,從而支持更多用戶同時訪問。
那麼,爲什麼緩存能大幅度提升系統的性能呢?我們知道,數據通常存儲在持久化存儲中,且大多數持久化存儲使用磁盤作爲存儲介質。傳統磁盤由機械手臂、磁頭、轉軸和盤片組成,盤片被劃分爲多個同心圓,稱爲磁道。這些磁道用來存儲數據。磁盤工作時,盤片高速旋轉,機械手臂帶動磁頭沿着徑向移動,定位到需要讀取的磁道。在此過程中,磁頭找到數據的時間被稱爲尋道時間,這是磁盤存取數據的瓶頸之一。
普通磁盤的尋道時間大約是 10 毫秒,而與此相比,CPU 執行指令和內存尋址的速度通常在納秒(ns)級別,從千兆網卡讀取數據的時間則是在微秒(μs)級別。可以看出,磁盤在整個計算機系統中是最慢的組件,甚至比其他部件慢上幾個數量級。因此,爲了提升性能,我們通常採用內存作爲存儲介質來實現緩存。
緩存的作用不僅僅限於簡單的存儲,它的語義已經變得更加豐富。在現代系統設計中,任何可以顯著降低響應時間的中間存儲都可以被稱爲緩存。例如,在操作系統中,CPU 就有多級緩存來減少訪問主內存的時間;文件系統中也有 Page Cache 緩存,用來提高文件讀取的效率。緩存的思想已經廣泛應用於多個領域,不僅限於傳統的數據庫緩存,而是滲透到計算機系統的方方面面。
異步處理
異步是一種常見的高併發設計方法,我們在很多技術文章和演講中常常會看到這個術語,同時它也經常與 “同步” 相提並論。例如,在分佈式服務框架 Dubbo 中,我們可以看到同步方法調用和異步方法調用;在 IO 模型中,也有同步 IO 和異步 IO。那麼,什麼是同步,什麼是異步呢?
以方法調用爲例,同步調用意味着調用方必須等待被調用的方法執行完成後才能繼續執行下一步操作。在同步調用的情況下,如果被調用的方法響應時間較長,調用方會一直阻塞,直到方法執行完成。這種方式在高併發場景下會導致大量阻塞,最終可能引發整體系統性能下降,甚至發生 “雪崩效應”。
異步調用則正好相反,調用方不需要等待被調用方法的邏輯執行完成,而是可以立刻返回並繼續執行其他操作。當被調用的方法完成後,結果會通過回調、事件通知等機制反饋給調用方。異步調用非常適合大規模高併發的系統中使用。例如,我們都知道的 12306 網站,訂票時頁面會顯示 “系統正在排隊” 的提示,這其實就表示系統在異步處理我們的訂票請求。
在 12306 系統中,查詢餘票、下單、以及更新餘票狀態等操作都是比較耗時的,可能涉及多個內部系統的調用。如果這些操作是同步的,那麼在高併發的情況下,就像 12306 剛上線時那樣,很多用戶在高峯期永遠無法成功下單。而採用異步處理後,系統能夠更有效地分擔負載,提升整體處理能力和用戶體驗。
而採用異步的方式,後端處理時會把請求丟到消息隊列中,同時快速響應用戶,告訴用戶我們正在排隊處理,然後釋放出資源來處理更多的請求。訂票請求處理完之後,再通知用戶訂票成功或者失敗。處理邏輯後移到異步處理程序中,Web 服務的壓力小了,資源佔用的少了,自然就能接收更多的用戶訂票請求,系統承受高併發的能力也就提升了。
瞭解了這些方法後,我們可能會問,是否在高併發系統設計中就必須把這些方法都應用到位?答案是否定的。系統設計是一個不斷演進的過程,"羅馬不是一天建成的",系統的設計也是如此。不同規模的系統會面臨不同的痛點,進而會有不同的架構設計側重點。如果在一開始就按照百萬、千萬併發量來設計系統,盲目追求像淘寶、微信那樣的架構,那麼這些系統的命運很可能會是失敗的。
爲什麼呢?因爲儘管像淘寶、微信這樣的大型系統能夠處理百萬、千萬併發的需求,但它們內部的複雜性是我們難以想象的。盲目地追隨這些大系統的設計思路,只會讓我們的架構變得異常複雜,最終導致難以維護和擴展。比如說,淘寶在經歷多年的發展後,才發現自己在整體擴展能力上的瓶頸,這時他們纔開始進行服務化改造。
我自己也曾經歷過類似的情況。在參與的一個創業項目中,我們在初期就選擇了服務化架構。但由於當時人力有限,團隊的技術積累不足,在實際開發過程中我們發現無法駕馭如此複雜的架構,導致了很多問題:比如問題定位困難、系統性能下降,甚至系統宕機時都很難找到根本原因。最終,我們不得不將服務進行整合,迴歸到更簡單的單體架構中。
這也提醒我們,在設計高併發系統時,必須根據實際的業務需求、技術儲備和團隊能力來選擇合適的架構,並隨系統的發展不斷調整和優化,而不是一開始就過於複雜化。
所以我建議一般系統的演進過程應該遵循下面的思路:
最初的系統設計應當以滿足當前的業務需求和流量情況爲目標,並選擇團隊最熟悉的技術體系。在實際開發過程中,隨着流量的增加和業務的發展,我們可能會發現架構中的一些問題,比如單點故障、橫向擴展的瓶頸,或是性能無法滿足需求的組件。此時,我們需要逐步修正這些問題。
在解決問題時,我們首先會考慮選擇那些社區中已經成熟並且團隊熟悉的組件,這樣可以更高效地應對問題並避免重複造輪子。如果社區沒有合適的解決方案,纔會考慮自行開發或定製解決方案。
然而,當對現有架構進行的小修小補已無法解決問題時,我們需要考慮更大規模的調整,如架構重構或重寫。通過這些更爲深度的調整,纔能有效解決現有架構無法滿足業務需求的難題。總之,系統架構的設計和演進是一個不斷調整和優化的過程,應根據實際需求逐步推進。
以淘寶爲例,最初在業務從 0 到 1 的階段,淘寶通過購買現成的硬件和軟件快速搭建了系統。然而,隨着流量的不斷增長,淘寶開始進行一系列的技術改造,以提高系統的高併發處理能力。這些改造包括將數據庫存儲引擎從 MyISAM 遷移到 InnoDB,實施數據庫的分庫分表,增加緩存,並開發中間件等。當這些優化手段不再滿足需求時,淘寶進一步對整體架構進行大規模重構,例如著名的 “五彩石” 項目,這使得淘寶的架構從單體架構逐步演進爲服務化架構。
正是通過這些逐步的技術演進,淘寶才最終構建了能夠支撐過億 QPS 的技術架構。歸根結底,高併發系統的演進應當是循序漸進的,始終圍繞解決系統中存在的問題展開,技術的不斷演化和優化纔是推動架構進步的真正驅動力。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/0mziLRZEPRPYxMooQIkzkA