IndexR


IndexR是由舜飛科技研發的實時OLAP系統。於 2017 年 1 月初正式開源,目前已經更新至 0.6.1 版本,其作者認為IndexR具有以下特點:

  • 超大數據集,低查詢延時(超大數據集由HDFS保證,查詢低延遲由MPP架構的Drill和IndexR專門設計的存儲格式保證)
  • 准實時 (和Druid實時攝入的思路類似,從Kafka實時攝入數據)
  • 高可用,易擴展(架構設計簡單,只有一種節點,可以輕易橫向擴展)
  • 易維護(支持Schema在線更新)
  • SQL支持 (由Drill支持,實際上Drill也是利用Calcite實現的)
  • 與Hadoop生態整合(Hive,Kafka,Spark, Zookeeper, HDFS)

Why IndexR


 IndexR的作者認為現有的各類OLAP系統均存在各種缺點,無法滿足其公司實際的OLAP需求,所以開發了IndexR。

  • Mysql,PostgreSQL等關系型數據庫:無法滿足超大規模數據集
  • ES等搜索系統:對OLAP場景沒有特殊優化,在大數據量場景下內存和磁盤壓力比較大
  • Druid,Pinot等時序數據庫:在查詢條件命中大量數據情況下可能會有性能問題,而且排序、聚合等能力普遍不太好,從IndexR作者的使用經驗來看運維比較困難,靈活性和擴展性不夠,比如缺乏Join、子查詢等。
  • Infobright,ClickHose等列式數據庫: 不是基於Hadoop生態的。
  • Kylin:查詢靈活性不足,無法進行探索式分析
  • Impala,Presto,SparkSQL,Drill等計算引擎 + Parquet等存儲引擎:這也是IndexR的架構。IndexR的優勢是更有效的索引設計,並且支持數據實時攝入。

IndexR Architecture


  • IndexR中只有一種節點IndexR Node,現在IndexR作為Drill插件嵌入了Drillbit進程,下圖是IndexR的服務部署圖:
  • Drill是一個類似Presto的MPP數據庫,Drillbit是一個類似Presto Work節點的常駐進程,和Hadoop的DN進程混部,可以利用HDFS的短路讀的特性。Zookeeper主要用來存儲表和segment的一些元信息。IndexR的架構圖如下:
  • IndexR支持從Kafka實時讀取數據。IndexR支持通過Drill,Hive,Spark查詢數據,不過Hive,Spark只能查詢歷史數據Drill可以同時查詢實時數據和歷史數據

IndexR Storage


1、基本概念

  • Table:表是對用戶可見的概念,用戶的查詢需要指定Table。
  • Segment:1個Table由多個Segment組成,Segment自解釋,自帶索引,是實時數據和離線數據轉換的紐帶,實時的segment和離線的segment具體結構稍有不同。
  • Column: IndexR是列式存儲的,即某一列的數據會集中存放在一起。某一列的索引和數據是存放在一起的。
  • Pack: 列數據在內部會進一步細分為Pack,每個Pack有65536行記錄,Pack是基本的IO和索引單位。
  • Row: 表示一行數據。實時數據攝入和離線導入的時候數據都是以行為單位加入一個segment的。

2、離線Segment的存儲格式

  • IndexR 在HDFS存儲的一個文件是一個Segment,一個Segment保存一個表的部分行,包含所有的列。
  • Segment 文件由4部分組成:版本號,Segment的元數據,所有Column 和 Pack的倒排索引。

  • Segment的元數據包括:行數,列數,每列的MAX和MIN值,每列的name, type,每列的各種索引的偏移量等。

  • Column包含多個Pack,每個Pack由DataPackNode,PackRSIndex,PackExtIndex,DataPack4部分組成,但是存儲的時候是先存儲所有Pack的索引數據,再存儲所有Pack的實際數據,這樣的好處是可以通過只讀取索引文件來快讀過濾掉不必要的Pack,來減少隨機IO。

    1. 圖中DataPack是實際的數據;

    2. DataPackNode是Pack元數據信息,包括索引文件的大小和偏移等;

    3. PackRSIndex是Pack的Rough Set索引;

    4. PackExtIndex是Pack的內索引,包括equal,in, greater, between, like 5種。

    5. 圖中的outerIndex是Pack級別的倒排索引,主要用於Pack之間的精准過濾。

3、實時Segment

  • 實時Segment存儲在實時節點 本機的文件系統,和離線Segment的主要區別是每個Column的數據,元數據,索引都是單獨一個文件。
  • 實時節點會定期的對本機的實時Segment進行merge,將多個segment合並為一個segment,並將所有Column寫入一個segment文件中。 基本原理和Druid類似,Durid(一): 原理架構

IndexR Index


  • IndexR的3層索引,依次是Rough Set Index(粗糙集索引), Inverted Index(倒排索引),PackExtIndex(內索引),如下圖

