1. 程式人生 > >海量結構化資料儲存技術揭祕:Tablestore儲存和索引引擎詳解

海量結構化資料儲存技術揭祕:Tablestore儲存和索引引擎詳解

前言

表格儲存Tablestore是阿里雲自研的面向海量結構化資料儲存的Serverless NoSQL多模型資料庫。Tablestore在阿里雲官網上有各種文件介紹,也釋出了很多場景案例文章,這些文章收錄在這個合集中
《表格儲存Tablestore權威指南》。值得一提的是,Tablestore可以支撐海量的資料規模,也提供了多種索引來支援豐富的查詢模式,同時作為一個多模型資料庫,提供了多種模型的抽象和特有介面。本文主要對Tablestore的儲存和索引引擎進行介紹和解讀,讓大家對Tablestore引擎層的原理和能力,索引的作用和使用方式等有一個認識。

基本架構

Tablestore是一款雲上的Serverless的分散式NoSQL多模型資料庫,提供了豐富的功能。假設使用者可以採用各種開源元件搭建一套類似服務,可以說是成本非常高昂,而使用Tablestore僅需在控制檯上建立一個例項即可享受全部功能,而且是完全按量計費,可以說是0門檻。

整體架構如下圖所示,本文不展開敘述每個模組的功能。

在服務端引擎層中,存在兩個引擎:儲存引擎和索引引擎。這兩個引擎的資料結構和原理不同,為了方便讀者理解,本文將這兩個引擎稱為表引擎(Table)和多元索引引擎(Searchindex)。整體來說,引擎層是基於LSM架構和共享儲存(盤古),支援自動的Sharding和儲存計算分離。

表引擎

表引擎的整體架構類似於Google的BigTable,在開源領域的實現有HBase等。

資料模型可以定義為寬行模型,如下圖所示。其中不同的分割槽可以載入到不同的機器上,實現水平擴充套件:

首先說明一下為什麼Tablestore的主鍵可以包含多個主鍵列,而像HBase只有一個RowKey。這裡有幾點:

  1. 多列主鍵列按照順序共同構成一個主鍵,類似MySQL的聯合主鍵。如果使用過HBase,可以把這裡的多列主鍵列,拼接起來看作一個RowKey,每一列其實都只是整體主鍵的一部分。
  2. 第一列主鍵列是分割槽鍵,使用分割槽鍵的範圍進行分區劃分,保證了分割槽鍵相同的行,一定在同一個分割槽(Partition)上。一些功能依賴這一特性,比如分割槽內事務(Transection),本地二級索引(LocalIndex, 待發布),分割槽內自增列等。
  3. 業務上常需要多個欄位來構成主鍵,如果只支援一個主鍵列,業務需要進行拼接,多列主鍵列避免了業務層做主鍵拼接和拆解
  4. 許多使用者第一次看到多列主鍵列時,常會有誤解,認為主鍵的範圍查詢(GetRange介面)可以針對每一列單獨進行,實際上這裡的主鍵範圍指的是整體主鍵的範圍,而非單獨某一列的範圍

這個模型具有這樣的一些優勢:

  1. 完全水平擴充套件,因此可支撐的讀寫併發和資料規模幾乎無上限。Tablestore線上也有一些業務在幾千萬級的tps/qps,以及10PB級的儲存量。可以說一般業務達不到這樣的上限,實際的上限僅取決於叢集目前的機器資源,當業務資料量大量上漲時,只要增加機器資源即可。同時,基於共享儲存的架構也很方便的實現了動態負載均衡,不需要資料庫層進行副本資料複製。
  2. 提供了表模型,相比純粹的KeyValue資料庫而言,具有列和多版本的概念,可以單獨對某列進行讀寫。表模型也是一種比較通用的模型,可以方便與其他系統進行資料模型對映。
  3. 表模型中,按照主鍵有序儲存,而非Hash對映,因此支援主鍵的範圍掃描。類似於HashMap與SortedMap的區別,這個模型中為SortedMap。
  4. Schema Free, 即每行可以有不同的屬性列,資料列個數也不限制。這很適合儲存半結構化的資料,同時業務在執行過程中,也可以進行任意的屬性列變更。
  5. 支援資料自動過期和多版本。每列都可以儲存多個版本的值,每個值會有一個版本號,同時也是一個時間戳,如果設定了資料自動過期,就會按照這個時間戳來判斷資料是否過期,後臺對過期資料自動清理。

這個模型也有一些劣勢:

  1. 資料查詢依賴主鍵。可以把這個資料模型理解為SortedMap,大家知道,在SortedMap上只能做點查和順/逆序掃描,比如以下查詢方式:

    1. 主鍵點查:通過已知主鍵,精確讀取表上的一行。
    2. 主鍵範圍查:按照順序從開始主鍵(StartPrimaryKey)掃描到結束主鍵(EndPrimaryKey),或者逆序掃描。即對Table進行順序或逆序遍歷,支援指定起始位置和結束位置。
    3. 主鍵字首範圍查:其實等價於主鍵範圍查,這裡只是說明,主鍵字首的一個範圍,其實可以轉換成主鍵的一個範圍,在表上進行順序掃描即可。
  2. 針對屬性列的查詢需要使用Filter,Filter模式在過濾大量資料時效率不高,甚至變成全表掃描。通常來說,資料查詢的效率與底層掃描的資料量正相關,而底層掃描的資料量取決於資料分佈和結構。資料預設僅按照主鍵有序儲存,那麼要按照某一屬性列查詢,符合條件的資料必然分佈於全表的範圍內,需要掃描後篩選。全表資料越多,掃描的資料量也就越大,效率也就越低。

那麼在實際業務中,主鍵查詢常常不能滿足需求,而使用Filter在資料規模大的情況下效率很低,怎麼解決這一問題呢?

上面提到,資料查詢的效率與底層掃描的資料量正相關,而Filter模式慢在符合條件的資料太分散,必須掃描大量的資料並從中篩選。那麼解決這一問題也就有兩種思路:

  1. 讓符合條件的資料不再分散分佈:使用全域性二級索引,將某列或某幾列作為二級索引的主鍵。相當於通過資料冗餘,直接把符合條件的資料預先排在一起,查詢時直接精確定位和掃描,效率極高。
  2. **加快篩選的速度: **使用多元索引,多元索引底層提供了倒排索引,BKD-Tree等資料結構。以上面查詢某屬性列值為例,我們給這一列建立多元索引後,就會給這一列的值建立倒排索引,倒排索引實際上記錄了某個值對應的所有主鍵的集合,即Value -> List, 那麼要查詢屬性列為某個Value的所有記錄時,直接通過倒排索引獲取所有符合條件的主鍵,進行讀取即可。本質上是加快了從海量資料中篩選資料的效率。

全域性二級索引

全域性二級索引採用的仍然是表引擎,給主表建立了全域性二級索引後,相當於多了一張索引表。這張索引表相當於給主表提供了另外一種排序的方式,即針對查詢條件預先設計了一種資料分佈,來加快資料查詢的效率。索引的使用方式與主表類似,主要的查詢方式仍然是上面講的主鍵點查,主鍵範圍查,主鍵字首範圍查。常見的關係型資料庫的二級索引也是類似的原理。

列舉一個最簡單的例子,比如我們有一張表儲存檔案的MD5和SHA1值,表結構如下:

FilePath(主鍵列) MD5(屬性列) SHA1(屬性列)
oss://abc/files/1.txt 0cc175b9c0f1b6a831c399e269772661 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8
oss://abc/files/2.txt 92eb5ffee6ae2fec3ad71c777531578f e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98
oss://abc/files/3.txt 4a8a08f09d37b73795649038408b5f33 84a516841ba77a5b4648de2cd0dfcb30ea46dbb4

通過這張表,我們可以查詢檔案對應的MD5和SHA1值,但是通過MD5或SHA1反查檔名卻不容易。我們可以給這張表建立兩張全域性二級索引表,表結構分別為:

索引1:

MD5(主鍵列1) FilePath(主鍵列2)
0cc175b9c0f1b6a831c399e269772661 oss://abc/files/1.txt
4a8a08f09d37b73795649038408b5f33 oss://abc/files/3.txt
92eb5ffee6ae2fec3ad71c777531578f oss://abc/files/2.txt

索引2:

SHA1(主鍵列1) FilePath(主鍵列2)
84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 oss://abc/files/3.txt
86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 oss://abc/files/1.txt
e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 oss://abc/files/2.txt
   

為了確保主鍵的唯一性,全域性二級索引中,會將原主鍵的主鍵列也放到主鍵列中,比如上面的FilePath列。有了上面兩張索引表,就可以通過主鍵字首範圍查的方式裡精確定位某個MD5/SHA1對應的檔名了。

多元索引引擎

多元索引引擎相比於表引擎,底層增加了倒排索引,多維空間索引等,支援多條件組合查詢、模糊查詢、地理空間查詢,以及全文索引等,還提供一些統計聚合能力(統計聚合功能待發布)。因為功能較單純的二級索引更加豐富,而且一個索引就可以滿足多種維度的查詢,因此命名為多元索引。

上面在講解決Filter模式查詢慢的問題時,提到倒排索引加快了資料篩選的速度,因為記錄了某列的Value到符合條件的行的對映,Value -> List 。實際上,倒排索引這一方式,不僅可以解決單列值的檢索問題,也可以解決多條件組合查詢的問題。

我們舉一個訂單場景的例子,比如下表為一個訂單記錄:

訂單號 訂單(md5)(主鍵) 消費者編號 消費者姓名 售貨員編號 售貨員姓名 產品編號 產品名 產品品牌 產品型別 下單時間 支付時間 支付狀態 產品單價 數量 總價錢
o0000000000 c49f5fd5aba33159accae0d3ecd749a7 c0019 消陳九 s0020 售楚十 p0003004 vivo x21 vivo 手機 2018-07-17 21:00:00   2498.99 2 4997.98

上面一共16個欄位,我們希望按照任意多個欄位組合查詢,比如查詢某一售貨員、某一產品型別、單價在xx元之上的所有記錄。可以想到,這樣的排列組合會有非常多種,因此我們不太可能預先將任何一種查詢條件的資料放到一起,來加快查詢的效率,這需要建立很多的全域性二級索引。而如果採用Filter模型,又很可能需要掃描全表,效率不高。折中的方式是,可以先對某個欄位建立二級索引,縮小資料範圍,再對其中資料進行Filter。那麼有沒有更好的方式呢?

多元索引可以很好的解決這一問題,而且只需要建立一個多元索引,將所有可能查詢的列加入到這個多元索引中即可,加入的順序也沒有要求。多元索引中的每一列預設都會建立倒排,倒排就記錄了Value到List的對映。針對多列的多個條件,在每列的倒排表中找到對應的List,這個稱為一個倒排鏈,而篩選符合多個條件的資料即為計算多個倒排鏈的交併集,這裡底層有著大量的優化,可以高效的實現這一操作。因此多元索引在處理多條件組合查詢方面效率很高。

此外,多元索引還支援全文索引、模糊查詢、地理空間查詢等,以地理空間查詢為例,多元索引通過底層的BKD-Tree結構,支援高效的查詢一個地理多邊形內的點,也支援按照地理位置排序、聚合統計等。

索引選擇

不是一定需要索引

  1. 如果基於主鍵和主鍵範圍查詢的功能已經可以滿足業務需求,那麼不需要建立索引。
  2. 如果對某個範圍內進行篩選,範圍內資料量不大或者查詢頻率不高,可以使用Filter,不需要建立索引。
  3. 如果是某種複雜查詢,執行頻率較低,對延遲不敏感,可以考慮通過DLA(資料湖分析)服務訪問Tablestore,使用SQL進行查詢。

全域性二級索引還是多元索引

  1. 一個全域性二級索引是一個索引表,類似於主表,其提供了另一種資料分佈方式,或者認為是另一種主鍵排序方式。一個索引對應一種查詢條件,預先將符合查詢條件的資料排列在一起,查詢效率很高。索引表可支撐的資料規模與主表相同,另一方面,全域性二級索引的主鍵設計也同樣需要考慮雜湊問題。
  2. 一個多元索引是一系列資料結構的組合,其中的每一列都支援建立倒排索引等結構,查詢時可以按照其中任意一列進行排序。一個多元索引可以支援多種查詢條件,不需要對不同查詢條件建立多個多元索引。相比全域性二級索引,也支援多條件組合查詢、模糊查詢、全文索引、地理位置查詢等。多元索引本質上是通過各種資料結構加快了資料的篩選過程,功能非常豐富,但在資料按照某種固定順序讀取這種場景上,效率不如全域性二級索引。多元索引的查詢效率與倒排鏈長度等因素相關,即查詢效能與整個表的全量資料規模有關,在資料規模達到百億行以上時,建議使用RoutingKey對資料進行分片,查詢時也通過指定RoutingKey查詢來減少查詢涉及到的資料量。簡而言之,查詢靈活度和資料規模不可兼得。

關於使用多元索引還是全域性二級索引,也有另外一篇文章描述:《Tablestore索引功能詳解》

除了全域性二級索引之外,後續還會推出本地二級索引(LocalIndex),推出後再進行詳細介紹。

常見組合方案

豐富的查詢功能當然是業務都希望具備的,但是在資料規模很大的情況下,靈活的查詢意味著成本。比如萬億行資料的規模,對於表引擎來說,因為水平擴充套件能力很強,成本也很低,問題不大,但是建立多元索引,費用就會非常高昂。全域性二級索引成本較低,但是隻適合固定維度的查詢。

常見的超大規模資料,都帶有一些時間屬性,比如大量裝置產生的資料(監控資料),或者人產生的資料(訊息、行為資料等),這類資料非常適合採用Tablestore儲存。對這類資料建立索引,會有一些組合方案:

  1. 對元資料表建立多元索引,全量資料表不建立索引或採用全域性二級索引。

    1. 元資料表可以是產生資料的主體表,比如裝置資訊表,使用者資訊表等。在時序模型中,產生資料的主體也可以認為是一個時間線,這條線會不斷的產生新的點。
    2. Tablestore的時序資料模型(Timestream)採用的也是類似的方式,對時序資料中的時間線建立一張表,專門用來記錄時間線的元資料,每個時間線一行。時間線表建立多元索引,用來做時間線檢索,而全量資料則不建立索引。在檢索到時間線後,對某個時間線下的資料進行範圍掃描,來讀取這個時間線的資料。
  2. 熱資料建立多元索引,老資料不建立索引或者採用全域性二級索引:

    1. 很多情況下僅需要對非常熱的資料進行多種維度查詢,對冷資料採取固定維度查詢即可。因此冷熱分離可以給業務提供更高的價效比。
    2. 目前多元索引還不支援TTL(後續會支援),需要業務層區分熱資料和冷資料。

總結

本文對Tablestore的儲存和索引引擎進行了介紹和解讀,並在如何選擇和應用索引方面給了一些參考,目的是加深大家對Tablestore的認識和理解,更好的應用Tablestore來解決業務需求。

 


本文作者:亦徵

原文連結

本文為雲棲社群原創內容,未經