稀疏索引與其在Kafka骗灶、ClickHouse中的應(yīng)用

Sparse Index

在以數(shù)據(jù)庫為代表的存儲(chǔ)系統(tǒng)中惨恭,索引(index)是一種附加于原始數(shù)據(jù)之上的數(shù)據(jù)結(jié)構(gòu),能夠通過減少磁盤訪問來提升查詢速度耙旦,與現(xiàn)實(shí)中的書籍目錄異曲同工脱羡。索引通常包含兩部分,即索引鍵(≈章節(jié))與指向原始數(shù)據(jù)的指針(≈頁碼)免都,如下圖所示锉罐。

https://www.geeksforgeeks.org/indexing-in-databases-set-1/

索引的組織形式多種多樣,本文要介紹的稀疏索引(sparse index)是一種簡(jiǎn)單而常用的有序索引形式——即在數(shù)據(jù)主鍵有序的基礎(chǔ)上绕娘,只為部分(通常是較少一部分)原始數(shù)據(jù)建立索引脓规,從而在查詢時(shí)能夠圈定出大致的范圍,再在范圍內(nèi)利用適當(dāng)?shù)牟檎宜惴ㄕ业侥繕?biāo)數(shù)據(jù)业舍。如下圖所示,為3條原始數(shù)據(jù)建立了稀疏索引升酣。

https://www2.cs.sfu.ca/CourseCentral/354/zaiane/material/notes/Chapter11/node5.html

相對(duì)地舷暮,如果為所有原始數(shù)據(jù)建立索引,就稱為稠密索引(dense index)噩茄,如下圖下面。

稠密索引和稀疏索引其實(shí)就是空間和時(shí)間的trade-off。在數(shù)據(jù)量巨大時(shí)绩聘,為每條數(shù)據(jù)都建立索引也會(huì)耗費(fèi)大量空間沥割,所以稀疏索引在特定場(chǎng)景非常好用。以下舉兩個(gè)例子凿菩。

Sparse Index in Kafka

我們知道机杜,單個(gè)Kafka的TopicPartition中,消息數(shù)據(jù)會(huì)被切分成段(segment)來存儲(chǔ)衅谷,擴(kuò)展名為.log椒拗。log文件的切分時(shí)機(jī)由大小參數(shù)log.segment.bytes(默認(rèn)值1G)和時(shí)間參數(shù)log.roll.hours(默認(rèn)值7天)共同決定。數(shù)據(jù)目錄中存儲(chǔ)的部分文件如下。

.
├── 00000000000190089251.index
├── 00000000000190089251.log
├── 00000000000190089251.timeindex
├── 00000000000191671269.index
├── 00000000000191671269.log
├── 00000000000191671269.timeindex
├── 00000000000193246592.index
├── 00000000000193246592.log
├── 00000000000193246592.timeindex
├── 00000000000194821538.index
├── 00000000000194821538.log
├── 00000000000194821538.timeindex
├── 00000000000196397456.index
├── 00000000000196397456.log
├── 00000000000196397456.timeindex
├── 00000000000197971543.index
├── 00000000000197971543.log
├── 00000000000197971543.timeindex
......

log文件的文件名都是64位整形蚀苛,表示這個(gè)log文件內(nèi)存儲(chǔ)的第一條消息的offset值減去1(也就是上一個(gè)log文件最后一條消息的offset值)在验。每個(gè)log文件都會(huì)配備兩個(gè)索引文件——index和timeindex,分別對(duì)應(yīng)偏移量索引和時(shí)間戳索引堵未,且均為稀疏索引腋舌。

可以通過Kafka提供的DumpLogSegments小工具來查看索引文件中的信息。

~ kafka-run-class kafka.tools.DumpLogSegments --files /data4/kafka/data/ods_analytics_access_log-3/00000000000197971543.index
Dumping /data4/kafka/data/ods_analytics_access_log-3/00000000000197971543.index
offset: 197971551 position: 5207
offset: 197971558 position: 9927
offset: 197971565 position: 14624
offset: 197971572 position: 19338
offset: 197971578 position: 23509
offset: 197971585 position: 28392
offset: 197971592 position: 33174
offset: 197971599 position: 38036
offset: 197971606 position: 42732
......

~ kafka-run-class kafka.tools.DumpLogSegments --files /data4/kafka/data/ods_analytics_access_log-3/00000000000197971543.timeindex
Dumping /data4/kafka/data/ods_analytics_access_log-3/00000000000197971543.timeindex
timestamp: 1593230317565 offset: 197971551
timestamp: 1593230317642 offset: 197971558
timestamp: 1593230317979 offset: 197971564
timestamp: 1593230318346 offset: 197971572
timestamp: 1593230318558 offset: 197971578
timestamp: 1593230318579 offset: 197971582
timestamp: 1593230318765 offset: 197971592
timestamp: 1593230319117 offset: 197971599
timestamp: 1593230319442 offset: 197971606
......

可見渗蟹,index文件中存儲(chǔ)的是offset值與對(duì)應(yīng)數(shù)據(jù)在log文件中存儲(chǔ)位置的映射块饺,而timeindex文件中存儲(chǔ)的是時(shí)間戳與對(duì)應(yīng)數(shù)據(jù)offset值的映射。有了它們拙徽,就可以快速地通過offset值或時(shí)間戳定位到消息的具體位置了刨沦。并且由于索引文件的size都不大,因此很容易將它們做內(nèi)存映射(mmap)膘怕,存取效率很高想诅。

