按照使用的資源類型劃分,咱們能夠把系統分爲三大類型:IO密集型、計算密集型,數據密集型。系統的類型反映了系統的主要瓶頸。現實狀況中,大部分系統在由小變大的過程當中,最早出現瓶頸的是IO。IO問題體如今兩個方面:高併發,存儲介質的讀寫(例如數據庫,磁盤等)。隨着業務邏輯的複雜化,接下來出現瓶頸的是計算,也就是常說的CPU idle不足。出現計算瓶頸的時候,通常會使用水平擴展(加機器)和垂直擴張(服務拆分)兩個方法。隨着數據量(用戶數量,客戶數量)的增加,再接下來出現瓶頸的是內存。數據庫
現在,內存的合理使用比以往更加劇要。一方面,大數據理論已經很是普及,用數據驅動產品也已經被廣泛接受並落地,同時數據分析也促使產品設計的更加精細,所以系統承載的數量比之前有了很大的變化,系統遇到內存瓶頸的時間也比之前大大縮短了。另外一方面,內存依然是相對昂貴的硬件,不能無限制的使用。即便在Amazon等雲服務上,大內存的實例也是很昂貴的,而且大內存的實例每每伴隨着高性能型CPU,這對一些數據密集型系統是一個浪費。所以,本文重點探討數據密集系統如何應對出現的瓶頸。緩存
任何工程上的問題最基本的思路都是「分而治之」。所以,當內存不夠時,很天然的想法是將數據拆分到多臺機器中,俗稱拆庫。沿用數據庫拆分的術語,拆庫又分爲「水平拆分」和「垂直拆分」兩個派別。服務器
水平拆分是指將同一種數據的不一樣記錄進行拆分。網絡
例如咱們有一億條商品數據供查詢。若是單機沒法存儲,可使用四臺機器,每臺機器存儲2500萬條商品數據。其中,每臺機器稱爲一個「分片」,同一個分片的多臺機器組成一個「分組」,從四個分組各選出一臺機器組成一個完整的服務。當上遊服務進行查詢時,同時查詢四臺機器,並對返回結果作合併。架構
在使用水平拆分的方案時,須要重點考慮如下問題:併發
索引服務負載均衡
如前幾篇文章所述,任何大數據量系統中,在啓動以前都須要加載索引數據。索引數據通常是預先計算好的,而且以二進制格式持久化的文件。由於服務進行了拆分,每一臺機器只須要加載一部分數據,所以須要爲每一個分組的機器單獨計算索引數據,這樣減小了系統啓動時處理的數據量,加快啓動速度。運維
數據更新高併發
一樣,因爲每臺機器只須要加載一部分數據,那麼也只須要處理這部分數據的更新。目前主流的更新數據流都是使用 Mesage Queue 做爲傳輸和持久化系統個,在服務端接收 Message Queue 的數據並持久化到本地,供在線服務按期讀取。通常同一類的數據使用一個 Topic 傳輸,同時 Message Queue 通常都支持 Partition 的機制。即在向 MQ 中發送一條數據時,能夠指定將該條數據發送到哪一個 Partition;在從 MQ 中讀取數據時,能夠指定只讀取哪些 Partition 的數據。例如上文的例子,存儲商品數據的服務器分了四個組,所以能夠將傳輸商品更新數據的 Topic 劃分爲四個 Partition,每一個分組的機器只須要訂閱其須要的 Partition 便可。在實際操做中,爲了保持將來的擴展性,通常 Partition 的數量都會設置爲分組數量的若干倍,例如八個或者十六個,這樣在將來數據量進一步增加致使分組個數進一步增長時,不須要修改 MQ 的 Partition 配置。性能
利用 MQ 這個機制,可使每臺機器只訂閱本身須要處理的數據,減小帶寬,也減小更新時處理的數據量,避免浪費資源。
服務管理的複雜性
在咱們管理上下游機器時,通常會使用以 ZooKeeper 爲核心的服務管理系統。即每一個服務都註冊在 ZooKeeper 中,當上遊服務須要訪問下游服務時,去 ZooKeeper 中查詢可用的下游服務列表,並同時考慮負載均衡等因素,選擇最合適的一個下游服務實例。
當一個服務出現分組時,管理的難度會增大。服務管理系統須要確保一個服務的每一個分組的實例一樣多,而且負載基本保持平衡。另外,當任何一臺機器出現 故障致使的宕時,須要啓動備用機器。這時,須要判斷是哪一個分組的機器發生了故障,並啓動相關分組的機器實例,從新註冊到 ZK 中。
沒法拆分的數據
有不少數據是沒法拆分的。一方面有些數據是自然不可拆分的,例如各類策略使用的詞典;另外一方面,有些數據即便能夠拆分,但和系統中其餘數據的拆分規則不一樣,那麼系統也沒法保證全部數據都能被拆分,只能優先拆分主要數據。
在傳統關係型數據庫的設計上,垂直拆分是指將一種數據的不一樣列進行拆分;在對系統架構的設計上,垂直拆分是隻將一個服務的不一樣計算邏輯拆分爲多個服務。在使用垂直拆分的方案時,須要重點考慮如下問題:
增長網絡請求次數,增長系統響應時間
若是是對響應時間要求很高的系統,必定會盡量地避免垂直拆分,例如搜索。而有一些對邏輯確實很複雜,對時間又不太敏感的系統,通常都會優先選擇垂直拆分,例如支付。
增長系統複雜度
將服務進行了分層,更加了開發成本,對運維的要求也更高。
數據冗餘
有一些數據會被拆分過的多個服務使用,會出如今上下游多個服務中,那麼數據的分發、更新都會更加複雜,即浪費資源,又進一步增長了系統的複雜度。所以,在垂直拆分的過程當中,必定要儘量將服務的功能作良好的劃分,避免一種數據被多個服務使用的狀況。
垂直拆分的方案中,有一種狀況能夠大幅減小機器數量,即:一部分數據的存在並非在處理請求的時候被直接使用,其存在是爲了維護被處理請求的邏輯直接使用的數據。
一個典型的例子是檢索服務中的正排索引。檢索服務在查詢時,直接使用的是倒排索引,而倒排索引是根據正排索引生成的。正排索引每每有多種數據,當一條數據發生更新時,會影響其餘類別的數據。所以,一條數據的更新信息沒法被單獨處理,在系統的內存中每每同時維護正排索引和倒排索引,致使內存翻倍。這種狀況下,若是咱們把正排索引獨立到一臺離線機器中,這臺機器維護正排索引的所有數據,當正排索引起生更新時,倒排索引的更新信息,並分發給全部在線機器。那麼,在線服務就不須要維護正排索引,可以大幅度減小內存的使用。
實際狀況中,大型系統每每同時使用水平拆分和垂直拆分兩種方案。一方面,水平拆分雖然服務內部進行了分組,但對外仍然是單一的服務,所以從業務邏輯上來說更加簡單。另外一方面,垂直拆分能夠將很是複雜、計算資源有不一樣需求的業務邏輯進行很好的隔離,方便系統中各業務邏輯能夠針對本身的特色進行開發和部署。所以,在選擇拆分方案時,要結合系統的主要矛盾以及目前團隊成員的技術特色,綜合考慮作出選擇。
俗話說,當上帝爲你關上了一扇門,必(可)定(能)爲你打開了一扇窗。若是說大數據是上帝爲架構師關上的一扇門,那麼熱點數據就是打開的那扇窗。雖然在現實世界中的數據是海量難以估算的,但幸運的是,有價值或者說值得關注的數據老是少數的。在大型系統中,請永遠把二八法則的重要性放在第一位。
通常來講,計算機的存儲系統分爲三級:CPU Cache,內存,磁盤。這三者的訪問速度依次下降(而且是數量級的下降),單位存儲的成本也依次下降(也是數量級的下降)。多級存儲的基本思想是,按照被訪問頻率的不一樣給數據分類,訪問頻率越高的數據應當放在訪問速度越快的存儲介質中。
三種系統都使用頁式存儲的結構,頁也是其處理數據的最小單位。因爲這個特性,咱們通常在編寫程序時,儘量地將連續訪問的數據放在內存的相鄰位置,以提升CPU Cache的命中率,也就是常說的 locality principle。
隨着SSD的出現,對磁盤的使用已經出現了新的方法論。機械磁盤的隨機讀寫速度在10ms左右,不太可能供實時系統使用。而SSD磁盤的隨機讀寫速度在100us左右,對於有些秒級響應的系統來講,已經能夠做爲實時系統的存儲介質。一種典型的狀況是系統存在至關數量的冷門數據。系統對於熱點數據能夠快速地反饋,對於不多被訪問的冷門數據能夠存儲在SSD磁盤中。當冷門數據被訪問時,只要latency仍然能夠控制在秒級,就能夠在保證用戶體驗只有不多的損害的狀況下,大幅減小系統成本。
一種典型的場景是電商的商品信息。常常被訪問的商品可能不到商品總量的1%。像淘寶這樣規模的電商系統,實際可能比1%還低。
另外一種典型的場景是用戶評論。不管按評論發表的前後順序,仍是按某種規則計算出的評論的質量度排序,老是前100個左右的評論被常常訪問,後面的評論幾乎不會被訪問到。
另外,回想上文提到的檢索服務的案例。正排索引除了能夠拆分爲單獨的服務以外,還能夠存儲在磁盤中。更新正排索引的時候直接從磁盤讀取數據,修改後寫會磁盤,同時更新內存的倒排索引。若是使用SSD磁盤,雖然更新的延遲會增加,但也會控制在毫秒級,對於系統徹底是能夠接受的。要知道,在一條數據到達檢索服務以前,都會通過若干次網絡傳輸,由磁盤引發的延遲並非主要因素。
在使用磁盤做爲能夠提供實時查詢功能的存儲介質時,很常見的方案是將磁盤做爲二級緩存,將最近訪問的數據保存在內存中,當訪問的數據不在內存中時,從磁盤讀取,並放入內存中。這個方案的假設是,最近被訪問的數據極可能在接下來仍然被訪問。採用這種方案須要重點注意,防止爬蟲或者外部的惡意請求短時間內訪問大量冷門數據,形成實際的熱點數據被換出緩存,致使處理真實請求時有大量的緩存失效。
大數據技術對商業效果的提高已經在愈來愈多的行業中被證實,將來的服務,不管是在線仍是離線,處理的數據都會有數量級甚至幾個數量級的增加。同時,咱們看到內存除了訪問速度愈來愈快,在存儲的數據量和成本上並無太大的變化。所以,將來愈來愈多的系統的主要瓶頸會從計算、IO轉移到數據量上,內存密集型系統會變得愈來愈重要,相信其架構在將來幾年也會有不少新的方式出現。