天天看點

塊級(ctid)掃描在IoT(物聯網)極限寫和消費讀并存場景的應用

postgresql , 塊掃描 , 行号掃描 , ctid , tid scan , iot , 物聯網 , 極限寫入 , 實時消費 , 實時讀 , 堆表 , heap , 時序

在物聯網有一個非常普遍的資料需求,就是資料的寫入,另一個普遍的需求則是資料的消費(按時序讀取),以及流式計算。

關于流式計算,請參考

<a href="https://github.com/digoal/blog/blob/master/201705/20170518_01.md">《(流式、lambda、觸發器)實時處理大比拼 - 物聯網(iot)\金融,時序處理最佳實踐》</a>

<a href="https://github.com/digoal/blog/blob/master/201612/20161220_01.md">《流計算風雲再起 - postgresql攜pipelinedb力挺iot》</a>

<a href="https://github.com/digoal/blog/blob/master/201512/20151215_01.md">《"物聯網"流式處理應用 - 用postgresql實時處理(萬億每天)》</a>

接下來我們談一談極限寫入和消費。

從資料存儲結構來看,postgresql的heap存儲是非常适合高速寫入的,追加式寫入。以下文章中已得到高速寫入的驗證。

<a href="https://github.com/digoal/blog/blob/master/201603/20160320_01.md">《postgresql 如何潇灑的處理每天上百tb的資料增量》</a>

brin索引,也被稱為塊索引,是針對資料塊中繼資料建立的索引(例如某個自增長字段,實體存儲和字段的值存在很好的線性相關性,那麼每個塊的資料區間就具有非常強的獨立性),brin索引非常小,對寫入性能的影響可以忽略。

brin适合實體存儲和字段的值存在很好的線性相關性的字段,例如時序字段。

或者使用cluster或order 重排後,适合對應字段。

消費是指異步的讀取資料,處理資料的過程,例如iot場景,資料的寫入延遲要求非常低,是以要求寫入吞吐特别大。

而處理方面,則通過消費機制,進行處理。

那麼如何消費呢?

通常可以根據索引進行消費,比如前面提到的brin索引,對寫入吞吐的影響小,同時支援=,以及範圍的檢索。如果有時序字段的話,brin是非常好的選擇。

然而并非所有的資料寫入場景都有時序字段(當然使用者可以添加一個時間字段來解決這個問題)。當沒有時序字段時,如何消費效率最高呢?

塊掃描是很好的選擇,前面提到了資料存儲是heap,追加形式。

postgresql提供了一種tid scan的掃描方法,告訴資料庫你要搜尋哪個資料塊的哪條記錄。

這條sql指查詢100号資料塊的第100條記錄。

這種掃描效率非常之高,可以配合heap存儲,在消費(讀取記錄)時使用。

postgresql暫時沒有提供傳回整個資料塊的所有記錄的接口,隻能傳回某個資料塊的某一條記錄,是以如果我們需要讀取某個資料塊的記錄,需要枚舉該資料塊的所有行。

如何評估一個資料塊有多少條記錄,或者最多有多少條記錄?

<a href="https://www.postgresql.org/docs/10/static/storage-page-layout.html">https://www.postgresql.org/docs/10/static/storage-page-layout.html</a>

heaptupleheaderdata layout

field

type

length

description

t_xmin

transactionid

4 bytes

t_xmax

delete xid stamp

t_cid

commandid

insert and/or delete cid stamp (overlays with t_xvac)

t_xvac

xid for vacuum operation moving a row version

t_ctid

itempointerdata

6 bytes

current tid of this or newer row version

t_infomask2

uint16

2 bytes

number of attributes, plus various flag bits

t_infomask

various flag bits

t_hoff

uint8

1 byte

offset to user data

overall page layout

item

pageheaderdata

24 bytes long. contains general information about the page, including free space pointers.

itemiddata

array of (offset,length) pairs pointing to the actual items. 4 bytes per item.

free space

the unallocated space. new item pointers are allocated from the start of this area, new items from the end.

items

the actual items themselves.

special space

index access method specific data. different methods store different data. empty in ordinary tables.

最大記錄數=block_size/(ctid+tuple head)=block_size/(4+27);

如果需要評估更精确的行數,可以加上字段的固定長度,變長字段的頭(4byte)。

如果資料沒有更新,删除;那麼ctid還可以作為索引來使用,例如全文檢索(es),可以在建立索引時使用ctid來指向資料庫中的記錄,而不需要另外再建一個pk,也能大幅度提升寫入性能。

<a href="https://www.citusdata.com/blog/2016/03/30/five-ways-to-paginate/">https://www.citusdata.com/blog/2016/03/30/five-ways-to-paginate/</a>

<a href="https://www.postgresql.org/message-id/flat/be64327d326568a3be7fde1891ed34ff.squirrel%40sq.gransy.com#[email protected]">https://www.postgresql.org/message-id/flat/be64327d326568a3be7fde1891ed34ff.squirrel%40sq.gransy.com#[email protected]</a>