以index文件為例,如果我們想要找到offset=197971577的消息岛心,流程是:

  • 通過二分查找来破,在index文件序列中,找到包含該offset的文件(00000000000197971543.index)忘古;
  • 通過二分查找徘禁,在上一步定位到的index文件中,找到該offset所在區(qū)間的起點(diǎn)(197971592)髓堪;
  • 從上一步的起點(diǎn)開始順序查找送朱,直到找到目標(biāo)offset。

最后干旁,稀疏索引的粒度由log.index.interval.bytes參數(shù)來決定驶沼,默認(rèn)為4KB,即每隔log文件中4KB的數(shù)據(jù)量生成一條索引數(shù)據(jù)争群。調(diào)大這個(gè)參數(shù)會(huì)使得索引更加稀疏回怜,反之則會(huì)更稠密。

Sparse Index in ClickHouse

在ClickHouse中换薄,MergeTree引擎表的索引列在建表時(shí)使用ORDER BY語法來指定玉雾。而在官方文檔中,用了下面一幅圖來說明轻要。

這張圖示出了以CounterID复旬、Date兩列為索引列的情況,即先以CounterID為主要關(guān)鍵字排序冲泥,再以Date為次要關(guān)鍵字排序赢底,最后用兩列的組合作為索引鍵。marks與mark numbers就是索引標(biāo)記,且marks之間的間隔就由建表時(shí)的索引粒度參數(shù)index_granularity來指定幸冻,默認(rèn)值為8192粹庞。

ClickHouse MergeTree引擎表中,每個(gè)part的數(shù)據(jù)大致以下面的結(jié)構(gòu)存儲(chǔ)洽损。

.
├── business_area_id.bin
├── business_area_id.mrk2
├── coupon_money.bin
├── coupon_money.mrk2
├── groupon_id.bin
├── groupon_id.mrk2
├── is_new_order.bin
├── is_new_order.mrk2
......
├── primary.idx
......

其中庞溜,bin文件存儲(chǔ)的是每一列的原始數(shù)據(jù)(壓縮存儲(chǔ)),mrk2文件存儲(chǔ)的是圖中的mark numbers與bin文件中數(shù)據(jù)位置的映射關(guān)系碑定。另外流码,還有一個(gè)primary.idx文件存儲(chǔ)被索引列的具體數(shù)據(jù)。每個(gè)part的數(shù)據(jù)都存儲(chǔ)在單獨(dú)的目錄中延刘,目錄名形如20200708_92_121_7漫试,即包含了分區(qū)鍵、起始mark number和結(jié)束mark number碘赖,方便定位驾荣。

在ClickHouse之父Alexey Milovidov分享的PPT中,有更加詳細(xì)的圖示普泡。

這樣播掷,每一列都通過ORDER BY列進(jìn)行了索引。查詢時(shí)撼班,先查找到數(shù)據(jù)所在的parts歧匈,再通過mrk2文件確定bin文件中數(shù)據(jù)的范圍即可。

不過砰嘁,ClickHouse的稀疏索引與Kafka的稀疏索引不同件炉,可以由用戶自由組合多列,因此也要格外注意不要加入太多索引列矮湘,防止索引數(shù)據(jù)過于稀疏斟冕,增大存儲(chǔ)和查找成本。另外板祝,基數(shù)太泄病(即區(qū)分度太低)的列不適合做索引列走净,因?yàn)楹芸赡軝M跨多個(gè)mark的值仍然相同券时,沒有索引的意義了。

The End

準(zhǔn)備凌晨上線伏伯,民那晚安橘洞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市说搅,隨后出現(xiàn)的幾起案子炸枣,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件适肠,死亡現(xiàn)場(chǎng)離奇詭異霍衫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)侯养,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門敦跌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逛揩,你說我怎么就攤上這事柠傍。” “怎么了辩稽?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵惧笛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我逞泄,道長(zhǎng)患整,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任炭懊,我火速辦了婚禮并级,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘侮腹。我一直安慰自己嘲碧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布父阻。 她就那樣靜靜地躺著愈涩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪加矛。 梳的紋絲不亂的頭發(fā)上履婉,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音斟览,去河邊找鬼毁腿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苛茂,可吹牛的內(nèi)容都是我干的已烤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妓羊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼胯究!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起躁绸,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤裕循,失蹤者是張志新(化名)和其女友劉穎臣嚣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥哑,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硅则,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了株婴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抢埋。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖督暂,靈堂內(nèi)的尸體忽然破棺而出揪垄,到底是詐尸還是另有隱情,我是刑警寧澤逻翁,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布饥努,位于F島的核電站,受9級(jí)特大地震影響八回,放射性物質(zhì)發(fā)生泄漏酷愧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一缠诅、第九天 我趴在偏房一處隱蔽的房頂上張望溶浴。 院中可真熱鬧,春花似錦管引、人聲如沸士败。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谅将。三九已至,卻和暖如春重慢,著一層夾襖步出監(jiān)牢的瞬間饥臂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工似踱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隅熙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓核芽,卻偏偏與公主長(zhǎng)得像囚戚,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狞洋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354