1. 概述
Spark是基於內存計算的通用大數據並行計算框架,內置多種組件,如批處理、流處理、機器學習和圖處理。Hive是基於Hadoop的數據倉庫,支持類SQL的命令查詢,提高了Hadoop的易用性。Spark與Hive、Hadoop一般是搭配使用,利用Hive中的數據分區能夠方便地管理和過濾數據,提升查詢效率。算法
DolphinDB是C++編寫的高性能分佈式時序數據庫,內置高吞吐低延遲的列式內存引擎,集成了功能強大的編程語言,支持類Python和SQL的腳本語言,能夠直接在數據庫中進行復雜的編程和運算。DolphinDB內部用Data Source來抽象分區數據。在Data Source之上,能夠完成SQL,機器學習,批處理和流處理等計算任務。一個Data Source既能夠是內置的數據庫分區,也能夠是外部數據。若是Data Source是內置數據庫的分區,大部分計算均可以在本地完成,極大地提高了計算和查詢效率。數據庫
本報告將對DolphinDB、Spark直接訪問HDFS(Spark+Hadoop,下文稱爲Spark)、Spark經過Hive組件訪問HDFS(Spark+Hive+Hadoop,下文稱爲Spark+Hive)三者進行性能對比測試。測試內容包括數據導入、磁盤空間佔用、數據查詢以及多用戶併發查詢。經過對比測試,咱們能更深刻的瞭解影響性能的主要因素,以及不一樣工具的最佳應用場景。編程
2. 環境配置
2.1 硬件配置緩存
本次測試使用了兩臺配置徹底相同的服務器(機器1,機器2),各個配置參數以下:服務器
主機:DELL PowerEdge R730xd網絡
CPU:Intel Xeon(R) CPU E5-2650 v4(24核 48線程 2.20GHz)併發
內存:512 GB (32GB × 16, 2666 MHz)app
硬盤:17T HDD (1.7T × 10, 222 MB/s 讀取;210 MB/s 寫入)框架
網絡:萬兆以太網機器學習
OS: CentOS Linux release 7.6.1810 (Core)
2.2 集羣配置
測試的DolphinDB版本爲Linux v0.95。測試集羣的控制節點部署在機器1上,每臺機器上各部署三個數據節點,共六個數據節點。每一個數據節點配置8個worker,7個executor,24G內存。
測試的Spark版本爲2.3.3,搭載Apache Hadoop 2.9.0。Hadoop與Spark配置爲徹底分佈式模式,機器1爲Master,而且在機器一、機器2上都具備Slave。Hive的版本是1.2.2,機器一、機器2上都具備Hive。元數據存儲在機器1上的MySql數據庫中。Spark 與Spark + Hive使用Standalone模式下的client 方式來提交應用。
測試時,DolphinDB、Spark、Spark+Hive均配置6塊硬盤,不一樣併發數下使用的CPU、內存總和都相同,都是48個線程,144G內存。Spark與Spark+Hive使用的資源只是對於特定的應用,每一個應用有6個executor,在多用戶併發的狀況下,Spark、Spark+Hive單個用戶使用的資源會隨着用戶數量增多而減小。不一樣併發數下每一個用戶使用的資源如表1所示。
表1.Spark、Spark+Hive不一樣併發數下單用戶使用的資源
3. 數據集及數據庫設計
3.1 數據集
測試數據集是紐約證券交易所(NYSE)提供的TAQ數據集,包含 8000 多支股票在2007.08.01-2007.08.31一個月內的Level 1報價數據,包含交易時間, 股票代碼, 買入價, 賣出價, 買入量, 賣出量等報價信息。數據集中共有 65 億(6,561,693,704)條報價記錄,一個 CSV 中保存一個交易日的記錄,該月共23個交易日,未壓縮的 23個CSV 文件共計 277 GB。
數據來源:https://www.nyse.com/market-data/historical
3.2 數據庫設計
表2. TAQ在各個系統中的數據類型。
在 DolphinDB database 中,咱們按照date、symbol列組合分區,第一分區使用日期DATE來進行值分區,共23個分區,第二分區使用股票代碼SYMBOL來進行範圍分區,分區數量100個,每一個分區大約120M左右。
Spark存儲在HDFS上的數據以23個csv對應23個目錄。Spark+Hive採用兩層分區,第一層分區使用日期DATE列進行靜態分區,第二層分區使用股票代碼SYMBOL進行動態分區。
具體腳本見附錄。
4. 數據導入和查詢測試
4.1 數據導入測試
原始數據均勻地分佈在兩臺服務器的6個硬盤上,這樣能夠充分利用集羣中的全部資源。DolphinDB經過異步多節點的方式並行導入數據,Spark與Spark+Hive並行啓動6個應用來讀取數據,把數據存儲到HDFS中。各個系統導入數據的時間如表3所示。各個系統中數據佔用的磁盤空間如表4所示。數據導入腳本見附錄。
表3. DolphinDB、Spark、Spark+Hive導入數據時間
表4. DolphinDB、Spark、Spark+Hive中數據佔用的磁盤空間
DolphinDB的導入性能明顯優於Spark和Spark+Hive,是Spark的4倍左右,是Spark + Hive的6倍左右。DolphinDB使用C++編寫而且內部有不少優化,極大地利用了磁盤的IO。
DolphinDB佔用的磁盤空間大於Spark與Spark+Hive,大約是他們的2倍,這是由於Spark和Spark+Hive在Hadoop上都使用Parquet格式,Parquet格式經過Spark寫入到Hadoop上默認使用snappy壓縮。
4.2 數據查詢測試
爲保證測試公平,每一個查詢語句要進行屢次測試,每次測試以前均經過 Linux 系統命令分別清除系統的頁面緩存、目錄項緩存和硬盤緩存。DolphinDB還清除其內置緩存。
表5中的查詢語句涵蓋了大部分查詢場景,包含分組、排序、條件、聚合計算、點查詢、全表查詢,用來評估DolphinDB、Spark、Spark+Hive在不一樣用戶數量提交下的性能。
表5. DolphinDB、Spark、Spark+Hive查詢語句
4.2.1 DolphinDB與Spark單用戶查詢測試
如下是DolphinDB與Spark單用戶查詢的結果,結果中的耗時爲查詢8次的平均用時。
表6. DolphinDB、Spark單用戶查詢結果
從結果能夠看出,DolphinDB的查詢性能是Spark+HDFS的200倍左右。查詢Q1到Q6都是以DolphinDB的分區字段爲過濾條件,DolphinDB只須要加載指定分區的數據,無需全表掃描,而Spark從Q1到Q6都須要全表掃描,耗費大量的時間。對於查詢Q7,DolphinDB和Spark都須要全表掃描,可是DolphinDB只加載相關的列,無需加載全部列,而Spark則須要加載全部數據。因爲Query運行時間被數據加載主導,DolphinDB和Spark的性能差距沒有以前的查詢語句的大。
4.2.2 DolphinDB與Spark+Hive單用戶查詢測試
因爲DolphinDB的數據通過分區,且在查詢的時候實現謂詞下推,效率明顯高於Spark。此處咱們使用Spark搭載Hive組件來訪問HDFS,對比DolphinDB和Spark+Hive的查詢性能。如下是DolphinDB、Spark+Hive單用戶查詢的結果,結果中的耗時爲查詢8次的平均用時。
表7. DolphinDB、Spark+Hive單用戶查詢結果
結果顯示,DolphinDB的查詢性能明顯優於Spark+Hive,是Spark+Hive的數十倍。與表6的結果相比,Spark+Hive的查詢速度比Spark要快得多,DolphinDB具備的優點明顯降低了不少。這是由於Hive對數據進行分區,且在查詢語句的條件帶有分區字段的時候,只加載部分數據,實現數據過濾,提升效率。查詢語句Q7掃描全表的時候會出現內存溢出。
DolphinDB、Spark+Hive都對數據進行了分區,且在加載數據時均可以實現謂詞下推,達到數據過濾的效果,可是DolphinDB的查詢速度優於Spark+Hive。這是由於Spark+Hive區讀取HDFS上的數據是不一樣系統之間的訪問,數據要通過序列化、網絡傳輸、反序列化的過程,很是耗時,從而影響性能。DolphinDB的大部分計算都在本地完成,減小了數據傳輸,所以更加高效。
4.2.3 DolphinDB與Spark計算能力對比
上面DolphinDB分別與Spark、Spark+Hive的查詢性能對比,因爲數據分區、查詢時的數據過濾以及傳輸影響了Spark的性能,所以這裏咱們先把數據加載到內存中,再進行相關的計算,比較DolphinDB和Spark+Hive。咱們省略了Spark+Hive,由於使用Hive只是爲了數據過濾,讀取HDFS上的數據更加高效,這裏的測試數據已經在內存中。
表8是測試計算能力的語句。每次測試都包含兩個語句,第一個語句是把數據加載到內存中,第二個語句是對內存中的數據進行計算。DolphinDB會自動緩存數據,Spark則經過本身的默認緩存機制從新建立一個臨時表TmpTbl。
表8. DolphinDB與Spark計算能力對比語句
如下是DolphinDB與Spark計算能力的測試結果,結果中的耗時是測試5次的平均用時。
表9. DolphinDB與Spark計算能力測試結果
因爲數據已經在內存中,對比表6,Spark使用的時間大幅度減小,可是DolphinDB的計算能力仍然比Spark優越。DolphinDB用C++編寫,本身管理內存,比起Spark使用JVM來管理內存更加高效。另外,DolphinDB內置了更高效的算法,提升了計算性能。
DolphinDB的分佈式計算以分區爲單位,計算指定內存的數據。Spark加載整個HDFS上的塊,一個數據塊包含了具備不一樣symbol值的數據,雖然緩存,可是仍然要篩選,因此在Q1與Q2的比值較大。Spark計算時使用的廣播變量是通過壓縮的,傳輸到其餘的executor上再解壓影響性能。
4.2.4 多用戶併發查詢
咱們使用表5中的查詢語句,對DolphinDB、Spark、Spark+Hive進行多用戶併發查詢測試。如下是測試結果,結果中的耗時是查詢8次的平均用時。
表10. DolphinDB、Spark、Spark+Hive多用戶併發查詢結果
圖1. DolphinDB、Spark多用戶查詢結果對比
圖2. DolphinDB、Spark+Hive多用戶查詢結果對比
從上面的結果能夠看出,隨着併發數量的增長,三者的查詢時間逐漸增長。當達到8個用戶併發的時候Spark性能較以前少許的用戶併發狀況下顯著降低,Spark 在執行Q7的時候會致使worker死亡。Spark+ Hive在多用戶訪問的時候與DolphinDB同樣,基本保持穩定,可是執行Q7查詢語句的一直會出現內存溢出的異常。
Spark+ Hive的查詢配置與Spark 同樣,由於有分區的做用,而且能夠過濾數據,查詢數據量比較小,因此效率相對於Spark掃描所有數據比較好。
DolphinDB在併發查詢中性能明顯優於Spark 與Spark+ Hive,從上圖能夠看出在多用戶併發訪問狀況下,隨着用戶數量的增長,DolphinDB相對於Spark 的優點幾乎是線性增加,相對於Spark + Hive 的優點基本保持不變,體現了有數據分區在查詢的時候實現數據過濾的重要性。
DolphinDB在多用戶併發的狀況下實現了多用戶的數據共享,不像Spark 的數據只是針對於具體的應用。因此在8個併發用戶的狀況下,Spark 每一個用戶分配到的資源比較少,性能顯著降低。DolphinDB的數據共享能夠減小資源的使用,在有限的資源下,把更多的資源留給用戶計算使用,提升用戶併發的效率,增大用戶的併發數量。
5. 小結
在數據的導入方面,DolphinDB能夠並行加載,Spark與Spark+Hive 則經過多個應用同時加載來導入數據。DolphinDB的導入速度是Spark 和Spark+ Hive 的4-6倍。在磁盤空間上,DolphinDB佔用的磁盤空間是Spark與Spark+ Hive在Hadoop上佔用的磁盤空間的兩倍左右,Spark與Spark + Hive使用了snappy壓縮。
在數據的SQL查詢方面,DolphinDB的優點更加明顯。優點主要來自四個方面:(1)本地化計算,(2)分區過濾,(3)優化的內存計算,(4)跨會話的數據共享。在單用戶查詢狀況下,DolphinDB的查詢速度是Spark的幾倍到上百倍,是Spark+ Hive 的幾十倍。Spark 讀取HDFS 是不一樣的系統之間的調用,其中包含了數據的序列化,網絡,反序列化很是消耗時間,且佔據不少的資源。DolphinDB的SQL查詢大部分是本地化計算,大幅減小了數據傳輸和加載的時間。Spark+ Hive 相對與Spark速度提高很大,主要是由於Spark + Hive只掃描相關分區的數據,實現了數據的過濾。在剔除本地化和分區過濾的因素後(即全部數據已經在內存中),DolphinDB的計算能力仍然優於Spark數倍。DolphinDB基於分區的分佈式計算效率很高,且對內存的管理比Spark基於JVM的管理更加優秀。Spark的多用戶併發會隨着用戶數量的增多效率逐漸降低,在查詢大數據量的時候用戶過多致使worker 死亡。Spark + Hive的多用戶併發相對比較穩定,可是加載數據過大會出現內存溢出錯誤。 多用戶狀況下, DolphinDB能夠實現數據的共享,從而減小加載數據使用的資源,查詢速度是Spark的數百倍,是Spark+Hive 的幾十倍。隨着用戶數量的增長,DolphinDB相對於Spark的性能優點更加明顯。涉及到分區查詢的狀況下,Spark+ Hive與DolphinDB顯著提升查詢性能。
Spark是一個很是優秀的通用分佈式計算引擎,在SQL查詢、批處理、流處理、機器學習等方面均有上佳表現。但因爲SQL查詢一般只須要對數據計算一次,相對於機器學習須要上百次的迭代,內存計算的優點沒法充分體現。所以,咱們更建議將Spark用於計算密集型的機器學習。
在測試過程當中,咱們也發現DolphinDB是一個很是輕量級的實現,集羣的搭建簡單快速, Spark + Hive+ Hadoop 集羣安裝配置很是複雜。
附錄
附錄1. 數據預覽
附錄2. Hive建立表語句
CREATE TABLE IF NOT EXISTS TAQ (time TIMESTAMP, bid DOUBLE, ofr DOUBLE, bidsiz INT, ofrsiz INT, mode INT, ex TINYINT, mmid STRING)PARTITIONED BY (date DATE, symbol STRING) STORED AS PARQUET;
附錄3.
DolphinDB導入數據腳本:
fps一、fps2分別表明機器一、2上全部的csv路徑的vector fps是包含fps1和fps2 的vector allSites一、allSites2 分別表明機器一、2上數據節點名稱的vector allSite 是包含 allSites1和allSites2的vector DATE_RANGE=2007.07.01..2007.09.01 date_schema=database('', VALUE, DATE_RANGE) symbol_schema=database('', RANGE, buckets) db=database(FP_DB, COMPO,[date_schema,symbol_schema]) taq = db.createPartitionedTable(schema, `taq, `date`symbol) for(i in 0..1){ for(j in 0..(size(fps[i])-1)) { rpc(allSites[i][j] % size(allSite[i])],submitJob,"loadData" , "loadData" ,loadTextEx{database(FP_DB), "taq", `date`symbol, fps[i][j]} ) } }
Spark與Hive導入數據的配置:
--master local[8] --executor-memory 24G