一、Doris演進史


Apache Doris —— 為分析而生

Doris發展歷程: Doris發展比較重要的關鍵節點與事件

 

#2008 - Doris1 :「築巢引鳳」的重要基石 


    早年,百度最主要的收入來源是廣告。廣告主需要通過報表服務來查看廣告的展現、點擊、消費等信息,並且能夠需要通過不同維度來獲得廣告的消費情況,用以指導后續的廣告的投放策略。

在Doris1誕生之前,百度使用 MySQL Sharding 方式來為廣告主提供廣告報表支持。隨着百度本身流量的增加,廣告流量也隨之增加,已有的 MySQL Sharding 方案變得不再能夠滿足業務的需求。主要體現在以下幾個方面: 

  • 第一,大規模數據導入會導致 MySQL 的讀性能大幅降低,甚至還有鎖表情況,在密集導入數據的情況下尤為明顯。同時在數據導入時,MySQL的查詢性能大幅下降,導致頁面打開很緩慢或者超時,用戶體驗很差;
  • 第二,MySQL在大查詢方面性能很差,因此只能從產品層面來限制用戶的查詢時間范圍,用戶體驗很差;
  • 第三,MySQL對數據量的支持是有限的。單表存儲的數據有限,如果過大,查詢就會變慢。對此的解決方案只有拆表、拆庫、遷移數據。隨着數據量的快速增長,已經無法維護。

當時數據存儲和計算成熟的開源產品很少,Hbase的導入性能只有大約2000條/秒,不能滿足業務每小時新增的要求。而業務還在不斷增長,來自業務的壓力越來越大。在這種情況下,Doris1誕生了,並且在2008年10月份跟隨百度鳳巢系統一起正式上線。

  •  

Doris1的主要架構如上圖所示。數據仍然通過用戶 ID 進行 Hash,將同一個用戶ID的數據交由一台機器處理。其中: 

  • Hm-Storage負責數據的存儲。
  • ODP、OMG負責將業務數據導入到Hm-Storage中。
  • AS負責解析、規划查詢請求,並將查詢請求發給Hm-Storage處理,並對Hm-Storage返回的數據進行一些業務相關的計算后將查詢結果返回給用戶。

相比於MySQL的方案,Doris1主要在如下幾個方面進行了改進

  • 首先,Doris1的數據模型將數據分為Key列,Value列。比如一條數據的Key列包括:用戶ID、時間、地域、來源等等,value列包括:展現次數、點擊次數、消費額等。這樣的數據模型下,所有Key列相同的數據Value列能夠進行聚合,比如數據的時間維度最細粒度為小時,那同一小時多次導入的數據是能夠被合並成一條的。這樣對於同樣的查詢來說,Doris1需要掃描的數據條目相比MySQL就會降低很多。
  • 其次,Doris1將 MySQL 逐條插入改成了批量更新,並且在通過外圍模塊將同一批次數據進行排序以及預聚合。這樣一個批次中相同Key的數據能夠被預先聚合,另外排序后的數據能夠在查詢的時候起到聚集索引的作用,提升查詢時候的性能.
  • 最后,Doris1提供了天表、月表這種類似物化視圖的功能。比如用戶是想將數據按天進行匯聚展現,那么對於這種查詢是可以通過天表來滿足的。而天表相對於小時表數據量會小幾倍,響應的查詢性能也會提升幾倍。

通過Doris1的工作,完全解決了MySQL Sharding遇到的問題。並於2008年10月於鳳巢系統一起上線,完美的支撐了廣告統計報表需求。

 

#2009 - Doris2:解「百度統計」燃眉之急 


   2008年的百度統計服務大約有50-60台MySQL,但是業務每天有3000萬+條增量數據,由於MySQL的存儲和查詢性能無法滿足需求,對存量數據的支撐已經到了極限,問題頻出,萬般無奈之下百度統計甚至關閉了新增用戶的功能,以減少數據量的增加。

   Doris1由於當時時間緊、任務重,所以設計、實現的時候只為了能夠滿足鳳巢的業務需求,並沒有兼顧其他的應用需求。由於Doris1方案對於鳳巢成功的支持,百度統計同學開始基於Doris1打造Doris2系統,主要將Doris1進行通用化改造,包括支持自定義schema等,使Doris能夠應用於其他產品。此外還進行一些優化以此來提升系統的查詢、存儲性能。

   2009年Doris2研發完成后上線百度統計,並且成功支撐百度統計后續的快速增長,成功的助力百度統計成為當時國內規模最大,性能、功能最強的統計平台。由於在鳳巢、百度統計上的成功,公司內部后續其他類似統計報表類的需求也都由Doris2進行支持,比如網盟、聯盟等報表服務。

 