1、Rough Set Index

  • RSIndex的思路和Bloomfilter一樣,可以快速判斷某個值是否在某個Pack中。RSIndex的構建過程十分簡單,就是將Pack中某一列的所有值進行N等分, 如果這列的區間長度m小於1024,則N等於m,否則N等於1024。然后將每個值映射到這N個區間,每個區間用1個bit表示。如下圖
  • 對於如下的date列:因為區間長度(20170110 - 20170101 = 9)小於1024,所以每個值對應的bit就是和該列最小值的差值,所以生成的RSIndex如下,value等於1表示存儲,等於0表示不存在。
  • 所以當我們查詢: SELECT column FROM A WHERE date = '20170104'   時, 我們知道 20170104 的value是0,所以確定20170104不在該pack,可以直接跳過。
  • 由於Pack內的數據是根據維度有序的,每個Pack總共有65536行記錄,所有有很大概率1個Pack的維度列的基數是小於1024的。所以RSIndex的索引文件很小,而且索引效率較高。

2、Inverted Index

  • IndexR對於需要倒排索引的列會建立倒排索引,用於Pack之間的精准過濾。 倒排索引的構建過程如下:
  1. 首先Pack內部會使用紅黑樹對value進行字典編碼,然后將字典保存下來。
  2. 在生成離線 Segment的時候,每一列會建立倒排索引。
  3. 倒排索引會保留每個value到packID的映射。
  4. 查詢時會根據value找到對應的packID。

3、PackExtIndex

  • PackExtIndex是Pack的擴展索引,包括equal, in, greater, between, like 5種,主要用於查詢時的對於Pack內部數據的快速過濾。PackExtIndex的實現方式有兩種,一種是基於字典的,一種是基於bit的簡單索引。

4、有了Inverted Index為什么還需要RSIndex

  • 一個很明顯的問題,既然倒排索引已經可以很精准的對Pack進行過濾,為啥還多此一舉再加個粗糙集索引呢? 因為倒排索引是可選項,而且存儲成本較高。

IndexR 常見問題


1、數據實時攝入如何實現

  • 實現思路和Druid基本類似,實時節點直接從Kafka拉取數據,生成RT Segment。

2、IndexR如何支持Hive查詢

  • 實現了IndexRInputFormat 和 IndexROutputFormat。

3、IndexR 如何支持Spark查詢

  • 實現了IndexRFileFormat,該類實現了接口org.apache.spark.sql.execution.datasources.FileFormat。

4、IndexR 如何整合Drill

  • IndexR主要負責存儲層,作為Drill的1個存儲插件,還會對具體的查詢過程進行優化,比如常見的條件下推,limit下推。

5、IndexR 的存儲性能

  • 作者聲稱VLT模式的Segment的Scan速度比Parquet快2倍,而且僅需要 75%的存儲。Basic模式的Segment使用了Infobright的壓縮算法,可以實現極高的壓縮比。

6、IndexR 如何實現Schema的在線更新

  • 當addColumn,deleteColumn,alterColumn時,生成新的SegmentSchema,然后通過MR job生成新的Segment,當Job commit時,刪除舊的Segment,並將新Segment從tmp目錄move到標准目錄,最后通知該Segment已更新。

7、IndexR 堆外內存的實現

  • 利用sun.misc.Unsafe直接操作堆外內存。
  • 像C語言一樣直接用指針從內存get值,用指針直接set值。
  • 讀取文件時直接讀寫到DirectByteBuffer。
  • 用到DirectByteBuffer的類一定及時釋放。

IndexR 亮點


  • 豐富的索引。
  • 豐富的謂詞下推。
  • 只有一種節點,外部依賴較少。
  • 同時支持OLAP和明細查詢。
  • 支持Schema在線更新。
  • 使用堆外內存避免GC。
  • 壓縮算法使用C++實現。

 IndexR 不足


  • 數據類型僅支持int, long, float, double, string。
  • 聚合函數僅支持sum, max, min, first, last。
  • Drillbit和DN混部,可能會影響HDFS的穩定性。
  • 強依賴Drill,必須先部署Drill。

IndexR 是最快的數據庫嗎?


  • 顯然不是!

  • 沒有預計算的系統肯定不會是最快的OLAP數據庫,對於需要大量Scan,大量計算,大量聚合的SQL, 不經過預計算則不可能實現秒級查詢。IndexR的作者顯然也知道這個問題,所以提出了父子表的概念,也就是對於一些查詢經常用到的高頻維度組合,可以把這些高頻的維度組合提前計算出來,作為一張子表,這就是預計算的思想,和Kylin能夠保證Cube和HBase的透明性相比,IndexR必須要求應用層實現表的路由,並且查詢時需要明確的指定不同表的名稱。

  • 其實實際業務的查詢一般也是符合二八定律的,我們只需要將高頻的20%的維度組合預計算出來,就可以滿足80%查詢的性能要求。 Kylin一直在維度組合優化上努力,而360也在Druid中引入了類似Kylin中cubooid的概念。

  • 所以我們可以得出,要想打造出一個高並發,足夠穩定,秒級響應的OLAP系統,預計算肯定是必要的,但關鍵是我們需要在預計算的度上進行自動化,智能化的把控。

參考資料



免責聲明!

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



猜您在找
 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM