1. 程式人生 > >淘寶雙11的伺服器架構分析(2)

淘寶雙11的伺服器架構分析(2)

NoSQL是SQL的有益補充

  在MyFOX出現之後,一切都看起來那麼完美,開發人員甚至不會意識到MyFOX的存在,一條不用任何特殊修飾的SQL語句就可以滿足需求。這個狀態持續了很長一段時間,直到有一天,我們碰到了傳統的關係型資料庫無法解決的問題——全屬性選擇器(如圖5所示)。

 淘寶資料魔方技術架構解析【轉】

圖5 全屬性選擇器

  這是一個非常典型的例子。為了說明問題,我們仍然以關係型資料庫的思路來描述。對於膝上型電腦這個類目,使用者某一次查詢所選擇的過濾條件可能包括“筆記本尺寸”、“筆記本定位”、“硬碟容量”等一系列屬性(欄位),並且在每個可能用在過濾條件的屬性上,屬性值的分佈是極不均勻的。在圖5中我們可以看到,膝上型電腦的尺寸這一屬性有著10個列舉值,而“藍芽功能”這個屬性值是個布林值,資料的篩選性非常差。

  在使用者所選擇的過濾條件不確定的情況下,解決全屬性問題的思路有兩個:一個是窮舉所有可能的過濾條件組合,在“雲梯”上進行預先計算,存入資料庫供查詢;另一個是儲存原始資料,在使用者查詢時根據過濾條件篩選出相應的記錄進行現場計算。很明顯,由於過濾條件的排列組合幾乎是無法窮舉的,第一種方案在現實中是不可取的;而第二種方案中,原始資料儲存在什麼地方?如果仍然用關係型資料庫,那麼你打算怎樣為這個表建立索引?

  這一系列問題把我們引到了“建立定製化的儲存、現場計算並提供查詢服務的引擎”的思路上來,這就是Prometheus(如圖6所示)。

淘寶資料魔方技術架構解析【轉】

圖6 Prom的儲存結構

  從圖6可以看出,我們選擇了HBase作為Prom的底層儲存引擎。之所以選擇HBase,主要是因為它是建立在HDFS之上的,並且對於MapReduce有良好的程式設計介面。儘管Prom是一個通用的、解決共性問題的服務框架,但在這裡,我們仍然以全屬性選擇為例,來說明Prom的工作原理。這裡的原始資料是前一天在淘寶上的交易明細,在HBase叢集中,我們以屬性對(屬性與屬性值的組合)作為row-key進行儲存。而row-key對應的值,我們設計了兩個column-family,即存放交易ID列表的index欄位和原始交易明細的data欄位。在儲存的時候,我們有意識地讓每個欄位中的每一個元素都是定長的,這是為了支援通過偏移量快速地找到相應記錄,避免複雜的查詢演算法和磁碟的大量隨機讀取請求。

淘寶資料魔方技術架構解析【轉】

圖7 Prom查詢過程

  圖7用一個典型的例子描述的Prom在提供查詢服務時的工作原理,限於篇幅,這裡不做詳細描述。值得一提的是,Prom支援的計算並不僅限於求和SUM運算,統計意義上的常用計算都是支援的。在現場計算方面,我們對HBase進行了擴充套件,Prom要求每個節點返回的資料是已經經過“本地計算”的區域性最優解,最終的全域性最優解只是各個節點返回的區域性最優解的一個簡單彙總。很顯然,這樣的設計思路是要充分利用各個節點的平行計算能力,並且避免大量明細資料的網路傳輸開銷。

  用中間層隔離前後端

  上文提到過,MyFOX和Prom為資料產品的不同需求提供了資料儲存和底層查詢的解決方案,但隨之而來的問題是,各種異構的儲存模組給前端產品的使用帶來了很大的挑戰。並且,前端產品的一個請求所需要的資料往往不可能只從一個模組獲取。

  舉個例子,我們要在資料魔方中看昨天做熱銷的商品,首先從MyFOX中拿到一個熱銷排行榜的資料,但這裡的“商品”只是一個ID,並沒有ID所對應的商品描述、圖片等資料。這個時候我們要從淘寶主站提供的介面中去獲取這些資料,然後一一對應到熱銷排行榜中,最終呈現給使用者。

 淘寶資料魔方技術架構解析【轉】

圖8 glider的技術架構

  有經驗的讀者一定可以想到,從本質上來講,這就是廣義上的異構“表”之間的JOIN操作。那麼,誰來負責這個事情呢?很容易想到,在儲存層與前端產品之間增加一箇中間層,它負責各個異構“表”之間的資料JOIN和UNION等計算,並且隔離前端產品和後端儲存,提供統一的資料查詢服務。這個中間層就是glider(如圖8所示)。

  快取是系統化的工程

  除了起到隔離前後端以及異構“表”之間的資料整合的作用之外,glider的另外一個不容忽視的作用便是快取管理。上文提到過,在特定的時間段內,我們認為資料產品中的資料是隻讀的,這是利用快取來提高效能的理論基礎。

  在圖8中我們看到,glider中存在兩層快取,分別是基於各個異構“表”(datasource)的二級快取和整合之後基於獨立請求的一級快取。除此之外,各個異構“表”內部可能還存在自己的快取機制。細心的讀者一定注意到了圖3中MyFOX的快取設計,我們沒有選擇對彙總計算後的最終結果進行快取,而是針對每個分片進行快取,其目的在於提高快取的命中率,並且降低資料的冗餘度。

  大量使用快取的最大問題就是資料一致性問題。如何保證底層資料的變化在儘可能短的時間內體現給終端使用者呢?這一定是一個系統化的工程,尤其對於分層較多的系統來說。

 淘寶資料魔方技術架構解析【轉】

圖9 快取控制體系

  圖9向我們展示了資料魔方在快取控制方面的設計思路。使用者的請求中一定是帶了快取控制的“命令”的,這包括URL中的query string,和HTTP頭中的“If-None-Match”資訊。並且,這個快取控制“命令”一定會經過層層傳遞,最終傳遞到底層儲存的異構“表”模組。各異構“表”除了返回各自的資料之外,還會返回各自的資料快取過期時間(ttl),而glider最終輸出的過期時間是各個異構“表”過期時間的最小值。這一過期時間也一定是從底層儲存層層傳遞,最終通過HTTP頭返回給使用者瀏覽器的。

  快取系統不得不考慮的另一個問題是快取穿透與失效時的雪崩效應。快取穿透是指查詢一個一定不存在的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。

  有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的資料雜湊到一個足夠大的bitmap中,一個一定不存在的資料會被這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。在資料魔方里,我們採用了一個更為簡單粗暴的方法,如果一個查詢返回的資料為空(不管是資料不存在,還是系統故障),我們仍然把這個空結果進行快取,但它的過期時間會很短,最長不超過五分鐘。

  快取失效時的雪崩效應對底層系統的衝擊非常可怕。遺憾的是,這個問題目前並沒有很完美的解決方案。大多數系統設計者考慮用加鎖或者佇列的方式保證快取的單執行緒(程序)寫,從而避免失效時大量的併發請求落到底層儲存系統上。在資料魔方中,我們設計的快取過期機制理論上能夠將各個客戶端的資料失效時間均勻地分佈在時間軸上,一定程度上能夠避免快取同時失效帶來的雪崩效應。

  結束語

  正是基於本文所描述的架構特點,資料魔方目前已經能夠提供壓縮前80TB的資料儲存空間,資料中間層glider支援每天4000萬的查詢請求,平均響應時間在28毫秒(6月1日資料),足以滿足未來一段時間內的業務增長需求。

  儘管如此,整個系統中仍然存在很多不完善的地方。一個典型的例子莫過於各個分層之間使用短連線模式的HTTP協議進行通訊。這樣的策略直接導致在流量高峰期單機的TCP連線數非常高。所以說,一個良好的架構固然能夠在很大程度上降低開發和維護的成本,但它自身一定是隨著資料量和流量的變化而不斷變化的。我相信,過不了幾年,淘寶資料產品的技術架構一定會是另外的樣子。

  其他文章摘要

【1】海量資料領域涵蓋分散式資料庫、分散式儲存、資料實時計算、分散式計算等多個技術方向。

  對於海量資料處理,從資料庫層面來講無非就是兩點:1、壓力如何分攤,分攤的目的就是為了把集中式變為分散式。2、採用多種的儲存方案,針對不同的業務資料,不同的資料特點,採用RDBMS或採用KV Store,選擇不同資料庫軟體,使用集中式或分散式儲存,或者是其他的一些儲存方案。

  【2】將資料庫進行拆分,包括水平拆分和垂直拆分。

  水平拆分主要解決兩個問題:1、底層儲存的無關性。2、通過線性的去增加機器,支援資料量以及訪問請求包括TPS(Transaction Per Second)、QPS(Query Per Second)的壓力增長。其方式如把一張大資料表按一定的方式拆分到不同的資料庫伺服器上。

  海量資料從集中式走向分散式,可能涉及跨多個IDC容災備份特性。

  【3】阿里巴巴的資料對不同地域資料的處理方法。

  由三個產品密切配合解決:是Erosa、Eromanga和Otter。

  Erosa做MySQL(或其他資料庫庫)的Bin-Log時時解析,解析後放到Eromanga。Eromanga是增量資料的釋出訂閱的產品。Erosa產生了時時變更的資料釋出到Eromanga。然後各個業務端(搜尋引擎、資料倉庫或關聯的業務方)通過訂閱的方式,把時時變更的資料時時的通過Push或Pull的方式拉到其業務端,進行一些業務處理。而Otter就是跨IDC的資料同步,把資料能及時反映到不同的AA站。

  資料同步可能會有衝突,暫時是以那個站點資料為優先,比如說A機房的站點的資料是優先的,不管怎麼樣,它就覆蓋到B的。

  【4】對於快取。

  1、注意切分力度,根據業務選擇切分力度。把快取力度劃分的越細,快取命中率相對會越高。
  2、確認快取的有效生命週期。

  【5】拆分策略

  1、按欄位拆分(最細力度)。如把表的Company欄位拆掉,就按COMPANY_ID來拆。

  2、按表來拆,把一張表拆到MySQL,那張表拆到MySQL叢集,更類似於垂直拆分。

  3、按Schema拆分,Schema拆分跟應用相關的。如把某一模組服務的資料放到某一機群,另一模組服務的資料放到其他MySQL機群。但對外提供的整體服務是這些機群的整體組合,用Cobar來負責協調處理。

  Cobar類似於MySQL Proxy,解析MySQL所有的協議,相當於可以把它看成MySQL Server來訪問的。