SAI 寫入路徑和讀取路徑
SAI 與基礎資料庫的儲存引擎深度整合。SAI 沒有抽象地索引表格。相反地,SAI 在寫入時索引 記憶表 和排序字串表 (SSTable),並在讀取時解決這些索引之間的差異。每個記憶表都是特定於特定資料庫表格的記憶體中資料結構。記憶表類似於寫回快取。每個 SSTable 都是資料庫定期將記憶表寫入的不可變資料檔。SSTable 會依序儲存在磁碟上,並針對每個資料庫表格維護。
本主題探討 SAI 讀取和寫入路徑的詳細資訊,並檢視 SAI 索引生命週期。
SAI 寫入路徑
SAI 索引可以在寫入任何資料到 CQL 表格之前或之後建立。作為複習,寫入 CQL 表格的資料會先寫入記憶表,然後在資料從記憶表清除後寫入 SSTable。建立 SAI 索引後,SAI 會收到針對目前記憶表的所有變更通知。與任何其他資料一樣,SAI 會更新插入和更新的索引,而 Apache Cassandra 會以完全相同的方式處理這些索引。SAI 也支援分割刪除、範圍墓碑和列移除。如果在查詢中執行刪除作業,SAI 會在後過濾步驟中處理索引變更。因此,SAI 在索引頻繁刪除的欄位時不會施加任何特殊罰則。

如果插入或更新包含索引欄位的有效內容,內容會新增到 記憶表索引,而更新列的主鍵會與索引值關聯。SAI 會計算新條目的增量堆積使用量估計值。此估計值會計入基礎記憶表的堆積使用量。此功能也表示隨著表格中索引的欄位越多,記憶表清除率會增加,而清除的 SSTable 大小會減少。總寫入數和所有實際記憶表索引的估計堆積使用量會顯示為指標。請參閱 SAI 指標。
Memtable 刷新
當達到刷新閾值時,SAI 會將 Memtable 索引內容直接刷新到磁碟,而不是建立額外的記憶體中表示。這是可能的,因為 Memtable 索引會先依據詞彙/值排序,然後再依據主鍵排序。當刷新發生時,SAI 會在 SSTable 撰寫時為每個索引欄位撰寫新的 SSTable 索引。

刷新作業是一個兩階段程序。在第一階段,列會撰寫到新的 SSTable。對於每一列,會產生一個列 ID,並建立三個索引元件。元件為
-
列 ID 對應到其對應代幣值的磁碟對應 — SAI 支援 Murmur3Partitioner
-
SSTable 分割區偏移
-
主鍵對應到其列 ID 的暫時對應,用於後續階段
第一個和第二個元件檔案的內容是壓縮陣列,其序數對應到列 ID。
在第二階段,當所有列都撰寫到新的 SSTable,且共用 SSTable 等級索引元件已完成後,SAI 會開始對每個索引欄位進行索引工作。特別是在第二階段,SAI 會反覆運算 Memtable 索引以產生詞彙及其代幣排序的列 ID。此反覆運算器會使用在第一階段建立的暫時對應結構,將主鍵轉換為列 ID。然後會將詞彙反覆運算器(含張貼)傳遞到不同的撰寫元件,具體取決於每個索引元素是針對字串欄位還是數字欄位。
在字串案例中,SAI 索引撰寫器會反覆運算每個詞彙,先將其張貼撰寫到磁碟,然後將這些張貼的偏移記錄在張貼檔案中,作為磁碟上、位元組順序樹狀結構中新條目(針對詞彙本身)的酬載。在數字案例中,SAI 會將數字索引的撰寫分為兩個步驟
詞彙會傳遞到平衡 kd 樹撰寫器,該撰寫器會將 kd 樹撰寫到磁碟。當樹的葉狀區塊撰寫完成時,其張貼會暫時記錄在記憶體中。這些暫時張貼會用於在葉狀節點和索引節點的不同層級建立磁碟上的張貼。
當欄位索引刷新完成時,會標記一個特殊的空標記檔案以表示成功。此程序會用於啟動和增量重建作業,以區分下列案例
-
某個欄位遺失 SSTable 索引檔案。
-
沒有可索引資料,例如當 SSTable 僅包含墓碑時。(墓碑是列中表示已刪除欄位的標記。在壓縮期間,已標記的欄位會被刪除。)
接著,SAI 會增加欄位已清除的 Memtable 索引計數器,並將每秒清除的儲存格數目新增至直方圖。
觸發壓縮時
請回想 Apache Cassandra 使用壓縮來合併 SSTable。壓縮會收集每個唯一列的所有版本,並使用 SSTable 中每個列的最最新版本(依時間戳記),組成一個完整的列。合併程序的效能很好,因為列會依每個 SSTable 中的分區金鑰排序,而且合併程序不會使用隨機 I/O。每個列的新版本會寫入新的 SSTable。舊版本以及任何準備刪除的列會留在舊 SSTable 中,並在任何待處理的讀取完成後刪除。

對於 SAI,當觸發壓縮時,每個索引群組會建立一個 SSTable 清除觀察器,以協調從其各自的 SSTable 寫入器執行個體中新壓縮資料寫入所有附加欄位索引的程序。與 Memtable 清除(其中已索引的詞彙已排序)不同,在壓縮期間反覆運算合併資料時,SAI 會緩衝已索引的值及其列 ID,並按權杖順序新增。
為避免耗盡可用堆積資源等問題,SAI 會使用累積區段緩衝區,並使用專有計算方式同步清除至磁碟。然後,每個區段會記錄區段列 ID 偏移量,並僅儲存區段列 ID(SSTable 列 ID 減去區段列 ID 偏移量)。SAI 會同步將區段清除至同一個檔案,以避免重寫所有區段的成本,並降低分區限制查詢和分頁範圍查詢的成本,因為這會減少搜尋空間。
從每欄位索引的張貼,到 SSTable 偏移量,再到 SSTable 分區的磁碟配置

實際的區段清除程序與 Memtable 清除非常類似。不過,在緩衝詞彙可以與其張貼一起寫入其各自類型特定的磁碟結構之前,會先將其排序。在特定索引的壓縮結束時,會標記一個特殊的空標記檔案以表示成功,並在 SAI 指標中記錄區段數目。請參閱 全域索引指標。
當整個壓縮任務完成時,SAI 會收到包含交易期間新增和移除的 SSTable 的 SSTable 清單已變更通知。SSTable Context Manager 和 Index View Manager 負責以原子方式將舊的 SSTable 索引替換為新的索引。此時,新的 SSTable 索引可供查詢使用。
SAI 讀取路徑
本節說明索引查詢如何由 SAI 協調器處理,以及如何由複製品執行。與傳統的次要索引不同,傳統的次要索引每個查詢最多只會使用一個欄位索引,而 SAI 實作了一個 查詢計畫
,讓單一查詢可以使用所有可用的欄位索引。
SAI 讀取作業的整體流程如下

索引選取和協調器處理
當收到查詢時,SAI 協調器執行的第一個動作,就是找出最具選擇性的索引,以利用一個或多個索引。最具選擇性的索引就是會最積極縮小篩選空間和最終結果數量的索引,方法是傳回估計結果列計算中的最低值。如果存在多個 SAI 索引(也就是每個 SAI 索引都基於不同的欄位,但查詢涉及多個欄位),則先選取哪一個 SAI 索引並不重要。
一旦選出最適合讀取作業的索引後,就會將索引嵌入讀取指令中,然後進入分散式範圍讀取裝置。分散式範圍讀取會按照令牌順序,在 Apache Cassandra 集群中查詢一或多輪。SAI 協調器會根據當地資料和查詢限制估算 並行度,也就是每個範圍的行數,以決定要連繫的範圍數。對於每一輪,並行度會決定要並行查詢多少個複製品。
在第一輪開始之前,SAI 會透過專有計算估算初始並行度,如下面的步驟 1 所示。

一旦建立了初始並行度,範圍讀取就會開始。

在步驟 2 中,SAI 協調器會根據並行度,並行地將要求傳送至所需的範圍。在步驟 3 中,SAI 協調器會等待來自所要求複製品的回應。在步驟 4 中,SAI 協調器會收集結果,並根據傳回的行和查詢限制重新計算並行度。
在每一輪完成時,如果尚未達到限制,就會調整並行度,以考量已讀取結果的形狀。如果第一輪沒有傳回任何結果,就會立即將並行度增加到剩餘令牌範圍的最小計算值和並行度的最大計算值。如果傳回結果,就會更新並行度。SAI 會重複步驟 2、3 和 4,直到滿足查詢限制。

為了避免查詢索引失敗的複製品,每個節點都會透過八卦將其自己的當地索引狀態傳播給對等節點。在協調器中,讀取要求會篩選包含要求中所使用、無法查詢的索引的複製品。在大部分情況下,第二輪的複製品查詢應該會傳回所有必要的結果。如果複製品之間的結果分佈極不平衡,可能需要進行更多輪的查詢。
深入了解:複本查詢規劃和檢視取得
複本從 SAI Coordinator 收到權杖範圍讀取請求後,就會開始執行本機索引查詢。SAI 透過查詢計畫實作索引搜尋器介面,讓使用者可以在單一查詢中存取所有可用的 SAI 欄索引。
查詢計畫會分析透過讀取指令傳遞給它的表達式。SAI 會決定應該使用哪些索引來滿足給定欄上的查詢子句。在將欄表達式與索引配對後,查詢控制器會取得每個欄索引的活動 SSTable 索引檢視。為了避免壓縮移除查詢中使用的索引檔案,查詢控制器在讀取任何索引檔案之前,會嘗試取得與查詢權杖範圍相交的索引檔案 SSTable 的參考,並在讀取請求完成時釋放它們。
此時,會建立權杖流程來串流每個欄索引中的比對。這些流程,以及決定如何合併它們的布林邏輯,會封裝在一個作業中,並傳回給查詢計畫元件。
SAI 權杖流程架構的角色
SAI 查詢引擎圍繞著一個權杖流程架構運作,定義了 SAI 如何非同步地反覆運算、跳入和合併來自個別 SSTable 索引和整個欄索引的比對分區串流。SAI 使用權杖來描述 Cassandra 環狀權杖中分區比對的容器。
反覆運算是這三個作業中最簡單的。特別是,張貼的反覆運算涉及透過區塊快取進行循序磁碟存取,以取得列 ID,這些 ID 用於查詢環狀權杖和分區金鑰偏移資訊。
權杖跳躍用於在從前一頁面邊界繼續時或是在權杖交集中找到較大權杖時跳過未比對的權杖。
比對串流和後過濾範例
考慮一個有個別欄索引的範例(例如 age = 44
),產生的流程是所有 Memtable 索引和所有 SSTable 索引的聯集。
-
SAI 以「延遲」的方式(也就是一次一個)反覆運算每個 Memtable 索引,並按照權杖順序透過個別權杖範圍分區的執行個體進行反覆運算。此功能減少了在環狀尾端不必要的資料搜尋所造成的額外負擔。
-
磁碟索引:SAI 傳回所有比對 SSTable 索引的聯集。在一個 SSTable 索引中,由於壓縮期間的記憶體限制,可能有多個區段。與 Memtable 索引類似,SAI 會以延遲的方式按照權杖排序順序搜尋區段。
當查詢中有使用 AND
查詢運算子連接多個索引表達式(例如 WHERE age=44 AND state='CA'
)時,索引表達式的結果會相交,並傳回符合所有索引表達式的分割鍵。

在索引搜尋後,SAI 會公開分割鍵的流程。對於每個單一分割鍵,SAI 會執行單一分割讀取操作,並傳回給定分割中的列。當列具象化後,SAI 會使用篩選樹套用另一輪篩選。SAI 會執行此後續篩選步驟,以處理下列事項
-
分割粒度:SAI 會追蹤分割偏移量。在寬分割架構的情況下,分割中的並非所有列都會符合索引表達式。
-
墓碑:SAI 沒有索引墓碑。已索引列有可能被新增加的墓碑遮蔽。
-
非索引表達式:操作可能包含沒有索引結構的非索引表達式。
下一步是什麼?
請參閱部落格,改善資料模型的更佳 Cassandra 索引:推出儲存附加索引。