• <xmp id="om0om">
  • <table id="om0om"><noscript id="om0om"></noscript></table>
  • 數據科學

    使用 GPU 在 Apache Spark 上加速 JSON 處理

    JSON 是一種熱門的文本數據格式,可實現 Web 應用程序中系統之間的互操作性以及數據管理。這種格式自 21 世紀初就已存在,源于 Web 服務器和瀏覽器之間的通信需求。標準 JSON 格式由可包含嵌套對象的鍵值對組成。JSON 在存儲 Web 事務信息方面的使用有所增長,并且可能包含非常大的值,有時每條記錄的大小超過 1 GB。首先,解析和驗證 JSON 不是與 GPU 加速相關的任務,因為文本格式的大小不規則,并且沒有默認順序。但是,隨著 JSON 在許多企業數據應用程序中的使用,對加速的需求也在增長。

    對于《財富》100 強零售公司而言,使用 JSON 格式存儲基本庫存數據。JSON 格式支持與產品分類和庫存相關的非結構化數據。針對點擊流數據的 JSON 處理包括在單個 Spark 工作負載中處理數十 TB 的 JSON 數據的大型查詢。

    GPU 加速助力零售商的生產

    當應用于在 GPU 上運行的生產工作負載時,結果對零售商來說非常明顯。GPU 運行時間從 16.7 小時縮短到 3.8 小時,與生產環境中類似的 CPU 集群相比,GPU 運行速度提高了 4 倍,并節省了 80% 的成本。

    集群中的節點是 GCP n1-standard-16 實例,每個節點都附加了一個 NVIDIA T4 GPU。

    GPU acceleration of JSON string processing comparing CPU to GPU showed over 4x improvement on a retailer workload. This production measurement is performed using GCP n1-standard-16 instances with a single T4 attached to each node.
    圖 1、適用于零售商工作負載的 GPU 加速。 此生產測量使用 GCP n1-standard-16 實例執行,每個節點附加一個 NVIDIA T4 GPU。

    Spark 的 get_json_object 函數

    自 22.02 版本發布以來,用于 Apache Spark 的 RAPIDS 加速器就一直存在針對 JSON 的 GPU 處理,但在加速處理方面存在挑戰。在與零售商合作時,使用 Spark 的 get_json_object function 處理 JSON 記錄的特定操作需要在 SQL 查詢中動態解析 JSON。JSON 格式允許使用層次結構嵌入對象,例如數組:

    JSON flow diagram showing how an object proceeds with whitespace and separates its value with a colon.  Additional objects are separated by a comma and closed with a curly brace.
    圖 2、JSON 對象和數組格式 (參考: https://www.json.org/json-en.html )

    get_json_object 函數的目的是根據所提供的路徑從 JSON 記錄字符串中提取物體。這是一個簡單的 SQL 查詢示例,其中 get_json_object 函數用于提取嵌套元素:

    SELECT get_json_object('[{"a":"b1"}, {"a":"b2"}]', '$[*].a')
    ["b1","b2"]

    在實際用例中,該函數允許選擇 JSON 記錄中與 ETL 工作流中的其他處理相關的嵌套對象。

    JSON 中大型字符串的挑戰

    在零售商工作負載中,使用中等寬度的輸出表時,單個 SQL 查詢語句可能會導致 get_json_object 函數被調用多達 50 次。字符串本身平均長度為多個 KiB。當您將調用頻率與長 JSON 字符串相加時,GPU 在處理數據時可能會面臨巨大的內存壓力。尤其是對 GPU 的 L1 緩存。GPU 上的初始實施將在 GPU 上并行處理每條記錄,以在默認情況下使用每線程記錄來加速處理。這導致 L1 緩存嘗試保存多個記錄,最終導致緩存崩潰。此外,如果線程塊內的線程發散,處理時間會減慢,因為線程塊將在需要處理發散線程時暫停其他線程。測試 30 TB 工作負載的原始結果是,在 CPU 集群上運行 16 小時,在類似的 GPU 集群上運行 16.7 小時。

    JSON path query mapped to data across thread blocks that run on the GPU. A single kernel would handle each JSON path query.
    圖 3. 每個 JSON 路徑查詢的單個內核

    在深入了解零售商的查詢和數據集時,我們發現數據包含 JSON 對象內的稀疏字段。這意味著,給定記錄中出現字段的概率非常低;具體而言,超過 85% 的字段在不到 0.01% 的記錄中出現。由于線程稀疏,在處理過程中線程很可能會在早期出現偏差。理想情況下,同一 warp 中的一組給定線程會運行所處理的類似數據。

    CUDA 編程指南 中:

    線程束一次執行一條通用指令,因此當線程束的所有 32 個線程在其執行路徑上保持一致時,即可實現充分的效率。如果線程束的線程通過依賴數據的條件分支發散,則該線程束會執行所采用的每個分支路徑,從而禁用不在該路徑上的線程。分支發散僅發生在線程束內;不同的線程束獨立執行,而不管它們執行的是公共代碼路徑還是不交接代碼路徑。

    最初,GPU 在處理零售商查詢中頻繁的 get_json_object 調用時速度緩慢,這一點已得到確認,原因是線程發散,因此開始了優化此類處理的工作。

    改進 GPU 上的 JSON 處理

    為了解決使用大字符串(尤其是稀疏數據)優化 JSON 處理的問題,我們必須改進在線程束中處理數據的方式,以提高線程處理類似數據的概率。為了提升性能,我們經歷了連續優化的過程,以幫助零售商加速工作負載。

    為了提供驗證優化的測試環境,我們執行了單節點基準測試,以演示優化工作的效果。本地基準測試環境包括具有 32 核 (CPU) 的 AMD Ryzen Threadripper PRO 5975WX 和 NVIDIA RTX A6000 48GB (GPU)。用于基準測試的數據是 5 列 20 萬行生成的 JSON 數據,這些數據基于零售商的 JSON 數據的近似值。未壓縮的基準測試數據約為 9.2 GB,使用 snappy 壓縮存儲為 Parquet 時約為 6.4 GB。請注意,由于大部分數據是隨機生成的,因此壓縮比非常低。get_json_object 調用的次數從每列一次到 50 多次不等。數據和路徑都很復雜,嵌套級別超過 10,并且使用數組索引和通配符。

    在使用 NVIDIA GPU(代表零售商使用的 GPU)的單節點上,使用大字符串生成的 JSON 數據的基準測試從最初略快于 CPU 處理,經過一系列優化后,速度提高了 5 倍以上。

    JSON data mapped across thread blocks that run on the GPU.  A single kernel would handle each data grouping.
    圖 4. 每個線程塊的單個內核數據

    應用的第一種技術是在同一線程束中針對相同數據合并多個查詢。如果在不同線程的字段中查詢大型記錄,我們可以刻意將它們分組到同一線程束中,以平衡線程差異并減輕緩存壓力。這有助于將我們的本地基準提高 3.2 倍,因此我們已經取得了巨大的勝利。

    JSON sorted data mapped across thread blocks that run on the GPU.  A single kernel would handle each sorted data grouping.
    圖 5、每個線程塊的單個內核數據 (sorted)

    但是,我們注意到,當跨線程束的 SQL 查詢中對同一 JSON 路徑進行后續查詢時,仍可能出現線程發散。這促使我們對查詢進行詞法分類。這有助于進一步減少線程發散,因為查詢在同一線程束內具有更高的相似性。實施該優化后,本地基準測試又提高了 10%,速度提高了 3.6 倍。

    最后,我們已開始利用 RAPIDS cuDF 庫中更具數據并行性的標記器,從而擺脫單字符解析,在處理 JSON 對象時實現多樣化的字符串解析。基準測試表明,此優化性能再提升 50%,整體速度提升了 5.6 倍。實施方案將于今年發布。

    GPU acceleration of JSON string processing comparing CPU to GPU showed over 5x improvement on local benchmarks with successive optimizations.
    圖 6、GPU 加速的 JSON 字符串處理

    要點

    處理大量字符串數據對 GPU 來說可能是一項挑戰,因此需要進行特殊優化。適用于 Apache Spark 的 RAPIDS 加速器與 cuDF 一起增強了 JSON 處理,從而提高了 GPU 上的速度。

    開始在 GPU 上使用 Apache Spark

    企業可以利用適用于 Apache Spark 的 RAPIDS 加速器,將現有的 Spark 工作負載無縫過渡到 NVIDIA GPUs,且無需更改代碼。適用于 Apache Spark 的 RAPIDS 加速器將 cuDF 的強大功能與 Spark 分布式計算框架的規模相結合,利用 GPU 加速處理。

    通過 此 Colab Notebook 親身體驗 JSON 處理和適用于 Apache Spark 的 RAPIDS 加速器,并查看即將舉行的 GTC 2025 會議 以了解詳情。

    未來工作

    我們還計劃針對 GPU 上的字符串處理進行其他優化,以便將用于加速 JSON 的類似技術用于更多表達式和功能。

    如要跟進或幫助做出貢獻,請查看適用于 Apache Spark 的 RAPIDS Accelerator cuDF 的開源作品。

    ?

    0

    標簽

    人人超碰97caoporen国产