為什麼非要把SQL放到Hadoop上? SQL易於使用。
那為什麼非得基於Hadoop呢?the robust and scalable architecture of Hadoop
目前SQL on Hadoop產品主要有以下幾種:
Hive, Tez/Stinger, Impala, Shark/Spark, Phoenix, Hawq/Greenplum, HadoopDB, Citusdata等。本文主要討論Hive, Tez/Stinger, Impala, Shark以及傳統開源資料倉儲brighthouse的特點和最新進展;下一篇文章會討論Hawq/Greenplum, Phoenix, HadoopDB, Citusdata。
在網際網路企業中一般的基於Hadoop的資料倉儲的資料來源主要有以下幾個:
1,通過Flume/Scribe/Chukwa這樣的日誌收集和分析系統把來自Apache/nginx等Server cluster的日誌收集到HDFS上,然後通過Hive建立Table時指定SerDe把非結構化的日誌資料轉化成結構化資料。
2,通過Sqoop這樣的工具把使用者和業務維度資料(一般儲存在Oracle/MySQL中)定期匯入Hive,那麼OLTP資料就有了一個用於OLAP的副本了。
3,通過ETL工具從其他外部DW資料來源裡匯入的資料。
目前所有的SQL on Hadoop產品其實都是在某個或者某些特定領域內適合的,沒有silver bullet。像當年Oracle/Teradata這樣的滿足幾乎所有企業級應用的產品在現階段是不現實的。所以每一種SQL on Hadoop產品都在儘量滿足某一類應用的特徵。
典型需求:
1, interactive query (ms~3min)
2,data analyst, reporting query (3min~20min)
3,data mining, modeling and large ETL (20 min ~ hr ~ day)
4,機器學習需求(通過MapReduce/MPI/Spark等計算模型來滿足)
Hive
Hive是目前網際網路企業中處理大資料、構建資料倉儲最常用的解決方案,甚至在很多公司部署了Hadoop叢集不是為了跑原生MapReduce程式,而全用來跑Hive SQL的查詢任務。
對於有很多data scientist和analyst的公司,會有很多相同table的查詢需求。那麼顯然每個人都從hive中查資料速度既慢又浪費資源。我們在 online的資料庫系統部署的時候都會在DB前面部署Redis或者memcache用於快取使用者經常訪問的資料。那麼OLAP應用也可以參考類似的方 法,把經常訪問的資料放到記憶體組成的叢集中供使用者查詢。
Facebook針對這一需求開發了Presto,一個把熱資料放到記憶體中供SQL查詢的系統。這個設計思路跟Impala和Stinger非常類似了。 使用Presto進行簡單查詢只需要幾百毫秒,即使是非常複雜的查詢,也只需數分鐘即可完成,它在記憶體中執行,並且不會向磁碟寫入。Facebook有超 過850名工程師每天用它來掃描超過320TB的資料,滿足了80%的ad-hoc查詢需求。
目前Hive的主要缺點:
1,data shuffle時網路瓶頸,Reduce要等Map結束才能開始,不能高效利用網路頻寬
2,一般一個SQL都會解析成多個MR job,Hadoop每次Job輸出都直接寫HDFS,效能差
3,每次執行Job都要啟動Task,花費很多時間,無法做到實時
4,由於把SQL轉化成MapReduce job時,map,shuffle和reduce所負責執行的SQL功能不同。那麼就有Map->MapReduce或者 MapReduce->Reduce這樣的需求。這樣可以降低寫HDFS的次數,從而提高效能。
目前Hive主要的改進:
1,同一條hive sql解析出的多個MR任務的合併。
由Hive解析出來的MR jobs中有非常多的Map->MapReduce型別的job,可以考慮把這個過程合併成一個MRjob。https://issues.apache.org/jira/browse/HIVE-3952
2,Hive query optimizer
http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.0.0.2/ds_Hive/optimize-joins.html
- Joins where one side fits in memory
- Star schema join的改進,就是原來一個大表和多個小表在不同column匹配的條件下join需要解析成多個map join + MR job,現在可以合併成一個MR job
這個改進方向要做的就是使用者不用給太多的hint,hive可以自己根據表的大小、行數等,自動選擇最快的join的方法(小表能裝進記憶體的話就用 map join,Map join能和其他MR job合併的就合併)。這個思路跟cost-based query optimizer有點類似了,使用者寫出來的SQL在翻譯成執行計劃之前要計算那種執行方式效率更高。
3,ORCFile
ORCFile是一種列式儲存的檔案,對於分析型應用來說列存有非常大的優勢。 http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.0.0.2/ds_Hive/orcfile.html
原來的RCFile中把每一列看成binary blob,沒有任何語義,所以只能用通用的zlib,LZO,Snappy等壓縮方法。
ORCFile能夠獲取每一列的型別(int還是string),那麼就可以使用諸如dictionary encoding, bit packing, delta encoding, run-length encoding等輕量級的壓縮技術。這種壓縮技術的優勢有兩點:一是提高壓縮率;二是能夠起到過濾無關資料的效果
現在ORCFile中主要有三種編碼:
- bit編碼,所有資料型別都可以用。Google’s protocol buffers and uses the high bit to represent whether this byte is not the last and the lower 7 bits to encode data
- run-length encoding(行程長度壓縮演算法),int型別專用。
- dictionary encoding,string型別專用。同時這個dictionary還能幫助過濾查詢中的predicate條件。
Run length Encoding對某些列壓縮會減少儲存3-4個數量級,對記憶體提升也有2-3個數量級,Dictionary Encoding一般對磁碟空間減少大概20倍,對記憶體空間大概減少5倍,根據Google PowerDrill的實驗,在常見的聚合查詢中這些特殊的編碼方式會對查詢速度有2-3個數量級的提升.
Predicate Pushdown:原來的Hive是把所有的資料都讀到記憶體中,然後再判斷哪些是符合查詢需求的。在ORCFile中資料以Stripe為單元讀取到內 存,那麼ORCFile的RecordReader會根據Stripe的後設資料(Index Data,常駐記憶體)判斷該Stripe是否滿足這個查詢的需求,如果不滿足直接略過不讀,從而節省了IO。
關於ORCFile的壓縮效果,使用情況和效能可以參考hortonworks的部落格
http://hortonworks.com/blog/orcfile-in-hdp-2-better-compression-better-performance/
未來ORCFile還會支援輕量級索引,就是每一列中以1W行作為一組的最大值和最小值。
通過對ORCFile的上述分析,我想大家已經看到了brighthouse的影子了吧。都是把列資料相應的索引、統計資料、詞典等放到記憶體中參與查詢條件的過濾,如果不符合直接略過不讀,大量節省IO。關於brighthouse大家可以參考下面的分析。
4,HiveServer2的Security和Concurrency特性
http://blog.cloudera.com/blog/2013/07/how-hiveserver2-brings-security-and-concurrency-to-apache-hive/
HiveServer2能夠支援併發客戶端(JDBC/ODBC)的訪問。
Cloudera還搞了個Sentry用於Hadoop生態系統的的安全性和授權管理方面的工作。
這兩個特點是企業級應用Hadoop/Hive主要關心的。
5,HCatalog Hadoop的統一後設資料管理平臺
目前Hive儲存的表格後設資料和HDFS儲存的表格資料之間在schema上沒有一致性保證,也就是得靠管理員來保證。目前Hive對列的改變只會修改 Hive 的後設資料,而不會改變實際資料。比如你要新增一個column,那麼你用hive命令列只是修改了了Hive後設資料,沒有修改HDFS上儲存的格式。還得 通過修改匯入HDFS的程式來改變HDFS上儲存的檔案的格式。而且還要重啟Hive解析服務,累壞了系統管理員。
- Hadoop系統目前對錶的處理是’schema on read’,有了HCatlog就可以做到EDW的’schema on write’。
- HCatlog提供REST介面提供後設資料服務,有利於不同平臺(HDFS/HBase/Oracle/MySQL)上的不同資料(unstructured/semi-structured/structured)共享。能夠把Hadoop和EDW結合起來使用。
- HCatlog對使用者解耦了schema和storage format。舉個例子吧,在寫MR任務的時候,目前是把所有的行資料都當成Text來處理,Text一點點解析出各個Column需要程式設計人員來控制。 有個HCatlog之後程式設計人員就不用管這事了,直接告訴它是哪個Database->Table,然後schema可以通過查詢HCatlog來 獲得。也省得資料儲存格式發生變化之後,原來的程式不能用的情況發生。
6,Vectorized Query Execution in Hive
https://issues.apache.org/jira/browse/HIVE-4160
- 目前Hive中一行一行的處理資料,然後呼叫lazy deserialization解析出該列的Java物件,顯然會嚴重影響效率。
- 多行資料同時讀取並處理(基本的比較或者數值計算),降低了一行一行處理中過多的函式呼叫的次數,提高了CPU利用率和cache命中率
- 需要實現基於向量的vectorized scan, filter, scalar aggregate, group-by-aggregate, hash join等基本操作單元。
Tez/Stinger
- 底層執行引擎不再使用MR,而是使用基於YARN的更加通用的DAG執行引擎
- MR是高度抽象的Map和Reduce兩個操作,而Tez則是在這兩個操作的基礎上提供了更豐富的介面。把Map具體到Input, Processor, Sort, Merge, Output,而Reduce也具體化成Input, Shuffle, Sort, Merge, Processor, Output。在MR程式裡,程式設計人員只需編寫對應的Processor邏輯,其他的是通過指定幾種具體實現來完成的;而在Tez裡面給我們更大的自由 度。其實這個跟Spark有點類似了,都是提供更豐富的可操作單元給使用者。
- 傳統的Reduce只能輸出到HDFS,而Tez的Reduce Processor能夠輸出給下一個Reduce Processor作為輸入。
- Hot table也放到記憶體中cache起來
- Tez service:預啟動container和container重用,降低了每次Query執行計劃生成之後Task啟動的時間,從而提高實時性。
- Tez本身只是YARN框架下得一個library,無需部署。只需指定mapreduce.framework.name=yarn-tez
http://dongxicheng.org/mapreduce-nextgen/apache-tez-newest-progress/
未來工作方向:
Cost-based optimizer,基於統計選擇執行策略,多表JOIN時按照怎樣的順序執行效率最高。
統計執行過程中每個中間表的Row/Column等數目,從而決定啟動多少個MR執行
Impala
Impala可以看成是Google Dremel架構和MPP (Massively Parallel Processing)結構的混合體。
https://github.com/cloudera/impala
Dremel論文: http://research.google.com/pubs/pub36632.html
優點:
- 目前支援兩種型別的JOIN:broadcast join和partition join。對於大表JOIN時由於記憶體限制,裝不下時就要dump部分資料到磁碟,那樣就會比較慢
- Parguet列存格式,同時能夠處理巢狀資料。通過巢狀資料以及擴充套件的SQL查詢語義,在某些特定的場景上避開了JOIN從而解決了一部分效能的bottleneck。
- Cloudera Manager 4.6以後會有slow query的分析功能
- Runtime Code Generation http://blog.cloudera.com/blog/2013/02/inside-cloudera-impala-runtime-code-generation/
- impala可以直接使用硬碟上的資料而不經過hdfs
缺點:
- impala不會按照group by的列排序
- 目前不支援UDF,impala 1.2即將支援Hive UDFs(Java寫的)和Impala native UDFs and UDAs(介面類似PosgreSQL)
- 不支援像Hive的Serializer/Deserializer,從而使得它做從非結構化到結構化資料的ETL工作比較麻煩。
- 不支援線上查詢容錯,如果參與查詢的某個node出錯,Impala將會丟棄本次查詢。
- 安全方面的支援還比較差。impalad之間傳輸的資料沒有加密,不支援表或者列級別的授權。
- 每個PlanFragment執行儘量並行化,但是有的時候並不是很容易。例如Hash Join需要等到其中一個表完全Scan結束才能開始。
不過雖然有這麼多缺點,但是很多公司還是開始嘗試Impala了。以百度為例,百度嘗試把MySQL接入Impala的後端作為儲存引擎,同時實現 相應操作對應的PlanFragment,那麼使用者來的query還是按照原來的解析方法解析成各種PlanFragment,然後直接排程到對應的節點 (HDFS DataNode/HBase RegionServer/MySQL)上執行。會把某些源資料或者中間資料放到MySQL中,使用者的query涉及到使用這部分資料時直接去MySQL 裡面拿。
Shark/Spark
由於資料能放到記憶體儘量放到記憶體,使用記憶體非常aggressive。優點是做JOIN時會比較快,缺點是佔用記憶體太大,且自行管理記憶體,佔用記憶體後不會釋放。
支援UDF
效能:
特別簡單的select…where查詢,shark效能的提升不明顯。(因為hive也不怎麼費時間)
但是如果查詢比較複雜select…join…where…group by,hive的job數目會比較多,讀寫HDFS次數增多,時間自然會變長。當記憶體還足夠大的時候shark效能是最好的,如果記憶體不夠裝下所有的資料時效能會下降,但還是會比Hive好很多。
SQL on Hadoop產品需要向傳統資料倉儲學習的地方
以開源資料倉儲brighthouse(基於MySQL的資料倉儲儲存引擎)為例。
VLDB 2008 論文 <<Brighthouse: An Analytic Data Warehouse for Ad-hoc Queries>>
brighthouse的SQL解析用的是MySQL的程式碼,開發了brighthouse專用的optimizer,executor以及storage engine
brighthouse的資料儲存通過三層來組織:Data Pack, Data Pack Node, Knowledge Node
- DP(Data Pack):brighthouse是列儲存的,每個DP儲存一列中64K個單元的資料。
- DPN(Data Pack Node):DPN和DP是一對一的關係,DPN中記錄每個DP資料對應的一些統計值(max,min,count,sum)
- KN(Knowledge Node):DP的更詳細的資料資訊和DP之間關係的資訊
KN又分為一下三個部分:
- HISTs(Histograms):數值型別列的統計直方圖,能夠快速判斷這個DP是否符合查詢條件。
- CMAPs(Character Maps):文字型別的點陣圖,用於快速查詢字元。(優化關鍵字like)
- Pack-To-Pack:等值JOIN操作時產生的兩個列(DP)之間關係的點陣圖。
DPN和KN相當於DP的一些統計資訊,佔整個DP的1%的儲存空間,所以可以輕鬆裝入記憶體。他們是為了快速定位哪些DP是跟這個query相關 (relevant)的,哪些是不相關(irrelevant)的,哪些是可能相關(suspect)的。從而減小IO讀取的資料量,提高效能。
效能測試:http://www.fuchaoqun.com/tag/brighthouse/
從這個效能測試中可以看出:
1,壓縮率:infobright比MyISAM/tar.gz的壓縮率都要高很多
2,查詢效能:跟建了索引的MyISAM表相比,查詢速度也要快3-6倍
總之,大家都缺少的是:
1,workload management or query optimization
多個表的JOIN如何執行,例如3個表的JOIN會有6種執行策略,那麼哪一種才是效率最高的呢。顯然要通過計算每種執行順序的開銷來獲得。在傳統資料庫 或者資料倉儲領域(Oracle/Teradata/PostgreSQL)都有非常好的查詢優化器,而在分散式系統中該如何衡量這些指標(磁碟IO,網 絡頻寬,記憶體)與最後查詢效率之間的關係是個需要認真研究的問題。
2,關聯子查詢correlated sub-queries還是沒有誰能夠實現。
在TPC-H中又很多關聯子查詢的例子,但是現在的SQL on Hadoop產品都不支援。聽Impala的人說,他們客戶對這個的需求不是很強烈,大部分關聯子查詢可以轉化成JOIN操作。但是目前的商業產品像Hawq/Greenplum都是支援關聯子查詢的。