#2010 - Doris3: 讓查詢再快一點 


  百度在2009-2011年發展迅猛,營收每年近100%的速度增長,與之相伴的是廣告數據量也隨之大幅增長。隨着業務數據量的不斷增長,Doris2系統的問題也逐漸成為業務發展的瓶頸。

  • 首先體現在Doris2無法滿足業務的查詢性能需求,主要是對於長時間跨度的查詢請求、以及大客戶的查詢請求。這是因為Doris2通過規則將全部數據按照用戶ID進行Sharding,這雖然能夠將全部數據分散到多台機器上,但是對於單一用戶的數據還是全部落在一台機器上。隨着單用戶數據量增多,一些查詢請求無法快速計算得到結果。
  • 其次,Doris2在日常運維方面基本上都需要停服后手動操作,比如 Schema Change、集群擴縮容等,一方面用戶體驗很差,一方面還會增加集群運維的成本。
  • 最后,Doris2本身並不是高可用系統,機器故障等問題還是會影響服務的穩定性,並且需要人肉進行復雜的操作來恢復服務。

   為了解決Doris2的問題,團隊開始了Doris3的設計研發。Doris3的主要架構如下圖所示,其中:

 

  • DT(Data Transfer)負責數據導入
  • DS(Data Seacher)模塊負責數據查詢
  • DM(Data Master)模塊負責集群元數據管理,數據則存儲在Armor分布式Key-Value引擎中。

   Doris3依賴ZooKeeper存儲元數據,從而其他模塊依賴ZooKeeper做到了無狀態,進而整個系統能夠做到無故障單點。

   在數據分布方面Doris3引入了分區的概念。首先數據會按照時間進行分區(比如天分區、月分區);在同一個分區里,數據會根據用戶ID再進行Sharding。這樣同一個用戶的數據會落在不同的分區上,而在查詢時多台機器就能夠同時處理一個用戶的數據了,實現了單用戶的分布式計算能力。但是可能還會存在一個分區內部單個用戶數據量過大的情況。對於這種情況Doris3設計了后續表功能,會將單個分區內大用戶的數據進行拆分,導入到多個分片中,這樣能夠保證每個分片內單個用戶的數據總量最高是有限度的。

   另外Doris3在日常運維Schema Change,以及擴容、縮容等方面都做了針對性設計,使其能夠自動化進行,不依賴線上人工操作。

   在當時,由於種種原因,Doris3最終確定使用了Armor來作為底層存儲系統。Armor是一款分布式Key-Value系統,支持多副本強一致,且單表內全Key有序。選用Armor作為底層存儲能夠使Doris3只負責管理分片,而分片的副本,以及副本的一致性都由Armor來處理。並且,集群的擴、縮容等操作也只需要Armor感知即可,Doris3本身並不需要感知。當然除了這些好處外,這樣的選型也有一些弊端。

   由於Armor是一個通用的Key-Value系統,並不感知上層的業務數據,它並不支持Doris這種數據模型,既相同Key的數據,Value字段是可以進行聚合的。比如數據導入的批次是五分鍾一批,但是數據時間粒度是小時,那么其實一個小時的數據可能是多次導入的,但是邏輯上是可以合並成一條數據的。所以為了實現這個功能,只能是Doris3自身實現了較為復雜的數據合並策略來完成相關數據的合並。

  Doris3在2011年完成開發后逐漸替換Doris2所制成的業務,並且成功的解決了大客戶查詢的問題。而公司內部后續的新需求,也都由Doris3來承擔支持。

 

#2012 - MySQL + Doris3: 百度的第一個OLAP平台 


   2012年隨着Doris3逐步遷移Doris2的同時,大數據時代悄然到來。在公司內部,隨着百度業務的發展,各個業務端需要更加靈活的方式來分析已有的數據。而此時的Doris3仍然只支持單表的統計分析查詢,還不能夠滿足業務進行多維分析的需求。由於缺少通用的SQL支持,Doris3在面對更加靈活的多維分析場景時有點力不從心。當時,公司內只有Hive以及類似系統支持大數據量的SQL查詢,但是他們均是面向解決離線分析場景,而在線多維分析領域缺少一款產品來滿足業務方的需求。

  所以,為了能夠支持業務的多維分析需求,Doris3采用了 MySQL Storage Handler 的方式來進行擴展。通過此種方式,將 Doris3 偽裝成一個MySQL的存儲后端,類似於MyISAM、InnoDB一樣。這樣既能夠利用上MySQL對於SQL的支持,也能利用上Doris3對於大數據量的支持。由於這里MySQL是計算單點,為了減輕MySQL的計算壓力,Doris3應用了MySQL的BKA(Batched Key Access)以及MRR(Multi-Range Read)等機制盡量的將計算下推到Doris3來完成,從而減輕MySQL的計算壓力。

  •  

