Druid.io索引過程分析——時間窗,列存儲,LSM樹,充分利用內存,concise壓縮


Druid底層不保存原始數據,而是借鑒了Apache Lucene、Apache Solr以及ElasticSearch等檢索引擎的基本做法,對數據按列建立索引,最終轉化為Segment,用於存儲、查詢與分析。

首先,無論是實時數據還是批量數據在進入Druid前都需要經過Indexing Service這個過程。在Indexing Service階段,Druid主要做三件事:第一,將每條記錄轉換為列式(columnar format);第二,為每列數據建立位圖索引;第三,使用不同的壓縮算法進行壓縮,其中默認使用LZ4,對於字符類型列采用字典編碼(Dictionary encoding)進行壓縮,對於位圖索引采用Concise/Roaring bitmap進行編碼壓縮。最終的輸出結果也就是Segment。

下面,我們先講解Druid的索引過程中的幾個基本概念,再介紹實時索引的基本原理,最后結合我們在生產環境中使用過的兩種索引模式加深對原理的理解。

1 Segment粒度與時間窗口

Segment粒度(SegmentGranularity)表示每一個實時索引任務中產生的Segment所涵蓋的時間范圍。比如設置{”SegmentGranularity” : “HOUR”},表示每個Segment任務周期為1小時。

時間窗口(WindowPeriod)表示當前實時任務的時間跨度,對於落在時間窗口內的數據,Druid會將其“加工”成Segment,而任何早於或者晚於該時間窗口的數據都會被丟棄。

Segment粒度與時間窗口都是DruidReal-Time中重要的概念與配置項,因為它們既影響每個索引任務的存活時間,又影響數據停留在Real-TimeNode上的時長。所以,每個索引任務“加工”Segment的最長周期 =SegmentGranularity+WindowPeriod,在實際使用中,官方建議WindowPeriod<= SegmentGranularity,以避免創建大量的實時索引任務。

2 實時索引原理

Druid實時索引過程有三個主要特性:

  1. 主要面向流式數據(Event Stream)的攝取(ingest)與查詢,數據進入Real-TimeNode后可進行即席查詢。

  2. 實時索引面向一個小的時間窗口,落在窗口內的原始數據會被攝取,窗口外的原始數據則會被丟棄,已完成的Segments會被Handoff到HistoricalNode。

  3. 雖然Druid集群內的節點是彼此獨立的,但是整個實時索引過程通過Zookeeper進行協同工作。

實時索引過程可以划分為以下四個階段:

Ingest階段 
Real-TimeNode對於實時流數據,采用LSM-Tree(Log-Structured Merge-Tree )將數據持有在內存中(JVM堆中),優化數據的寫入性能。圖3.29中,Real-TimeNodes在13:37申明服務13:00-14:00這一小時內的所有數據。

Persist階段 
當到達一定閾值(0.9.0版本前,閾值是500萬行或10分鍾,為預防OOM,0.9.0版本后,閾值改為75000行或10分鍾)后,內存中的數據會被轉換為列式存儲物化到磁盤上,為了保證實時窗口內已物化的Smoosh文件依然可以被查詢,Druid使用內存文件映射方式(mmap)將Smoosh文件加載到直接內存 中,優化讀取性能。如圖3.29中所示,13:47、13:57、14:07都是Real-TimeNodes物化數據的時間點。 
這里寫圖片描述

圖3.28描述了Ingest階段與Persist階段內數據流走向以及內存情況。Druid對實時窗口內數據讀寫都做了大量優化,從而保證了實時海量數據的即席可查。

Merge階段 
對於Persist階段,會出現很多Smoosh碎片,小的碎片文件會嚴重影響后期的數據查詢工作,所以在實時索引任務周期的末尾(略少於SegmentGranularity+WindowPeriod時長),每個Real-TimeNode會產生back-groundtask,一方面是等待時間窗口內“掉隊”的數據,另一方面搜索本地磁盤所有已物化的Smoosh文件,並將其拼成Segment,也就是我們最后看到的index.zip。圖3.29中,當到達索引任務末期14:10分時,Real-TimeNodes開始merge磁盤上的所有文件,生成Segment,准備Handoff。

Handoff階段 
本階段主要由CoordinatorNodes負責,CoordinatorNodes會將已完成的Segment信息注冊到元信息庫、上傳DeepStorage,並通知集群內HistoricalNode去加載該Segment,同時每隔一定時間間隔(默認1分鍾)檢查Handoff狀態,如果成功,Real-TimeNode會在Zookeeper中申明已不服務該Segment,並執行下一個時間窗口內的索引任務;如果失敗,CoordinatorNodes會進行反復嘗試。圖3.29中,14:11分完成Handoff工作后,該Real-TimeNode申明不再為此時間窗口內的數據服務,開始下一個時間窗口內的索引任務。

這里寫圖片描述


免責聲明!

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



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