IndexR:實時、基於Hadoop的數據倉庫
摘要
IndexR實現了一種可部署於分散式環境,可並行化處理,帶索引的,列式的結構化數據格式。基於這種數據格式,IndexR構建了一個數據倉庫系統(Data Warehouse),它基於Hadoop生態,可以對海量數據集做快速統計分析(OLAP),數據可實時導入並且對於查詢零延遲。IndexR 為解決大數據場景下分析緩慢、數據延遲、系統複雜等問題而設計。本文描述了IndexR的設計思想,系統架構,以及核心的技術細節。
目前IndexR項目已經開源,項目地址:https://github.com/shunfei/indexr。
簡介
舜飛科技的核心業務之一程序化廣告業務,對接全網的各大媒體,每秒產生上百萬的分析數據。這些數據對廣告投放活動的過程進行了精細的追蹤和描述,比如創意的展示量、點擊量,活動產生的註冊數、回訪數等。我們需要對這些數據進行實時分析處理,用於包括客戶報告,投放優化,欺詐分析,收費結算等。數據使用者的查詢模式是非固定的,無法預測的,並且隨著業務量的激增,數據量也急劇增長。我們需要一種新的技術來解決這些需求:
- 超大數據集,低查詢延時。查詢模式無法預測,無法預計算;表數據量普遍超過1億,甚至上百億千億,過濾條件有可能會命中大量數據;數據在查詢的同時還會有大量的更新,每秒入庫幾萬的數據。要保證較低的查詢延時,一般情況下查詢延時要求在5s以內,常用高頻查詢要求1s以內。
- 准實時。數據從產生到體現在分析結果延時幾秒以內。時效性對於某些業務至關重要,並且越實時的數據,價值越大。
- 可靠性,一致性,高可用。這些數據是公司最重要的數據之一,任何錯誤和不一致可能會直接體現在客戶報表中,對公司的業務和品牌形象產生影響,至關重要。
- 可擴展,低成本,易維護。業務會快速發展,會產生新的數據源,加入新的表,舊的數據不能刪除,這帶來巨大的成本壓力,和運維壓力。典型的更新如加列、列值更新等操作不能影響線上服務,不能帶來入庫或者查詢延遲。
- SQL支持。全面支持SQL,要像Mysql一樣好用,功能強大。不僅僅支持常見的多維分析,還需要支持複雜的分析查詢,如JOIN,子查詢等,支持自定義函數(UDF,UDFA)。
- 與Hadoop生態整合。Hadoop生態的蓬勃發展給大數據處理帶來越來越強的處理能力,如果能與它的工具鏈深度結合,會極大擴展系統的價值。
IndexR是舜飛科技大數據平台組為了應對這些挑戰的答案。我們無法在當前的開源產品中找到可以滿足所有以上需要的工具。
目前提供相似功能的產品,有些通過使用傳統的關係型數據技術,或者通過預先建Cube加速查詢。這些方式可能會帶來一些問題,比如運維困難,數據量瓶頸,或者模式不夠靈活,無法支持業務變化。有些方案使用內存存儲技術,使用上成本比較高,而且在大數據分析場景並無特別大的速度優勢。近年出現的一些時序資料庫,解決了一些入庫延遲方面的問題,但是在查詢性能,可用性,可擴展性等方面存在一些問題。
IndexR數據倉庫系統基於許多優秀的開源產品,並且參考了一些已經存在的工具,精心設計和實現而成。它把數據存放於HDFS,使用Zookeeper在集群中通訊和交涉,使用Hive方便的管理分區數據,可以通過Kafka高速實時導入數據,查詢層使用優秀的分散式查詢引擎Apache Drill。它的存儲和索引設計參考了Infobright社區版和Google Mesa論文,壓縮演算法借鑒了Infobright,實時入庫從HBase和Druid獲得啟發。
本文從以下幾個方面對IndexR進行闡述:
- 存儲格式與索引,IndexR的核心模塊。
- 實時入庫模塊,實現快速入庫並且查詢零延遲。
- 層次結構與部署架構,如何與Hadoop生態系統深度結合。
- 工程實現的問題以及解決方案。
- 典型項目選型。
- 數據倉庫在新環境下的挑戰,IndexR的意義。
目前在舜飛已經穩定運行,支撐了DSP、網站檢測分析等核心業務的實時分析任務,集群每天入庫消息300億+,目前總數據量為千億級別。
存儲格式與索引設計
數據文件
IndexR存儲結構化數據,比如以下是一個虛構的廣告投放用戶表 Table A:
數據文件稱為Segment,一個Segment保存一個表的部分行,包含所有的列,如下圖。
Segment文件是自解釋的,它包含版本信息,完整的表定義,各個部分的元數據(offset),以及索引。IndexR默認對所有的列進行索引。行順序可以是入庫的自然順序,也可以是按照用戶定義的欄位排序。這樣的設計可以簡化系統架構,不需要額外的元數據存儲,非常適合於分散式環境下的並行處理,也方便外部系統如Hive直接使用。
Segment的行數據在內部會進一步細分為pack,每個pack都有獨立的索引。pack內部的行數據是以列存儲的,即某一列的數據會集中存放在一起。這種方式對於列數據的快速遍歷,和壓縮帶來極大的優勢。對於現代通用計算機架構,cache友好,方便vector process,充分發揮現代多核CPU的性能。Segment的列數據使用特別優化的壓縮演算法,根據數據類型選擇不同的演算法和參數,通常壓縮率10:1以上。
在實際業務數據測試中,IndexR每個節點每秒可以處理1億個欄位。測試機器配置: [Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz] x 2, 60G RAM, SATA 7200 RPM DISK。這個配置在目前伺服器配置中算低端的,更強大的CPU會對IndexR有非常大的性能提升。
索引
IndexR採用粗糙集索引(Rough Set Index),它能以極低的成本,很高的精確度定位到相關文件和位置。
比如我們的某一個數據塊(pack)有以下數據,有date(int類型)和use_name(string)類型。
對於number類型,會記錄該列的最大值(max),最小值(min),然後把它們的區間(max-min)進行分割成多個區間,每一個區間使用一個bit表示。然後把各個具體的值映射到這個區間之中。IndexR對於number和string類型有不同的索引方式,這裡描述基本的思路。
比如查詢如圖,value值為1表示這個區間存在一行或者多行的數據,為0表示不存在。我們只需要存儲max,min,和value序列(5個bit)就完成了對這一列的索引。
SELECT user_name FROM A WHERE date = 20170106
因為20170106屬於區間2,value是0,即可以知道20170106不存在於這個pack,可以直接跳過。這是一種類似於bloomfilter的過濾方式,索引不命中的pack一定不包含需要的數據
string類型的索引和number類似,不過更加複雜一點。
目前常見的索引有B+樹索引,倒排索引,這些索引可以精確定位到具體行,在相對小數據量情況下很有效。這種方式通常沒有特別有效的壓縮,數據文件大小一般在原始數據的1~3倍之間,當數據量膨脹到一定程度,這類索引的代價就會被放大,甚至無法服務。
IndexR的粗糙集索引的優勢是非常快速,索引文件足夠小,可以低成本的方式load到內存,在極大數據量場景下仍然能有效的工作。由於數據通常是排序的內聚的,通過實際數據的觀察,列的值基數(cardinality)通常比較小,這種方式是可以有效的過濾掉無關的pack。它會對所有的列進行索引,非常適合於業務不固定,或者數據分析場景的探索型分析。
實時入庫
IndexR支持實時數據追加,但不支持數據在線更新,可以通過離線的方式使用Hive等工具更新數據,這樣的設計和Mesa類似。它的入庫速度非常快,通常單個節點單表可以達到30k消息/s。消息到達IndexR Node之後,可以立刻被查詢。
IndexR的實時入庫模塊使用類似LSM-Tree的結構。使用commitlog文件保存消息,最新的數據存放於內存,在達到一定閥值之後會被寫入硬碟。
內存中的數據周期性的存儲到硬碟,時間一久會產生較多碎片文件,這些文件在達到一定閥值之後,會被整理合併。
行的存儲順序可以是自然入庫順序,也可以按照指定欄位排序,類似於關係型資料庫中的一級索引和HBase中的Column Family,這樣做可以讓數據更加內聚,對於查詢非常有利。
類似於Mesa,如果需要,IndexR實時入庫可以根據多維分析(Multidimensional Analysis)的概念,把欄位分成維度(Dimension)和指標(Metric/Measure),具有相同維度的行會合併到一起,指標使用聚合函數(aggregation function, e.g. SUM, COUNT),並且表之間可以設計成父子關係。
如圖,Table B 與 Table C 可以可以認為是 Table A 的子表。Table A 擁有三個維度(date, country, campaign_id),可以表達最詳細的信息。Table B 與 Table C 通過減少維度,減少了數據量,可以更加快速的獲得查詢結果。
應用層只需要做簡單的表路由,比如
SELECT date, country, SUM(impressions) FROM B WHERE country = CN GROUP BY date, country
可以路由到Table B表,快速獲得結果。如果需要下鑽(Drill Down)查詢,如
SELECT campaign_id, SUM(impressions) FROM A WHERE country = CN and date = 20170101 GROUP BY campaign_id
則會路由到Table A。
這種設計類似於關係型資料庫中預聚合View。在OLAP領域,特別是多維分析場景,這種設計非常有效。
架構設計
IndexR的架構設計遵循簡單可靠、易擴展的原則。它可以大規模集群部署,支持上千個節點。事實上IndexR的硬體成本相對來說很低,並且可以通過加節點線性擴展處理能力。
Apache Drill作為IndexR的查詢層。Drill是一個全新的查詢引擎,專註於SQL計算,使用了代碼生成技術,vector process,列式計算,堆外內存(消除GC)等技術,有專門針對對於大數據集的優化。速度極快,並且支持標準SQL,沒有遷移負擔。從我們的使用經驗來看,它非常穩定,工程質量很高。
IndexR主要負責存儲層,並且對具體的查詢過程進行優化,比如常見的條件下推(predicate pushdown),limit下推等,未來還將支持聚合下推(aggregation pushdown)。IndexR通過任務分配演算法,結合數據距離、節點繁忙程度等,把計算任務分配到最合適的節點。
HDFS存儲具體的數據文件,分散式文件系統幫助構建節點無狀態的服務。數據存放於HDFS中,可以方便的使用各種Hadoop工具進行其他複雜分析。我們對接了Hive,方便對數據進行離線處理。由於HDFS上的數據只有一份,可以同時被多個工具處理,省去了繁瑣的同步步驟,在10:1的高壓縮比上又節省一倍空間。
數據經過Kafka等隊列高速導入IndexR。IndexR的實時導入非常靈活,可以隨時增加或者刪除導入節點。它擁有極高的導入性能(30k/s),入庫延遲的壓力成為歷史。
在IndexR集群中只有一種節點(IndexR Node),有利於部署和維護,不需要對節點進行劃分。目前IndexR作為Drill插件嵌入了Drillbit進程。
IndexR提供了indexr-tool工具,提供了完整的運維工具。比如可以在線更新表結構,在線添加、修改實時入庫配置。
工程實現的挑戰
演算法和數據結構要真正落地,必須通過具體的工程來實現,而工程實現的質量決定了項目的最終效果。如果空有高超的設計圖紙,而沒有高質量的施工和合適的材料,高樓大廈是建不起來的。IndexR在工程上最求極致的性能,但又不失靈活的擴展性。
- 使用直接內存(Direct Memory))。IndexR主要使用Java8編寫,而Java的堆內存(Heap)與垃圾回收(GC)的模式在大數據運算場景下面臨比較大的挑戰。在需要使用較大內存(超過32G)以及數據更新頻繁時,JVM的GC問題比較明顯,容易造成性能不穩定,並且對象實例的內存模型通常很浪費內存。我們在IndexR項目中把所有的存儲數據和運算臨時數據存放於堆外,手動管理內存申請釋放。這樣提高了代碼複雜度,但相比於傳統的堆內存模式,節省了超過1/2內存,並且沒有了GC代價,涉及大量數據的賦值操作通常可以使用內存拷貝,節省大量CPU循環。
- 充分利用現代CPU能力。IndexR的堆外內存模型對於充分發掘硬體潛能非常有益,它們通常是連續的內存塊,沒有類指針跳轉,沒有虛函數損耗,CPU寄存器和多級緩存都可以充分利用,而且對於使用vector processor非常便利,沒有結構轉換開銷。
- 避免隨機讀取。通常磁碟的特點是連續讀取非常快,因而Kafka可以使用磁碟做消息隊列;而隨機讀取相對很慢,故傳統資料庫的瓶頸一般在IO。IndexR的索引方式對磁碟連續讀取友好,並且它會對數據進行整理從而更加內聚。我們還特別對文件讀取方式進行了細緻的優化。
- 優化線程、IO調度。在任務非常繁忙的時候,CPU爭搶帶來的線程切換的開銷變的不可忽視。並且由於資料庫環境的特殊性,在做繁忙CPU任務的同時,還會進行網路、IO操作。如何做任務調度,合理安排線程數量和任務,對整體性能影響比較大。有時候單線程比多線程效率更高,並且更省資源。
- 關鍵性能點使用C++實現。它在同時涉及內存操作和複雜CPU運算場景時,運行效率優勢明顯。我們把關鍵的性能點,比如壓縮演算法,使用C++實現。
工具選型
IndexR是一個新的工具,如果你的項目有以下需求,或者之前已經有一些選型但是無法滿足需求,可以考慮使用IndexR。
IndexR適合的經典場景:
- 需要在海量數據之上做快速的統計分析查詢。
- 要求入庫速度非常快,並且需要實時分析。
- 存放超大量歷史明細資料庫。比如網站瀏覽信息,交易信息,安保數據,電力行業數據,物聯網設備採集數據等。這類數據通常量非常大,數據內容複雜,存放時間比較久,且希望在需要時可以比較快速的根據各種條件做明細查詢,或者在一定範圍內做複雜的分析。這種情況下可以充分發揮IndexR的低成本,可擴展,適合超大數據集的優勢。
目前業界典型選型:
- 使用Mysql,PostgreSQL等關係型資料庫,不僅用於業務查詢(OLTP),也做統計分析,一般是在現有業務資料庫上直接做一些分析需求。這種方式在數據量增長之後就會遇到性能問題,特別是分析查詢會對業務查詢產生極大影響。可以考慮把數據導入IndexR做分析,即把業務資料庫和分析資料庫分開。
- ES,Solr等全文搜索資料庫用於統計分析場景。這類資料庫最大的特點是使用了倒排索引解決索引問題。對於統計分析場景通常沒有特別優化,在大數據量場景下內存和磁碟壓力比較大。如果遇到性能問題,或者數據量撐不住了,可以考慮使用IndexR。
- Druid,Pinot等所謂時序資料庫。在查詢條件命中大量數據情況下可能會有性能問題,而且排序、聚合等能力普遍不太好,從我們的使用經驗來看運維比較困難,靈活性和擴展性不夠,比如缺乏Join、子查詢等。在保存大量歷史數據情況下需要的硬體資源相對昂貴。這種場景下可以考慮使用IndexR直接替換,不用擔心業務實現問題。
- Infobright,ClickHose等列式資料庫。列式資料庫本身非常適合於OLAP場景,IndexR也屬於列式資料庫。最大的區別在於IndexR是基於Hadoop生態的。
- 離線預聚合,建Cube,結果數據存放於HBase等KV資料庫,如Kylin等。這種方式在只有多維分析場景且查詢比較簡單的情況下非常有效。問題就在於靈活性不足(flexibility),無法探索式分析,以及更複雜的分析需求。IndexR可以通過表配置達到預聚合的效果,並且聚合是實時,沒有延遲的;可以保留原始數據或者高維度數據,通過表路由決定具體的查詢表。
- 為了解決大數據量的即時分析問題,上層使用Impala,Presto,SparkSQL,Drill等計算引擎來做查詢,存儲層使用開源數據格式比如Parquet,基於Hadoop生態。這類架構和IndexR很相似。IndexR的優勢在於更有效的索引設計,更好的性能,並且支持實時入庫,秒級延遲。我們在相同環境下與Parquet格式做過查詢性能對比,IndexR的查詢速度提升在3~8倍以上。之後IndexR經歷了很大的性能優化,估計會有更好的表現。
- Kudu,Phoenix等既支持OLTP場景,又為OLAP場景優化等開源產品。通常很難兩者兼顧,建議分成實時庫和歷史庫,針對不同數據特點採用不用的存儲方案。
- 內存資料庫。貴。
舜飛科技大數據平台組對於以上提到的大部分技術選型有著豐富的經驗,即這些工具我們或者在生成環境中使用過,或者有過深入的調研和測試,這也促使了IndexR的誕生。
思考和總結
大數據經過近些年的快速發展,完整的生態漸漸成熟,已經早已不是只有Hadoop跑MR任務的時代。人們在在滿足了能夠分析大量數據集的需求之後,漸漸的對時效性、易用性等方面提出了更高的要求,因而誕生了如Storm,Spark等新的工具。新的問題催生新的挑戰,提供新的機遇。而傳統的數據倉庫產品,在面對大數據的衝擊顯得非常無力。IndexR為解決這種現狀,提供了新的思路和方向。
IndexR是新一代數據倉庫系統,為OLAP場景而設計,可以對超大量的結構化數據進行快速的分析,支持快速的實時入庫。它功能強大,並簡單可靠,支持大規模集群部署。它與Hadoop生態系統深度整合,可以充分發揮大數據工具的能力。
不用再為分析能力的瓶頸擔憂,不用放棄經典的OLAP理論,不用降級你的服務,不用擔心業務人員對大數據工具不熟悉,IndexR像Mysql一樣好用,會SQL就好了。
IndexR在開源之後,我們已經看到有不少使用案例,包括國內外的不同團隊。有意思的是,有些團隊的使用方式比較特別,比如用於存放超大量(單表千億級別)的複雜明細數據,做歷史數據的明細查詢。IndexR不僅可以用於多維分析,商業智能等OLAP經典領域,還可以用於物聯網,輿情監控,人群行為分析等新興方向。
聯繫方式
- 聯繫郵箱:weiwan@sunteng.com
- QQ交流群:606666586 (IndexR討論組)
- 關注微信公眾號:數據平台小組
原文鏈接:IndexR技術白皮書
推薦閱讀:
※數據分析師可以創造什麼價值?
※如何快速學習Python
※R語言學習之簡單數據分析
※大數據VS大擁堵:大數據治理交通
※滴滴打車滴米系統的演算法?