通過 MySQL + Doris3 這個方案,百度Insight團隊為PS、LBS、WISE等產品線提供了百度內部第一個OLAP分析服務平台。

 

#2012 - OLAP Engine:突破底層存儲束縛 


 另一方面Doris3支持報表分析場景時,底層通用 Key-Value 存儲引擎的弊端也逐漸顯露。作為一個通用 Key-Value 存儲引擎,在支持報表引擎方面暴露了一些問題。

  • 第一,由於Key-Value系統讀取只能夠讀取全Key,全Value,而報表分析系統中的大部分查詢並不需要讀取所有列,這樣會帶來不必要的IO開銷;
  • 第二,正如前文所說,由於引擎本身不感知業務模型,不能夠再進行Merge的同時完成數據的合並,這需要Doris3借助復雜的作業管理在引擎外部完成Merge工作既不簡潔,也不高效;
  • 第三,為了保證業務的導入原子性,Doris3為每批次導入都賦值一個版本號,並記錄在每條數據Key的最后部分。這樣在查詢的時候,需要對每條數據進行Key的解析,比較版本號,過濾掉不需要的版本。這樣一方面需要讀取無需讀取的數據,一方面需要解析所有Key,從而帶來不必要的CPU開銷;
  • 第四,Key-Value系統無法感知數據內容,只能使用通用壓縮算法,進而導致數據的壓縮效率不高。這樣在查詢、讀取時都會帶來較多的IO負載。

為了能夠在底層存儲引擎上有所突破,OLAP Engine項目啟動了。這個項目的發起者是當時從Google來的高T,為百度帶來了當時業界最領先的底層報表引擎技術。OLAP Engine最大的特點包括以下幾點。

  • 第一,引擎端原生就支持Schema,並且所有的列分為Key列,Value列。這樣就能夠跟上層的業務模型能夠對應上,查詢部分列時,無需加載全部列,減少不必要的IO開銷。
  • 第二,獨特的數據模型。Value列支持聚合操作,包括SUM、MIN、MAX等。在Key列相同的情況下,Value列就能夠按照聚合操作類型完成對應的聚合操作。而引擎本身導入方式類似於LSM Tree,這樣在引擎后台進行Merge的同時,就能夠將相同Key的數據中的Value字段按照對應的操作進行聚合。這樣就無需外部再進行數據合並作業管理,將引擎層與業務層合並合二為一,省去不必要的IO、CPU開銷。
  • 第三,數據批量導入,原子生效。對於每個批次的導入,都會有個 Delta 文件對應,並且會有個版本號。在查詢的時候只是在初始化的時候來確定讀取哪個文件,這樣就只會讀取生效版本的數據,而不會讀取沒有生效版本的數據,更不會浪費CPU來進行版本號比較過濾。
  • 第四,行列式存儲。多行(比如1024行)數據存儲在一個Block內,Block內相同列的數據一同壓縮存放,這樣可以根據數據特征利用不同的壓縮算法(比如對於時間字段使用RLE等)大幅提高數據壓縮效率。

 即使分布式層沒有采用復雜的分布式管理,只是使用類似 Doris2 的用戶ID Sharding方式,OLAP Engine后續也成功的支持了鳳巢,網盟等廣告業務。這充分的能夠體現OLAP Engine強大的報表分析能力。雖然OLAP Engine取得了成功,但是由於硬Sharding方案帶來的不易運維、不易擴展等問題仍然存在。

 

