按照使用的資源型別劃分,我們可以把系統分為三大型別:
io密集型、計算密集型,資料密集型
。系統的型別反映了系統的主要瓶頸。現實情況中,大部分系統在由小變大的過程中,最先出現瓶頸的是io。io問題體現在兩個方面:高併發,儲存介質的讀寫(例如資料庫,磁碟等)。隨著業務邏輯的複雜化,接下來出現瓶頸的是計算,也就是常說的cpu idle不足。出現計算瓶頸的時候,一般會使用水平擴充套件(加機器)和垂直擴張(服務拆分)兩個方法。隨著資料量(使用者數量,客戶數量)的增長,再接下來出現瓶頸的是記憶體。
如今,記憶體的合理使用比以往更加重要。
一方面,大資料理論已經非常普及,用資料驅動產品也已經被普遍接受並落地,同時資料分析也促使產品設計的更加精細,因此系統承載的數量比以前有了很大的變化,系統遇到記憶體瓶頸的時間也比以前大大縮短了。另一方面,記憶體依然是相對昂貴的硬體,不能無限制的使用。即使在amazon等雲服務上,大記憶體的例項也是很昂貴的,並且大記憶體的例項往往伴隨著高效能型
cpu,這對一些資料密集型系統是乙個浪費。因此,本文重點**資料密集
系統如何應對出現的瓶頸。
任何工程上的問題最基本的思路都是「分而治之
」。因此,當記憶體不夠時,很自然的想法是將資料拆分到多台機器中,俗稱拆庫。沿用資料庫拆分的術語,拆庫又分為「水平拆分」和「垂直拆分」兩個派別。
水平拆分是指將同一種資料的不同記錄進行拆分。
例如我們有一億條商品資料供查詢。如果單機無法儲存,可以使用四台機器,每台機器儲存2500萬條商品資料。其中,每台機器稱為乙個「分片」,同乙個分片的多台機器組成乙個「分組」,從四個分組各選出一台機器組成乙個完整的服務。當上游服務進行查詢時,同時查詢四台機器,並對返回結果做合併。在使用水平拆分的方案時,需要重點考慮以下問題:
如前幾篇文章所述,任何大資料量系統中,在啟動之前都需要載入索引資料。索引資料一般是預先計算好的,並且以二進位制格式持久化的檔案。因為服務進行了拆分,每一台機器只需要載入一部分資料,因此需要為每個分組的機器單獨計算索引資料,這樣減少了系統啟動時處理的資料量,加快啟動速度。
利用 mq 這個機制,可以使每台機器只訂閱自己需要處理的資料,減少頻寬,也減少更新時處理的資料量,避免浪費資源。
在我們管理上下游機器時,一般會使用以 zookeeper 為核心的服務管理系統。即每個服務都註冊在 zookeeper 中,當上游服務需要訪問下游服務時,去 zookeeper 中查詢可用的下游服務列表,並同時考慮負載均衡等因素,選擇最合適的乙個下游服務例項。
當乙個服務出現分組時,管理的難度會增大。服務管理系統需要確保乙個服務的每個分組的例項同樣多,並且負載基本保持平衡。另外,當任何一台機器出現 故障導致的宕時,需要啟動備用機器。這時,需要判斷是哪個分組的機器發生了故障,並啟動相關分組的機器例項,重新註冊到 zk 中。
有很多資料是無法拆分的。一方面有些資料是天然不可拆分的,例如各種策略使用的詞典;另一方面,有些資料即使可以拆分,但和系統中其他資料的拆分規則不同,那麼系統也無法保證所有資料都能被拆分,只能優先拆分主要資料。
在傳統關係型資料庫的設計上,垂直拆分是指將一種資料的不同列進行拆分;在對系統架構的設計上,垂直拆分是只將乙個服務的不同計算邏輯拆分為多個服務。在使用垂直拆分的方案時,需要重點考慮以下問題:
如果是對響應時間要求很高的系統,一定會盡可能地避免垂直拆分,例如搜尋。而有一些對邏輯確實很複雜,對時間又不太敏感的系統,一般都會優先選擇垂直拆分,例如支付。
將服務進行了分層,更加了開發成本,對運維的要求也更高。
有一些資料會被拆分過的多個服務使用,會出現在上下游多個服務中,那麼資料的分發、更新都會更加複雜,即浪費資源,又進一步增加了系統的複雜度。因此,在垂直拆分的過程中,一定要盡可能將服務的功能做良好的劃分,避免一種資料被多個服務使用的情況。
垂直拆分的方案中,有一種情況可以大幅減少機器數量,即:一部分資料的存在並不是在處理請求的時候被直接使用,其存在是為了維護被處理請求的邏輯直接使用的資料
。 實際情況中,大型系統往往同時使用水平拆分和垂直拆分兩種方案。一方面,水平拆分雖然服務內部進行了分組,但對外仍然是單一的服務,因此從業務邏輯上來講更加簡單。另一方面,垂直拆分可以將非常複雜、計算資源有不同需求的業務邏輯進行很好的隔離,方便系統中各業務邏輯可以針對自己的特點進行開發和部署
。因此,在選擇拆分方案時,要結合系統的主要矛盾以及目前團隊成員的技術特點,綜合考慮做出選擇。
俗話說,當上帝為你關上了一扇門,必(可)定(能)為你開啟了一扇窗。如果說大資料是上帝為架構師關上的一扇門,那麼熱點資料就是開啟的那扇窗。雖然在現實世界中的資料是海量難以估算的,但幸運的是,有價值或者說值得關注的資料總是少數的。在大型系統中,請永遠把二八法則的重要性放在第一位。
一般來說,計算機的儲存系統分為**:cpu cache,記憶體,磁碟。這三者的訪問速度依次降低(並且是數量級的降低),單位儲存的成本也依次降低(也是數量級的降低)。多級儲存的基本思想是,按照被訪問頻率的不同給資料分類,訪問頻率越高的資料應當放在訪問速度越快的儲存介質中。
三種系統都使用頁式儲存的結構,頁也是其處理資料的最小單位。由於這個特性,我們一般在編寫程式時,盡可能地將連續訪問的資料放在記憶體的相鄰位置,以提高cpu cache的命中率,也就是常說的 locality principle。
隨著ssd的出現,對磁碟的使用已經出現了新的方**。機械磁碟的隨機讀寫速度在10ms左右,不太可能供實時系統使用。而ssd磁碟的隨機讀寫速度在100us左右,對於有些秒級響應的系統來說,已經可以作為實時系統的儲存介質。一種典型的情況是
系統存在相當數量的冷門資料
。系統對於熱點資料可以快速地反饋,對於很少被訪問的冷門資料可以儲存在ssd磁碟中。當冷門資料被訪問時,只要latency仍然可以控制在秒級,就可以在保證使用者體驗只有很少的損害的情況下,大幅減少系統成本。
一種典型的場景是電商的商品資訊。經常被訪問的商品可能不到商品總量的1%。像**這樣規模的電商系統,實際可能比1%還低。在使用磁碟作為可以提供實時查詢功能的儲存介質時,很常見的方案是將磁碟作為二級快取,將最近訪問的資料儲存在記憶體中,當訪問的資料不在記憶體中時,從磁碟讀取,並放入記憶體中。這個方案的假設是,最近被訪問的資料很可能在接下來仍然被訪問。採用這種方案需要重點注意,防止爬蟲或者外部的惡意請求短期內訪問大量冷門資料,造成實際的熱點資料被換出快取,導致處理真實請求時有大量的快取失效。另外,回想上文提到的檢索服務的案例。正排索引除了可以拆分為單獨的服務之外,還可以儲存在磁碟中。更新正排索引的時候直接從磁碟讀取資料,修改後寫會磁碟,同時更新記憶體的倒排索引。如果使用ssd磁碟,雖然更新的延遲會增長,但也會控制在毫秒級,對於系統完全是可以接受的。要知道,在一條資料到達檢索服務之前,都會經過若干次網路傳輸,由磁碟引起的延遲並不是主要因素。
計算密集型 IO密集型 資料密集型
2 計算密集型任務雖然也可以用多工完成,但是任務越多,花在任務切換的時間就越多,cpu執行任務的效率就越低,所以,要最高效地利用cpu,計算密集型任務同時進行的數量應當等於cpu的核心數。3 計算密集型任務由於主要消耗cpu資源,因此,執行效率至關重要。python這樣的指令碼語言執行效率很低,完全...
資料密集型 大資料
科學研究四大正規化 第一正規化 經驗科學 人類最早的科學研究,主要以記錄和描述自然現象為特徵,又稱為 實驗科學 經驗科學是 理論科學 的對稱,指偏重於經驗事實的描述和明確具體的實用性的科學,一般較少抽象的理論概括性。在研究方法上,以歸納為主,帶有較多盲目性的觀測和實驗。一般科學的早期階段屬經驗科學,...
如何設計IO密集型多執行緒和CPU密集型多執行緒?
多執行緒技術是我們日常工作中遇到的最常見的技術了,它的使用經常伴隨著執行緒池,今天我們聊聊如何設計乙個合理的執行緒池。首先執行緒池是一種多執行緒處理形式,處理過程中將任務新增到佇列,然後在建立執行緒後自動啟動這些任務。如果所有執行緒池執行緒都始終保持繁忙,但佇列中包含掛起的工作,則執行緒池將在一段時...