勿谈大,且看Bloomberg的中数据处理平台
勿談大,且看Bloomberg的中數據處理平臺
摘要:中數據意味著數據體積已經超越單服務器處理的上限,但也無需使用數千臺節點組成的集群——通常是TB級,而不是PB級的。這里,我們不妨走進Bloomberg的用例,著眼時間序列數據處理上的數據和體積挑戰。
中數據意味著數據體積已經超越單服務器處理的上限,但也無需使用數千臺節點組成的集群——通常是TB級,而不是PB級的。這里,我們不妨走進Bloomberg的用例,著眼時間序列數據處理上的數據和體積挑戰。
以下為譯文
在Bloomberg,我們并不存在大數據挑戰。取而代之,系統正在遭遇“中數據(Medium?data)”的威脅,而當下許多行業的機構基本上都面臨著這種威脅。對Bloomberg來說,在企業級低延時場景下,Hadoop和Spark這樣的系統既沒有效率,也難以維護。時至今日,高核心數、SSD以及海量內存已并不稀奇,但是當下的大數據平臺(通過搭建商用服務器集群)卻并不能完全利用這些硬件的優勢,存在的挑戰也不可謂不大。同時,當下很多分布式組件也深受Java的影響,很難達到預期的低延時性能。
一個實際用例
債券時間序列數據通常包括一個債券(比如IBM)、一個字段(比如price)、一個時間和一個值。
通常情況下,數據會被拆分成兩個部分:當天數據和歷史數據——處理當天數據的系統通常會捕獲一天中的所有行為,而處理歷史數據的系統需要負責前一段時間所積累的數據。在過去,統一這兩種數據是不可能實現的,因為他們有著不同的性能需求:當天數據的處理系統必須可以承受大量的寫入操作,而歷史數據處理系統通常是每天一次的批量更新,但是數據體積更大,而且搜索次數也更多。
在債券時間序列數據上,在總量為一年的數據上,某個字段的響應時間需要控制在5毫秒。同時,這些數據每天會被訪問數十億次,峰值期間大約50萬每秒。對于Bloomberg來說,這個系統非常重要,一旦發生故障,很可能就會擾亂到資本市場。
問題隨之而來,類似Portfolio?Analytics等應用往往會同時需求大量的數據。一個債券組合很可能包括數以萬計的債券,而類似歸因(attribution)這種計算往往需要每個源每天40個字段的數據。從而,在多年數據上計算一個債券組合的歸因需要上千萬的數據點(datapoint)。因此,即使在命中率為99.9%的高效緩存中,仍然存在大量緩存未命中的情況。這樣一來,如果底層系統使用磁盤介質的話,這個操作往往會造成成千上萬的磁盤尋道。同時,基于用戶的數量,系統中存在著大量的請求。因此,不難想象,這會給現有價格歷史系統造成什么樣的挑戰。
數年前,解決這個問題的途徑是將一切都放到內存和固態硬盤上,同時將高度壓縮的blobs分割到多個數據庫中。這是一個巨大的飛躍,系統速度提升了2到3個數量級,然而這并不是我們想要的——跨多數據庫壓縮blobs分割是非常麻煩的。
時間序列數據通常會轉化為非常極端的并行問題,往往會出現這樣一個情況:當為一個組合取數以千萬計的數據點時,工作可以根據需求被任意拆分到數以千萬的主機上。這樣看來,并行似乎是最好的解決方案。而在單主表的分布式處理上,理論中HBase應該是個非常契合的計算框架。
當然從理論上講,理論和實踐應該是一致的,然而在實踐中往往并不是一直如此。數據集確實可以達到一定的效果,但是在性能、效率、期滿及彈性上都存在一定的障礙。這樣一來,問題就在于如何移除這些障礙。
當一個節點發生故障后,數據并不會丟失——因為數據已經通過HDFS備份到多個節點上。但是這里仍然存在一個非常大的缺點,在任何給定時間,到給定region的讀寫操作只被一個region服務器控制。如果這個region掛掉,故障將會被發現,故障轉移會自動的進行。但是,直到這個故障被處理前,它負責的任何讀寫都不可能繼續進行。
在故障轉移上,HBase社區的發展可以說是日新月異,需求的時間也是愈來愈少,但是這里仍然存在一個巨大的漏洞。分布式系統中的故障往往通過設置期滿判定,通過心跳或者其他機制來感知。這樣一來,如果超時被設置的太短,很可能就會產生誤報,但是如果時間被設置太長,則會造成更長時間的不可用。
在Bloomberg用例下,SLA是毫秒級的。但是,超時的設置卻是秒級的,這樣一來,即使故障被偵測后的處理時間無限接近于0,HBase故障轉移所造成的延時完全不可行。
在與多個Hadoop提供商交流后,我們也得到了幾個可行的解決方案,其中大部分是通過給數據庫做多個備份來解決問題。鑒于Bloomberg系統可以應對整個數據中心丟失的大方針,使用這個途徑無疑需要給每個數據庫配置多個同時運行的副本,在我們看來這么做太復雜了。最終,我們對這個替代方案并不滿意,并決定嘗試修改。
如果故障轉移檢測和恢復過程不能被加速,那么某個region服務器發生故障后,這里必須存在可以立刻被查詢的備用節點。根據這個思路,我們擬定了短期解決方案:數據必須在多個不同的地方進行存儲,雖然在傳輸上可能會存在一定的延時,但是在這種存在大量批處理更新場景的類似價格歷史日結系統中卻完全可行——在備用region服務器上使用這個策略可以保證事件接收的順序,提供了時間序列上的一致性,即使延時很高。
時間序列一致性備份region服務器被作為JIRA-10070的一部分添加到HBase中。
結論和下一步
除下故障轉移,HBase還存在大量其他的問題。仔細地檢查了瓶頸的來源,進行了大量的優化后(比如使用同步垃圾回收機制),系統性能得到了顯著提升:
- PORT寫入性能提升1000倍
- Read檢索速度較之前提升3倍
通過HBase實驗,我們將運行時響應時間縮短到原來的四分之一,并為將來提升留下了足夠的發展空間。同時,更快的機器也有利于縮短響應時間。通過使用開源平臺,我們認真思索來自多個提供商的意見,在中型數據處理上,我們可以看到很大的發展空間。
更重要的是,我們的收獲不只是性能一個特性,我們更可以通過開源技術連接到一個更廣泛的發展空間。
附錄:HBase分配圖解
性能1:分布和并行
性能2:同址計算
即使故障得以解決,在原始性能和一致性上仍然存在問題,這里我們將詳述性能上的3個實驗和結果。實驗應用在一個合適的集群上,擁有11臺搭載SSD的主機,每臺主機配備了兩個志強E5處理器以及128GB內存。在講義的右上角顯示了兩個數字,第一個是實驗初始時的平均響應時間,另一個則是進行改進后的響應時間,平均請求時間來自20萬個記錄上做隨機的鍵值查詢。
使用HBase,用戶可以在大的Portfolio文件上做拆分,并且分配到集群中的多個主機上進行處理。這也是為什么要托管備用的region服務器以應對故障——如果請求發送到每個服務器,其中一個服務器在1分鐘或者更多的時間內沒有反應,很明顯這個服務器已經出現問題,一個服務器產生故障將拖累集群中所有作業的處理時間。
因此,下一個需要著重對待的就是分配和并行。第一個工作就是如何平均的將作業拆分:在一個指定的大數據集上,集群中每臺機器獲得的chunk大小都是相同的?理想狀態中,對1000行的數據進行拆分,每臺服務器都應該獲得100行。然而在一個簡單的架構中,這點根本無法實現:如果原始鍵是債券名+XXX,那么所有IBM債券將放在同一個region中,同時,IBM將比其他債券更經常得到訪問,這種現象也被稱為hotspotting。
解決方案是使用HBase提供的特性來彌補。HBase中的數據總會通過原始鍵進行物理劃分,如果原始鍵本身已經被哈希,同時這種哈希被作為一個前綴,隨后行則會以不同的方式進行分配。想象一下,如果原始鍵是security+year+month+field,取它的MD5,并將之作為一個前綴,那么IBM這個債券分配到任何服務器上的可能性都會相同。
在一個完美的分配中,我們將獲得一個完美的并行性:集群中11個節點都會做相同數量的作業。每個工作不只是負責相同的工作量,在每個請求上也會同樣平均。毫無疑問,這里需要做的是盡可能地提升系統并行性。
解決這個問題的一個方法就是在每臺主機上運行盡量多的region服務器,因此需要盡量提升主機的性能。這將提升總的region服務器數量,從而提升并行性的等級,隨之顯著的減少響應時間。
講義中的圖表顯示了這個實驗的結果。如果11臺服務器上每個只搭建一個region,總計11個,平均響應時間是260毫秒。當region數量提升到每臺主機3個時,也就是總計33臺主機,平均響應時間將下降到185毫秒。每臺主機上5個region服務器將提升到160毫秒。但是如果每臺主機上的region服務器提升到10個時,響應時間反而會提高,為什么?
出現這種問題后,首先想到的可能就是負載是否超過了服務器的性能;每臺服務器同時運行10個region服務器進程,每個都擁有多個線程,顯然核心數量會不足。但是,根據研究,這個并還不足以作為影響系統的原因,真實的答案非常有意思,但是在揭開它之前,我們先看一下同址計算。
大數據的原理之一就是讓計算盡可能的靠近數據,這么做的理由非常簡單。舉個例子,如果你想知道一個大數據集表格中究竟有多少行,你可能需要將每一行都取到本地客戶端,然后循環訪問并進行計算,如果使用的是傳統數據庫環境,你還可以使用“select?count(*)?from…”,后者顯然是更加有效的。
說永遠比做容易。許多問題使用這個途徑是無法解決的,即使在許多已知的情況下,許多框架都會出現問題。在海量數據分析上,2013年National?Research?Council(國家研究委員會)提出了7個大型并行計算問題,希望對分布式計算系統進行良好的分類,比較有意思的是,根據測算結果,Hadoop并不適合所有類型。
幸運的是,我們有一個簡單的可用的用例,它可以再次減半響應時間。
現在的情況是,這里有數據的多個源,Barclays、Merrill?Lynch和多個公司都提供了債券計價數據。相同債券同一天的數據也可能出現在其他源中,但是價格可能不一致。每個客戶有不同的優先順序,每個請求都包含了某個源應該用在某個訂單的順序。嘗試從第一個數據源中獲取所有數據,如果發現丟失,則會嘗試下一個源。通常情況下,發現所有數據需要訪問5個這樣的數據源。
在分離數據庫世界中,不同的源都處于不同的地理位置中,這就意味著嘗試第一個數據庫,取得所有的數據,查詢丟失了什么,構成一個新的請求,并發布下一個任務。
對于HBase,我們仍然可以獲得物理分類的優勢,支持上千萬列,并通過協同處理器進行同址計算。
通過將源和字段列與security和date整合,它們將被混搭在相同的region服務器上?。協同處理器的邏輯將變為“為指定行發現第一個源,并進行security和date匹配”。
在一個只包含一些行的小協同處理器上,平均響應時間將降到85毫秒。
性能3:同步中斷
繼續上文的話題,增加region服務器數量降低性能給我們留下的謎題:為什么響應時間在開始時有改善,而隨后則會變得更糟糕?問題的答案涉及到兩個方面——Java和所有高fan?out分布式系統一些常見的問題。
一個涉及到不止1個fan?out的請求中,服務器訪問越高,fan?out的程度就越高。那么,在一個有fan?out的請求中,響應時間該如何計算?
答案就是,響應的時間由最慢的反應者決定,當給11臺主機每個都配備10個region服務器時,每個請求需要fan?out?110個進程。如果其中109個是1毫秒完成,1個請求是170毫秒,那么響應時間將高達170毫秒。
這里的罪魁禍首毫無疑問就是Java的垃圾回收機制,它會凍結一個機器直到回收結束。Fan-out的程度越高,其中一個region服務器在做垃圾回收的可能性就越大。當region數量達到110個時,可能性已經開始接近1。
這里的解決方案非常的簡單。既然在垃圾回收過程中所有的服務器都會被凍結,那么為什么不讓這些region服務器同時做垃圾回收?這種情況下,請求將需要更多的時間,但是毫無疑問的是,在處理的過程中,沒有region服務器會做垃圾回收。為此,我們編寫了不能再簡單的代碼進行測試——system.gc()以及30秒會調用一次這個方法的定時器。
通過這個操作,我們首次將相應時間從85毫秒降低到60毫秒。
Java垃圾回收機制這個詬病已經被廣泛認知,這也是Jeff?Dean歸納為Synchronized?Disruption中的一個問題。任何并行系統中的請求都需要遭受最慢者的摧殘,因此影響個體機器的問題將同時影響到整個系統。想獲得更多詳情,推薦閱讀“Achieving?Rapid?Response?Times?in?Large?Online?Services”,你將獲得更多關于高fan?out計算系統的使用經驗。
這就意味著,Java當下已經成為很多高fan?out計算系統的基礎,其中包括Hadoop、HBase、Spark、SOLR等,同步進行垃圾回收將解決非常大的問題。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的勿谈大,且看Bloomberg的中数据处理平台的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何编写高质量和可维护的代码
- 下一篇: Make!Sense 动手好伴侣,带你轻