#2013 - 用PALO:玩轉OLAP 


   底層技術的發展會激發上層業務的需求,而上層業務的需求同時會為底層的技術帶來新的挑戰。隨着第一款OLAP產品的問世,數據分析師們的建模就更加復雜,有時查詢SQL會有上千行,人為閱讀已經相當吃力。而MySQL + Doris3方案的弊端也就越發突顯。因為分析SQL越來越復雜,大量的計算都需要在MySQL中完成,這樣MySQL的計算能力就成為整個系統的性能瓶頸,突破這個性能瓶頸也就變得極為緊迫。

  因此Doris亟需一款擁有分布式計算能力的查詢引擎。幸運的是當時(2013年)各種SQL on Hadoop項目也正蓬勃發展,比如Impala,Tajo,Presto等等。在有限的時間內並不充分調研的情況下,團隊選取了Impala作為了后續系統的分布式查詢引擎。當時的選擇Impala主要的原因是因為其性能較高,並且BE的C++語言跟我們已有系統的語言一致,未來可以省去一部分序列化開銷。

  由於MySQL + Doris3的方案制約了業務的使用,當時公司的另一個團隊邀請了Oracle的Exadata進行POC,這給了Doris團隊很大的壓力。如果Doris想繼續在OLAP領域繼續發展,就需要快速的產出原型,並且性能上還要勝出Exadata。為了快速的驗證方案的可行性,團隊幾個月內就把Impala與Doris3進行了集成,並用TPC-H進行了測試,結果是Impala + Doris3性能比Exadata更好。這次原型的成功為我們贏得了一次機會,能夠讓團隊繼續改造Doris3從而更好的支持OLAP場景。

新產品的名字命名為PALO,意為玩轉OLAP。

  PALO1除了增加分布式查詢層之外,因為OLAP Engine在統計報表領域的成功,PALO1放棄了Doris3依賴的通用Key-Value系統,選擇了OLAP Engine作為自己的單機引擎。因為沒有了分布式Key-Value系統,那么PALO1自己完成數據分片管理、副本管理等工作。

PALO1的架構如下所示。

  •  

     

其中DM負責管理元數據、數據的分布、分片副本管理等內容,DM本身沒有狀態,元數據內容都存儲在MySQL中。FE負責接收用戶的查詢請求,並且進行查詢規划解析。BE是負責存儲數據,以及進行具體的查詢執行。

隨着PALO1的正式上線,除了遷移所有Doris3已有的的業務外,也成功支持了當時百度內部大部分的OLAP分析場景。

 

#2015 - PALO 2:讓架構再簡單一點 


    如果說PALO1是為了解決性能問題,那么PALO2主要是為了在架構上進行優化。由於PALO1模塊數目較多,並且外部依賴MySQL,這其實還是增加了運維的壓力的。所以我們在PALO2項目中力求將系統的架構進行簡化。經過簡化后的系統架構如下圖所示。

PALO2中我們只存在2種模塊:FE、BE。

  • FE一方面負責管理、存儲元數據,另一方面FE還負責與用戶交互,接受用戶查詢,對查詢規划,監督查詢執行,並將查詢結果返回給用戶。
  • FE本身是有狀態的,但是它內部通過BDB JE,能夠將元數據進行多副本復制,從而能夠保證服務的高可用。
  • BE與PALO1功能一致,只是PALO2的BE包含了存儲引擎,一方面減少了一個模塊,並且在用戶查詢的時候少了一次數據的序列化、反序列化操作,節約CPU消耗。

通過PALO2的工作,系統架構本身變得相當簡潔,並且不需要任何依賴。因為PALO2架構的簡潔,我們后續也相對容易的基於PALO2提供了公有雲服務以及私有化部署;另一方面,當PALO開源之后其他用戶也能夠用通過較低的門檻來搭建使用PALO 。在此之后PALO雖然經過幾次改進,但是整體架構仍然保持PALO2的架構。

 

#2017 and Future:Apache Doris (incubating) ,是更廣闊的世界 


   PALO2在百度內部基本服務了所有的統計報表、多維分析需求,我們相信它一定可以應用到其他公司,能夠幫助更多的人更加高效、方便的支持類似的業務需求。因此,我們選擇了開源,PALO於2017年正式在GitHub上開源,並且在2018年貢獻給Apache社區,並將名字改為Apache    Doris(incubating)進行正式孵化。貢獻給Apache之后,Doris就不僅僅是百度的項目,而成為了Apache的項目。

隨着開源,Doris已經在京東、美團、搜狐、小米等公司的生產環境中正式使用,也有越來越多的Contributor加入到Doris大家庭中。一路走來,Doris從未懼怕過挑戰,也從未被困難擊倒。時至今日,Doris已經站在了更高的舞台上,准備擁抱更多的機遇與挑戰。 

 

參考資料

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM