抖音集團離線數倉血緣基礎能力的構建與應用
一、背景介紹
企業數據建設面臨兩大類問題:
- 第一類問題:聚焦于如何有效識別數據傳輸鏈路,特別是在各公司離線數倉規模持續擴大的背景下。用戶常遇到以下挑戰:
首先,針對多業務線場景,需要明確某一 Hive 表中包含哪些業務線的數據,以及某個業務線的數據具體存儲在哪些 Hive 表中。這要求企業具備標簽識別能力,以清晰界定業務范圍。
其次,隨著離線 ETL 鏈路的延伸,敏感數據的范圍也在不斷擴大。因此,企業需要準確標注敏感數據的邊界,并實施精確的管控措施。
再者,數據規模不斷增多,存儲成本也在持續攀升。企業需判斷哪些 Hive 表甚至 Hive 列適合進行數據治理,以助力降本增效。 - 第二類問題聚焦于數據保護領域。隨著安全合規要求的日益嚴格,保障敏感數據的安全成為每個企業都必須應對的挑戰。這主要包括兩方面:
一方面,隨著 ETL 鏈路的擴展,不同業務歸屬的數據可能最終匯聚到同一個 Hive 表或列中。這時,企業需要實施更細致的權限管控,確保下游使用數據時滿足權限最小化原則。
另一方面,對于高度敏感的場景,企業需要對查詢結果進行脫敏處理。在確保隱私數據安全合規的前提下,盡可能降低用戶的使用成本,使用戶能夠更便捷地利用這些數據。
基于血緣的數據發現&數據保護方案
針對上述問題,我們提出了一套依托 SQL 血緣能力的數據發現與數據保護解決方案。
針對第一類數據發現問題,首先利用表級和列級的血緣能力,構建一個涵蓋所有 Hive 表的全局血緣關系圖。從全局血緣圖譜的業務起點出發,逐層分析各節點間的 SQL 語義,以此傳播標簽信息。最終,憑借全局標簽信息,我們能夠高效且精確地識別數據的使用情況和整體流動鏈路,進而對數據實施精細化的運營管理。
對于第二類數據保護場景,同樣依賴于表/列級別的血緣能力。通過深入分析 SQL 的構成,確保在不影響計算語義的前提下,對計算結果進行精準脫敏,從而減輕對用戶側的干擾。在權限控制層面,憑借血緣能力實現更精細的權限提取,達到行列級別的權限管控,進而完成權限最小化的操作。
二、血緣基礎能力介紹
1. 什么是 SQL 血緣
SQL 血緣是一種用于跟蹤和分析數據處理過程的技術,可以幫助我們清晰地了解數據是如何在計算鏈路中傳遞和演變的。
以上圖中的 SQL 為例,假設有三張表:table1包含 a1、a2、a3 三列,table2 包含 b1、b2、b3 三列,而 table3 則有 c1、c2 兩列。現在,我們基于這三張表構建了一個 SQL 查詢,其中 table1 作為子查詢 t1,table2 作為子查詢 t2,這兩個子查詢通過 join 操作連接,并將最終結果插入到 table3 中。
在這個查詢中可以看到,table3 的 c1 列的數據來源于 table1 的 a2 列,而 c2 列的數據則來源于 table2 的 b2 列。這種列的流動關系就構成了右側所示的血緣關系圖。在這個關系圖譜中,三張表通過列的流轉相互關聯,清晰地展示了數據是如何在這些表之間流動的。
2. 如何實現 SQL 血緣提取
接下來從技術角度闡述如何從 SQL 中提取血緣信息。
首要步驟是對 SQL 進行解析和優化,這一流程會生成一個樹狀的執行計劃結構。解析和優化的流程可以參考上圖中右側部分。當接收到用戶的 SQL 后,首先會進入 Parser 階段,對 SQL 進行詞法分析和語法分析,從而生成一棵抽象語法樹(SqlNode 結構)。其次,進入 validate 模塊,對語義正確性和元數據進行校驗。再次,基于新的抽象語法樹進行 convert 和 optimize 操作,包括一些轉換和優化步驟。經過這些步驟后,我們就能得到一個最終的樹狀執行計劃結構,如上圖下方所示。
需要強調的是,在血緣追蹤的場景中,優化步驟是很有必要的。因為優化階段會執行諸如列裁剪、常量折疊等優化規則,這些規則對于提高血緣提取的準確率和正確率有著極大的幫助。
第一步:得到一個樹狀的執行計劃,并基于執行計劃去追蹤血緣。
第二步:取執行計劃最外層每一列對應的 Index 下標信息,并使用這個 Index 下標逐層的向下檢索。在離線數倉的場景中,大部分操作都是選擇一張表,將結果插入到另一張表里,因此數據的底層來源通常是另一張 Hive 表。在執行計劃中,該 Hive 表對應的節點就是 TableScan 節點。
基于 Index 信息遞歸向下尋找,直到找到最底層的 TableScan 節點,在 TableScan 節點 Index 下標對應位置的列信息,就是最外層列對應的列血緣。
以圖中左下角的 SQL 為例,具體講解這一過程的實現。
該 SQL 經過解析和優化后,會形成圖示的執行計劃。可以看到,SQL 中的每一個片段都能對應到執行計劃中的一個節點。
例如,SQL 的第一行 insert overwrite 操作在執行計劃中對應一個 TableModify 算子,第二行和第三行的 select 操作對應執行計劃中的 Project 算子。再向下是兩張表的 join 操作,該 join 操作對應 HashJoin 算子。join 之后,t1 和 t2 兩個子查詢是平級關系,join 的下一層有兩個平級的 Project。兩個子查詢內部在執行計劃中 f 分別對應 Project、Filter 和 TableScan 算子。TableScan 算子就對應查詢的底表信息。
拿到執行計劃后,按照前文實現原理中的第二步,基于 index 向下尋找。
以 DQL 部分為例:select a2 和 b2 對應執行計劃中的 Project 節點,它們最終插入的是 table3,因此對應的列信息是 table3 的 c1 和 c2。通過找到這一列對應的 index,逐層向下遞歸尋找。標黃的部分是基于 index 尋找鏈路的過程,逐層尋找,最終定位到最底層的 TableScan 節點。
經過尋找,我們發現 c1 底層列來源為 table1 的 a2 這一列,即構成血緣關系。c2 的血緣同理。
3. 基于策略的多樣化血緣提取能力
前面探討了血緣能力在底層的實現機制,通過該能力可以完成基礎的表和列級別的血緣提取,滿足大多數場景的需求。但為了滿足更多多樣化需求,我們團隊進一步開發了基于策略的多樣化血緣能力,并將其封裝成 SDK,以便各業務方能夠更便捷地使用。
以典型策略場景舉例子。
第一種場景為業務方不滿足于列級別的血緣追蹤,在離線數倉中,業務可能會遇到一些復雜類型的數據,如 Json、Map、Struct 等,這些復雜類型的數據可能包含更多的信息,需要復雜類型中 column key 級別的血緣追蹤。為此,我們特別設計了策略來支持復雜類型 column key 級別的血緣提取。例如,能夠追蹤到某個 JSON 字段的血緣來源于哪個 column 的哪個 key。
第二種場景為支持弱引用血緣的提取。在標準的列血緣追蹤中,抖音集團主要通過 select 鏈路來追蹤。但實際上,列不僅被用在 select 語句中,還可能被用在 where、group by、order by 等場景中。為了滿足這些場景的需求,血緣能力也支持提取以上場景的血緣,并將其統一歸結為弱引用血緣,以便下游靈活使用。
第三種場景是 UDF 定制化血緣。在一些特殊情況下,例如用戶使用了 if 表達式,如果 column1 大于 10,則返回 column2 的信息,否則返回 column3 的信息。在標準的列血緣追蹤中,最終結果列會依賴 column1、column2 和 column3 這三個列。但在某些特殊情況下,上游業務側可能希望更精確地追蹤數據來源。經過分析,我們發現 column1 在這個 SQL 中只作為判斷條件存在,其數據并不會作為真正的結果數據存儲到最終的數據表中。因此,血緣能力配置了特定的規則,可以對此類 UDF 進行定制化邏輯處理,從而忽略作用在條件位置的列,實現更精準的數據來源追蹤。
最后一種場景是支持統計列產出路徑上的計算關系。以下面的 SQL 為例:select column1, max(column2) from 一張表。在該 SQL 中,column1 沒有經過任何計算,直接作為結果返回,因此計算關系是 direct。而 column2 則經過了一些計算,因此計算關系是 expression。通過描述這種列的計算關系,可以為下游提供更多的執行時信息。
綜上所述,我們團隊開發了基于策略的多樣化血緣能力能夠滿足不同業務的定制化需求,為各業務方提供便捷化的使用方式。
三、血緣能力在數據發現場景的應用
上一章節主要闡述了 SQL 血緣的概念、實現方式,以及在 SQL 血緣基礎上所做的能力擴展。
接下來,將通過具體的業務場景,來展示這些能力擴展是如何在實際應用中落地的。
1. 基于血緣的標簽傳播能力
前文曾提到,離線數倉中存在著海量的 Hive 表信息,且其存儲規模還在持續擴大。為了實現對數據的精細化運營,首先需要對每一張 Hive 表乃至每一個 Hive 列都有深入的了解,并打上精確標簽。
面對可能達到百萬級、千萬級的信息量,如何為這些信息打上清晰的標簽成為了一個挑戰。為此,我們構建了一個全局標簽傳播系統。
該系統的整體思路分為以下三步:
- 第一步,提取所有的 SQL 任務。基于表/列級別的血緣能力,構建離線數倉的全局血緣關系圖,提供數據流轉的全局視角。
- 第二步,從一些信息明確的業務節點出發,這些節點包括用戶已經對其有明確感知的表和列。以這些節點為根基,逐層向下擴展,通過分析每一層的 SQL 語義,利用 SQL 語義進行標簽的傳播,從而完成全局標簽的擴展。
- 第三步,基于已經獲取的全局標簽信息,識別數據的使用情況及整體的流動鏈路。
綜上所述,構建全局標簽傳播系統,能夠有效地為海量 Hive 表及 Hive 列打上精確的標簽,進而實現對數據的精細化運營與管控。
下面從技術層面詳細闡述上述三步的具體實施方法。
2. 構造全局血緣圖
第一步,構建全局血緣圖。這一階段的首要任務是收集離線數倉中所有的 SQL 任務。得益于之前提到的 SQL 血緣提取能力,能夠對這些 SQL 任務進行血緣信息提取。
完成血緣信息的提取后,再將這些信息導入到一個圖數據庫中。在這個數據庫中,無論是表還是列,都被視為一個頂點。由于表和表之間、列和列之間,甚至表和列之間都存在依賴關系,因此它們之間會有邊進行連接。這些頂點和邊共同構成了一個全局的 Hive 資源血緣圖。
以右側給出的簡單示例為例,可以清晰地看到,在圖數據庫中,各個表和列通過邊相互連接,形成了一個完整的血緣關系網絡。這個全局血緣圖提供了離線數倉中數據流轉的直觀視圖,為后續的數據管理和運營奠定了堅實的基礎。
3. 逐層分析 SQL 語意
在已經獲取全局血緣圖信息的基礎上,接下來依據業務的初始標記點進行逐層擴散,以實現標簽的傳播。
這一過程具體分為以下幾個關鍵步驟。
首先,確定一個業務根節點,即業務上具有明確認知和清晰標簽的節點。其次,利用全局血緣圖,輕松獲取到該根節點所有的一級下游信息。再次,深入分析根節點與一級下游之間的 SQL 語義,從而確定一級下游的標簽情況。
以表的標簽傳播為例,假設 TableA 是業務根節點,帶有 APP 和 event 兩個標簽。當 TableA 的數據流轉到下游表時,根據 SQL 的語義來判斷標簽的變化情況。
比如,如果 TableA 到 TableB 的流轉過程中進行了裁剪和 filter 操作,即可基于該操作對標簽信息進行篩選和裁剪。因此,TableB 可能會繼承 TableA 的部分標簽,并且這些標簽的值可能會有所變化。
TableC 和 TableD 標簽也同理。在傳播過程中,需要根據每個 SQL 語句的具體操作來更新標簽的值。比如,TableC 可能只做了 APP 的過濾,所以 APP 標簽會有所變化,而 event 標簽則保持不變。而 TableD 如果是一個簡單的數據轉存操作,那么可能會繼承上游的全部標簽。
這樣的逐層分析和標簽傳播可以完成從業務根節點到其下游所有表的標簽傳播過程。這一方法不僅確保了標簽的準確性和一致性,還為后續的數據管理和運營提供了有力的支持。
4. 逐層傳遞標簽信息
繼續沿用之前的傳播規則,逐層地進行標簽傳播。這一傳播過程將持續進行,直到新一輪的傳播不再產生任何新的標記節點,這意味著已經到達了葉子節點,即下方已沒有更多的 Hive 表可以進一步標記。
當這一時刻到來時,所有標簽傳播工作便宣告完成。此時,全局中的所有 Hive 表都已被賦予了合適的標簽語義。
這些標簽的用途廣泛,不僅可以用于追蹤敏感資源的擴散情況,還可以作為元數據或注釋傳播的手段。使用標簽能夠更高效地管理和運營數據資源,確保數據的準確性和合規性。
5. 基于血緣的數據治理能力
接下來,將探討如何利用血緣關系來進行數據治理。
這一思路與之前的標簽傳播有相似之處,而標簽傳播能力在數據治理領域同樣也能發揮巨大作用。在傳統的數據治理場景中,離線側通常依賴于 HDFS 的訪問日志來實現數據治理。由于 Hive 表的數據最終存儲在 HDFS 上,通過分析 HDFS 的訪問日志來判斷哪些數據在一段時間內未被訪問,并據此進行表級別或分區級別的 TTL(Time To Live)治理,以降低存儲壓力。
然而,在實際開發過程中,我們發現即使某個分區正在被使用,也并非該分區的所有列都在被使用。Hive 表上的不同列,其生命周期可能是不同的。這就引發了一個新問題:如何為不同的列設置專屬的 TTL,從而減少列級的存儲成本?這成為了業務側的一個新痛點。
為了解決這個問題,抖音集團數據引擎研發團隊基于 Parquet 底層能力構建了一個名為“列級 TTL”的功能。這一功能可以為 Hive 表上的不同列配置專屬的 TTL,更精細地管理數據的生命周期,進一步降低存儲成本,并提高數據治理的效率。
在解決了不同列生命周期不同、需要配置列級 TTL 的技術難題后,依然面臨著一個新的產品問題:如何讓 Hive 表的 owner 能夠合理地設置每個列的生命周期,以降低使用成本。
為了解決該問題,我們引入了基于血緣的數據治理方案。該方案與之前的標簽傳播類似,依靠全局血緣圖來實施,但關注點從表層面轉移到了列層面,主要關注列的一級下游。
做法是采集每個列一級下游所有列級的最長分區使用范圍。例如,如果 ColumnA 有四個下游使用場景,分別是 ColumnB、ColumnC、ColumnD 和 ColumnE,我們會分析這些場景中使用的 SQL 語句,以確定 ColumnA 的最長分區使用范圍。
以 ColumnA 和 ColumnB 的鏈路為例,如果 SQL 語句每次都使用最近 20 天的數據來計算平均值,那么 ColumnA 到 ColumnB 的最長分區使用范圍就是 20 天。同樣地,ColumnA 的其它下游列也會計算出最長分區使用范圍。
以上信息收集起來后,可以為 ColumnA 提供一個合理的 TTL 推薦值。當然,這個推薦值只是基于數據使用情況的建議,用戶還可以根據自己的業務場景進行調整。
總之,以上方案是幫助用戶推薦一個合理的列級別 TTL 閾值,以降低用戶使用成本,降低存儲壓力。
四、血緣能力在數據保護場景的應用
前文介紹了血緣能力在數據發現以及數據治理等場景中的應用。
接下來將探討血緣能力在數據保護這一場景下的應用。
1. 基于血緣能力精細化提取 SQL 權限
(1)業務背景&整體思路
目前各公司在安全合規方面面臨巨大壓力,需要遵循數據權限最小化的原則來確保數據使用的規范性。
SQL 作為大數據分析場景中最簡單、最通用的語言之一,在離線場景中有廣泛應用。為了確保SQL場景中的權限使用規范和最小化,我們必須解決 SQL 權限精細化管控問題。
解決方案分為兩個層面:SQL 解析和權限管理。
在 SQL 解析層面,基于血緣能力定義了一套新的權限點提取規則,這套規則能夠完成細粒度的行列級別權限點提取。而在權限管理層面,我們支持了行列混合的權限管控,通過橫向和縱向權限點的捆綁組合,將用戶實際查詢的資源定位到行列重疊的資源單元格上,從而實現更細粒度的資源級別權限管控。
以抖音集團為例,用戶提交的 SQL 會首先被發送到統一的 SQL 處理引擎 ByteQuery 上。ByteQuery 是一個統一的 SQL 解析和優化引擎,它基于血緣能力能夠完成精準的 SQL 權限點提取邏輯。提取到的權限點信息會被發送到統一的權限管理服務進行鑒權。如果用戶有權限,SQL 會經過優化后發送到具體的執行引擎(如 Presto、Spark 等)執行;如果用戶沒有權限,則會返回給用戶提示缺少相應權限,并建議其完成對應的申請。
以具體的 SQL 查詢為例,如果用戶查詢的是“select name from db.table where ID=3”,從 SQL 視角來看,行業普遍的權限提取可能只涉及到表級別或列級別的權限。然而,通過深入分析用戶實際數據查詢的范圍,我們可以發現用戶實際查詢的是 name 列和 ID=3 的行所構成的資源方塊。因此,無論是表級別還是列級別的管控都顯得過于粗略,資源方塊級別的管控才是更優的方案。
為了實現這一目標,抖音集團的血緣能力在權限提取側支持了行列混合的權限提取,并在權限管控側支持了對資源方塊級別的權限管控。通過這種方法,能夠更精細地控制用戶對數據的訪問權限,確保數據的安全和合規性。
(2)權限提取方案
首先看看業界是如何處理權限提取問題的。以 Apache Hive 為例,在 SQL 解析的過程中會收集解析階段各階段的輸入(input)和輸出(output)信息。通過這些信息,Hive 能夠提取出 SQL 所使用的所有庫表信息,并將這些信息作為庫表的權限點。若需要更細致的控制,Hive 在優化過程中會在對應的 TableScan 節點上維護一個關聯列(reference column),這個關聯列記錄了 SQL 查詢所涉及的列信息。最終,這些信息被提取出來作為列權限使用。通過這種方法,能夠完成表權限或列權限的提取。
在我們的解決方案中,接收到用戶提交的 SQL 語句后,首先通過 ByteQuery 引擎進行解析和優化,將 SQL 轉化為執行計劃,這個過程在之前的介紹中已經提及,并展示在右側的圖中。接下來,我們根據特定的規則從該執行計劃中提取關注的特定節點。在獲取這些節點后,再利用表列級別的 SQL 血緣能力,確定節點在底層查詢中實際使用的行列信息,完成庫表行列級別的權限提取。
在上述權限點提取完成后,會進行權限點的組合與匹配,以確定最終的權限驗證范圍。這是一個總體的概念,接下來將從庫權限、庫表權限、列權限和行權限這三個層面,通過更復雜的 SQL 語句,來詳細介紹如何執行該過程。
本次舉例的 SQL 語句包含了一個子查詢 T1,由兩部分組成:table1 和 table2 的數據進行了 union 操作,之后將 union 的結果與另一個子查詢 T2 進行了 join 操作,最終生成了三個列。
(3)庫表權限提取思路
在第一部分中,主要任務是提取 SQL 中所有的庫表權限。
處理流程如下:首先,對 SQL 進行解析和優化。SQL 中對表的查詢操作會被映射成一個或多個 TableScan 節點。其次,遍歷執行計劃,完成所有 TableScan 節點的提取,由此輕松地獲取到所有被查詢的表的信息。
以右側的這個 SQL 為例,當它被轉化為執行計劃后,如圖所示,可以看到它包含了 3 個 TableScan 節點。通過采集這三個 TableScan 節點的具體信息,可以拿到庫表級別的權限需求,用于后續的權限驗證和授權過程。
(4)列權限提取思路
在列權限的提取過程中,首先需要定義明確的規則來確定哪些列需要進行權限驗證。目前,規則定義主要分為兩類:
- 返回列鑒權:對于 SQL 最終返回結果中的列信息,進行權限驗證。以右側的 SQL 為例,其最終返回結果包含三列數據,數據將直接展示給用戶,必須進行權限驗證。
- 過濾條件列鑒權:當過濾條件為兩個列相等時,可能存在通過特殊語法傳遞數據的情況,也需進行權限檢查。
基于上述規則,整體處理流程分為三步:
- 獲取返回列信息:從執行計劃的最外層算子中獲取所有列信息,這些信息代表 SQL 返回結果對應的列。
- 提取過濾條件:從執行計劃中提取所有的 Filter 條件,特別是那些表示兩個列相等的條件。以右側 SQL 為例,倒數第二行中的“T1.column1 = T2.C2”就符合這一條件,并提取出來。
- 利用血緣能力確定底表列信息:上一步提取出的列信息(如“T1.column1”)在語義上并不明確,我們無法直接知道具體代表哪個表、哪個列。基于血緣關系逐一處理上述提取的規則,就能確定每個列信息對應的底表列信息,并最終鑒別這些底表列的權限。
以右側 SQL 為例,首先,查看最外層算子持有列,如“T1.column1”,并確定它需要進行權限驗證。其次,基于血緣關系查看“T1.column1”的具體數據來源,最終定位到“T1.column1”的數據來源實際上是“table1.A1”和“table2.B1”。因此,針對“T1.column1”進行鑒別的權限應該是“table1.A1”和“table2.B1”的權限。同理,對其它列也采取相同的邏輯進行處理,最終完成所有列的權限提取。
(5)行權限提取思路
行權限的提取過程的思路與之前的列權限提取類似,主要的提取規則是關注過濾條件中列與常量相等的情況。
處理流程的前幾個階段與之前類似:
- 遍歷執行計劃:獲取執行計劃中所有的過濾條件信息。
- 獲取并分類過濾條件:在獲取到 Filter 條件后,并分類,特別關注那些列與常量相等的條件。以右側的 SQL 為例,其最下面一行的“T1.column2 = 張三”就是一個列與常量相等的條件,滿足提取規則。
- 依靠血緣信息確定底表列:通過血緣關系,確定“T1.column2”實際上對應的底表列信息,并針對此列進行行權限的鑒別。
對于其它類型的過濾條件,也有相應的處理策略:
- 兩個列相等:這種情況在列權限提取規則中已經覆蓋,會按照列權限的規則進行處理。
- 常量和常量相等:這種情況不涉及到任何權限校驗,因為在 SQL 優化階段,這種無意義的比較通常會被優化掉。
以右側的 SQL 為例,提取其所有的 Filter 信息,并追蹤列的血緣關系,最終提取到的行權限信息如上圖所示。
接下來對以上提取的權限信息進行整合與組合,以便更清晰地了解每個查詢所涉及的具體資源。
以右側這個 SQL 為例,在 table1 上,它實際查詢的列是 A1 和 A2,而查詢的行則滿足“dt = 20230101”和“A2=zhangsan”這兩個條件。同理,對于 table2 和 table3,我們也會基于上述信息完成橫向和縱向的權限信息提取。
將這些信息映射到右側的表里(假設第一張表是 table1,第二張表是 table2,第三張表是 table3,且它們分別有 A1、A2、A3、A4、A5 等列),通過橫向和縱向的組合劃分,可以將檢索的資源精確地定位到行列交錯的標注黃色的資源方塊上。
這一步驟標志著,在權限提取側完成了最細粒度的權限提取,即資源方塊級別的權限提取。這為后續的權限管控奠定了堅實的基礎。然而,值得注意的是,權限提取只是權限管控的一部分,只有與權限管控策略相結合,才能確保數據的安全性和合規性。
2. 血緣能力在動態脫敏場景下的應用
動態脫敏是保障數據安全的重要手段,它能在數據展示或傳輸過程中,對數據進行實時的脫敏處理,以保護隱私數據的安全。
這種能力主要有兩種實現時機:計算前脫敏和計算后脫敏。
- 計算前脫敏:當計算引擎讀取到敏感數據時,會立即對其進行脫敏處理。這種方式相對簡單,但它更接近于存儲層加密。因為一旦數據被脫敏,它就已經變成了密文,這可能會影響后續的 SQL 查詢邏輯,如 Join、Filter 或 UDF 計算等。因此,計算前脫敏可能會對用戶的 SQL 使用產生較大影響。
- 計算后脫敏:與此相反,計算后脫敏是在計算引擎讀取到敏感數據后,優先執行后續計算,而在最終返回結果前再進行脫敏處理。這種方式實現起來更復雜,因為它需要對最終結果進行脫敏,而最終結果已經沒有直接的數據來源信息。為了實現這一點,我們需要基于 SQL 分析數據走向,追蹤數據來源,才能做出是否需要脫敏的判斷。計算后脫敏的優點在于它對用戶的影響較小,因為它并沒有打破用戶對 SQL 的語義理解,仍然完成了合理的計算后才對結果做脫敏處理。
在技術實現上,無論采用哪種脫敏時機,都需要首先解析和優化用戶的 SQL,將其轉化為執行計劃信息,再讀取用戶查詢的表,檢查表中是否配置了脫敏規則。基于脫敏配置信息來動態地改寫執行計劃,并在適當的位置插入脫敏算子。
接下來,將詳細介紹動態脫敏在兩個具體場景中的實現方式。
- 計算前脫敏場景:
在計算前脫敏的場景中,脫敏操作被直接插入到 TableScan 節點之前。由于能夠直接獲取到 Hive 表的信息,我們可以輕易地判斷哪些列需要進行脫敏處理。以某個 SQL 查詢為例,如果我們在讀取 table1 的 A2 列時,發現其源數據配置被標記為敏感數據,需要脫敏,那么我們可以在 A2 列對應的 TableScan 算子之上,固定下標位置插入一個 Masking 脫敏算子。這樣,后續的 Filter、Join 等計算操作都會基于脫敏后的數據進行處理,從而輕松實現動態脫敏。
- 計算后脫敏場景:
與計算前脫敏不同,計算后脫敏需要將脫敏操作放置在查詢的最外層算子處。此時,脫敏操作已經遠離了標識 Hive 表信息的 TableScan 節點。以某個包含 C1、C2 兩列的 SQL 查詢為例,我們可能無法直接判斷這兩列是否需要脫敏。為了解決這個問題,我們需要基于血緣信息來追蹤每一層的計算鏈路,并根據計算鏈路來判斷哪些列需要脫敏處理。
這個追蹤過程與前面提到的血緣追蹤類似,如果我們基于血緣判斷鏈路發現某列需要脫敏,就會在最外層對應的位置插入一個脫敏算子;如果不需要脫敏,則直接返回原始列。
如果 DB.table1 中的某列(標綠色)是敏感數據,操作步驟為拿到最外層算子,逐層追蹤該列的血緣信息。綠色的框表示追蹤范圍,最終發現 C1 的來源是 A2,且該鏈路上需要脫敏。因此,在 C1 之上插入一個 masking 脫敏算子。而對于 C2 列,如果在追蹤過程中發現其底表的依賴是非敏感資源,則不需要進行任何脫敏處理,直接返回原始列即可。
通過這種方式,我們可以在對用戶 SQL 語義影響更小的場景下,同時完成對敏感數據的保護。這種動態脫敏的實現方式既靈活又有效,能夠根據不同的業務場景和需求進行適應性調整。