Ledgers和Fragments是在Zookeeper中維護(hù)和跟蹤的邏輯結(jié)構(gòu)。物理上數(shù)據(jù)不存儲在Ledgers和Fragments對應(yīng)的文件中群叶。BookKeeper中存儲的實現(xiàn)是可拔插的,Pulsar默認(rèn)使用名稱為DbLedgerStorage的存儲實現(xiàn)问词。
Pulsar 的數(shù)據(jù)最終是靠 Bookkeeper(Bookie) 存儲的桃犬,各個 Pulsar Bookie 之間是平等的,kafka 的存儲節(jié)點在 Partition 層次上有主從之分垛孔。
pulsar單個 Broker 數(shù)據(jù)寫流程如下:
- 1 將寫請求記入 WAL【類似于數(shù)據(jù)庫的 Journal 文件】
一般把 WAL 和數(shù)據(jù)存儲文件分別存儲到兩種存儲盤上,如把 WAL 存入一個 SSD 盤施敢,而數(shù)據(jù)文件存入另一個 SSD 或者 SATA 盤周荐。
2 將數(shù)據(jù)寫入內(nèi)存緩存中。
3 寫緩存寫滿后或達(dá)到時間閾值時僵娃,進(jìn)行數(shù)據(jù)排序并刷盤概作,排序時將同一個ledger的數(shù)據(jù)聚合后按照時間先后進(jìn)行排序磨澡。
4 將 <(LedgerID, EntryID), EntryLogID> 寫入 RocksDB
LedgerID 相當(dāng)于 kafka 的 ParitionID爪膊,EntryID 即是 Log Message 的邏輯 ID杨箭,EntryLogId 就是 Log消息在 Pulsar Fragment文件的物理 Offset缩抡。
這里把這個映射關(guān)系存儲 RocksDB 只是為了加快寫入速度,其自身并不是 Pulsar Bookie 的關(guān)鍵組件拐辽。
讀:
1 從寫緩存讀取數(shù)據(jù)【因為寫緩存有最新的數(shù)據(jù)】焚碌;
2 如果寫緩存不命中媒鼓,則從讀緩存讀取數(shù)據(jù)垃僚;
3 如果讀緩存不命中集绰,則根據(jù) RocksDB 存儲的映射關(guān)系查找消息對應(yīng)的物理存儲位置,然后從磁盤上讀取數(shù)據(jù)谆棺;
4 把從磁盤讀取的數(shù)據(jù)回填到讀緩存中栽燕;
5 把數(shù)據(jù)返回給 Broker。
寫:
Bookie 的整個寫入流程除了自身把內(nèi)存緩存數(shù)據(jù)批量刷盤一步外改淑,整個流程幾乎不需要跟磁盤進(jìn)行IO碍岔,所以速度也是極快。
寫入都按順序?qū)懭肴罩疚募梢源鎯υ趯S玫拇疟P上朵夏,并且可以批量刷盤以獲得搞得吞吐量蔼啦。除此之外從寫入操作來看沒有其他的同步磁盤IO操作,數(shù)據(jù)都是寫入到內(nèi)存的緩存區(qū)仰猖。
總結(jié)
上圖為Pulsar默認(rèn)使用的bookie架構(gòu)