隨著數(shù)據(jù)集規(guī)模的不斷擴大,采用 Amazon S3 和谷歌云存儲( GCS )等云存儲平臺變得越來越流行。盡管節(jié)點本地存儲可能會帶來更好的 IO 性能,但在數(shù)據(jù)集超過單 TB 規(guī)模后,這種方法可能變得不切實際。
在遠程存儲是唯一實用的解決方案的情況下, PyData 生態(tài)系統(tǒng)的許多部分已經(jīng)采用文件系統(tǒng)規(guī)范(fsspec)作為通用文件系統(tǒng) API 。自從s3fs和gcsfs推出以來,fsspec已經(jīng)為用戶提供了足夠的遠程存儲訪問權(quán)限,但內(nèi)部字節(jié)傳輸和緩存算法還沒有對拼花等高性能文件格式進行特定于格式的優(yōu)化。
關(guān)鍵教訓(xùn)
在本文中,我們將介紹fsspec.parquet模塊,它為遠程拼花文件提供了一種支持格式的字節(jié)緩存優(yōu)化。這個模塊是實驗性的,并且僅限于一個公共 API :open_parquet_file。
此 API 提供了更快的遠程文件訪問。與 cuDF 和 cuDF 數(shù)據(jù)幀庫中的默認read_parquet行為相比,對于大型拼花地板文件的部分 I / O (列塊和行組選擇),整體吞吐量有了一致的性能提升。
我們還討論了這個新模塊中使用的優(yōu)化,并給出了初步的性能結(jié)果。
什么是 fsspec ?
文件系統(tǒng)規(guī)范(fsspec)是一個開源項目,為各種后端存儲系統(tǒng)提供統(tǒng)一的 Python 接口。fsspec對應(yīng)于一個特定的fsspec Python 庫和一個更大的 GitHub 組織,其中包含許多特定于系統(tǒng)的存儲庫(例如s3fs和gcsfs)。
在基于 Python 的庫或應(yīng)用程序中使用fsspec的優(yōu)點是,類似于 POSIX 的文件 API 可以從遠程對象和本地文件進行讀寫。當(dāng)一個基于云的對象被一個fsspec兼容的文件系統(tǒng)打開時,底層應(yīng)用程序會得到一個AbstractBufferedFile對象,或者其他一些類似文件的對象,這些對象被設(shè)計為使用原生 Python 文件對象進行 duck type 操作。現(xiàn)在,這些類似文件的對象可以像本地 Python 文件句柄一樣處理。
一個明顯的區(qū)別是AbstractBufferedFile對象必須在內(nèi)部使用特定于文件系統(tǒng)的命令,以便向遠程存儲系統(tǒng)輸入和從遠程存儲系統(tǒng)獲取字節(jié)。由于內(nèi)部數(shù)據(jù)傳輸操作的延遲通常高于本地磁盤訪問,fsspec提供了幾種緩存策略來預(yù)取數(shù)據(jù),同時避免了許多小請求。
在這篇文章的后面,我們將解釋為什么對于大型拼花地板文件,默認緩存策略通常不太理想,以及新的KnownPartsOfAFile(“部件”)選項如何顯著減少讀取延遲。
什么是拼花地板?
Parquet 是一種面向二進制列的數(shù)據(jù)存儲格式,設(shè)計時考慮了性能、壓縮和部分 I / O 。由于與 CSV 等文本格式文件相比具有顯著的性能優(yōu)勢,自 2013 年首次發(fā)布以來,開源格式的受歡迎程度迅速增長。
為了理解 Fsspec 拼花地板模塊中使用的優(yōu)化,對拼花地板規(guī)范有一個高層次的理解是很有用的。圖 1 顯示,所有拼花文件都由一組連續(xù)存儲的行組組成,而這些行組中的每一個都包括一組連續(xù)存儲的列塊。
圖 1 拼花地板文件格式的高級視覺表示
總之,拼花地板文件中的大部分字節(jié)都對應(yīng)于這些列塊。剩余的字節(jié)用于將文件元數(shù)據(jù)存儲在舊格式的頁腳中。此頁腳元數(shù)據(jù)包括文件中每個列塊的字節(jié)偏移量和可選統(tǒng)計信息(min、max、valid count、null count)。
由于這些重要信息整合在頁腳中,因此只需對拼花地板文件的結(jié)尾進行采樣,即可確定文件中每個列塊的具體位置。
fsspec 新拼花模塊的用途是什么?
fsspec已經(jīng)是 Python 下加載拼花地板文件的最常用方法。新fsspec.parquet模塊的主要目的是為這項任務(wù)提供優(yōu)化的實用程序。
在內(nèi)部,這個新的實用程序(open_parquet_file)基本上將一個傳統(tǒng)的開放調(diào)用封裝在特定于拼花地板的邏輯中,該邏輯設(shè)計用于在用戶啟動顯式讀取操作之前,開始將所有相關(guān)數(shù)據(jù)從遠程文件傳輸?shù)奖镜貎?nèi)存。
盡管任何大小的讀取都可能受益于此新實用程序,但當(dāng)讀取操作僅針對所有列和行組的子集時,可以看到最顯著的改進。例如,當(dāng)遠程讀取使用列投影時,相同的列列表可以直接傳遞給open_parquet_file:
from fsspec.parquet import open_parquet_file import pandas as pd path = “
如前所述,fsspec新open_parquet_file函數(shù)的主要目的是通過在AbstractBufferedFile.open中使用支持格式的緩存策略,提高大型拼花地板文件的讀取性能。
要理解拼花地板模塊使用的特定優(yōu)化為什么是有益的,首先了解簡單的無緩存方法以及默認的預(yù)讀策略是有幫助的。
了解無緩存和預(yù)讀方法
圖 2 顯示了對于 naive 和 naive 讀調(diào)用序列,無緩存文件訪問可能如何映射到read_parquet操作中的遠程 get 調(diào)用(在遠程文件已經(jīng)打開之后)。
圖 2 從遠程拼花文件比較理想和原始數(shù)據(jù)訪問模式
在這個特定的示例中,假設(shè)拼花文件足夠大(~ 400MB +)以包含四個不同的行組,read_parquet調(diào)用的目標是四個可用列中的兩個。這意味著AbstractBufferedFile對象最終必須將八個不同的列塊范圍以及頁腳元數(shù)據(jù)傳輸?shù)奖镜貎?nèi)存中。
在禁用緩存的情況下,經(jīng)過良好調(diào)整的拼花地板庫可以使用五個不同的請求僅將必要的數(shù)據(jù)移動到本地內(nèi)存中。然而,由于fsspec的類文件接口包含state,這五個讀取調(diào)用始終是串行的,每次調(diào)用都會產(chǎn)生一整段延遲時間。
這種 ideal-access 場景無法利用并發(fā)性來最小化延遲,即使該策略可能會最小化文件系統(tǒng)請求的數(shù)量并產(chǎn)生高的總體吞吐量。對于采用 naive-access 方法且未明確最小化讀取調(diào)用數(shù)的拼花地板庫,read_parquet操作可能會出現(xiàn)高延遲和低總體吞吐量!
此時,我們已經(jīng)確定,在文件已經(jīng)打開進行讀取之后, I / O 庫無法利用文件系統(tǒng)的并發(fā)性。更重要的是,當(dāng)涉及部分 I / O 時,默認的預(yù)讀緩存策略可能會進一步降低觀察到的性能。這是因為預(yù)讀緩存的固有假設(shè)是,順序文件訪問可能是連續(xù)的。
Figure 3 shows that read-ahead caching is likely to transfer about 20 MB of unnecessary data, 5 MB of read-ahead for each row-group.
圖 3 中預(yù)讀和無緩存文件訪問策略的比較 fsspec
正如您在以下性能結(jié)果中看到的,禁用緩存優(yōu)于預(yù)讀緩存的好處取決于read_parquet中使用的引擎和特定的存儲系統(tǒng)。
如果引擎已經(jīng)包含了支持格式的優(yōu)化,可以將必要的字節(jié)范圍移動到本地內(nèi)存中(即pyarrow和fastparquet),那么無緩存選項可能是更好的選擇。當(dāng)引擎假定本地文件訪問速度很快( cuDF )時,某種形式的fsspec級緩存可能非常關(guān)鍵。
在這兩種情況下,引擎都無法開始傳輸所需的字節(jié)范圍,直到創(chuàng)建fsspec文件對象之后。它受到順序數(shù)據(jù)傳輸附加延遲的限制。
現(xiàn)在,我們已經(jīng)對典型的 read _ parquet 調(diào)用中的默認和無緩存 AbstractBufferedFile 行為有了較高的理解,現(xiàn)在我們可以解釋open_parquet_file為提高總體讀取吞吐量而使用的兩種通用優(yōu)化。
優(yōu)化 1 :使用“部件”緩存策略
默認情況下,與AbstractBufferedFile中使用的格式無關(guān)的緩存策略不同,您可以使用新的KnownPartsOfAFile(“部件”)選項在文件打開之前精確緩存所需內(nèi)容。
from fsspec.parquet import open_parquet_file import pandas as pd path = “://my-bucket/my-data” columns = [“col1”, “col2”] options = {“necessary”: ”credentials”} with open_parquet_file( path, columns=columns, storage_options=options, ) as f: df = pd.read_parquet(path, columns=columns)
圖 4 顯示,用于訪問read_parquet中數(shù)據(jù)的邏輯與用于遠程數(shù)據(jù)訪問的get調(diào)用的數(shù)量或大小之間不再存在任何關(guān)系。從拼花引擎的角度來看,任何讀取操作幾乎都是瞬時的,因為所有必需的數(shù)據(jù)都已緩存在內(nèi)存中。
圖 4 這個 fsspec 的“部件”緩存策略。在打開類似文件的對象之前,所有必要的數(shù)據(jù)都必須緩存在本地內(nèi)存中。
優(yōu)化 2 :異步并行傳輸“部件”
盡管之前的優(yōu)化使您能夠避免read_parquet中的許多小型 get 操作和不必要的數(shù)據(jù)傳輸,但在初始化AbstractBufferedFile之前,您仍然必須填充KnownPArtsOfAFile緩存。
為了盡可能高效地執(zhí)行此操作,請使用cat_ranges一次性獲取所有必需的列塊,包括異步獲取和使用asyncio并行獲取。因為對于包含多個字段或多個行組的文件,傳輸?shù)牧袎K的總數(shù)可能很大,所以只要聚合的請求的大小保持在上限以下,就可以聚合相鄰的字節(jié)范圍請求。
圖 5 顯示,這種方法最終會導(dǎo)致并發(fā)傳輸多個字節(jié)范圍的最佳大小。
圖 5中使用的數(shù)據(jù)傳輸優(yōu)化 fsspec.parquet
初步 fsspec 。拼花地板基準測試結(jié)果
要將open_parquet_file的性能與其他基于fsspec和pyarrow的文件處理方法進行比較,請使用 可用 Python 腳本 :
pyarrow-6.0.1
fastparquet-0.8.0
cudf-22.04
fsspec/s3fs/gcfs-2022.2.0
使用這個腳本,我們從一個 789M 的拼花地板文件中讀取一列,該文件共包含 10 個行組和 30 個列,具有快速壓縮,需要傳輸大約 27M 的數(shù)據(jù)。圖 6-7 中總結(jié)的 S3 和 GCS 的結(jié)果清楚地表明,當(dāng)從默認緩存策略轉(zhuǎn)向open_parquet_file時,性能顯著提升 85% 或更高。
事實上,新功能有效地匹配了 PyArrow 的原生S3FileSystem實現(xiàn)的性能,該實現(xiàn)是專門為其鑲木地板引擎的最佳性能而設(shè)計的。在本文中,我們僅將其與 Amazon S3 基準測試的本機 PyArrow 文件系統(tǒng)進行比較,因為 PyArrow 在發(fā)布時僅提供 Amazon S3 和 Hadoop 的公共支持實現(xiàn)。
圖 6 S3 存儲的一般基準測試結(jié)果
圖 7 GCS 存儲的一般基準測試結(jié)果
為了說明使用open_parquet_file縮放文件的好處,我們還從一個 12 GB 的拼花地板文件中讀取了一列,其中包含禁用壓縮的公共 GCS 存儲中 Criteo 數(shù)據(jù)集的第一天。圖 8 顯示,新的fsspec函數(shù)可以提供比默認緩存 10 倍或更多的加速。
圖 8 地面軍事系統(tǒng)存儲的 Criteo 數(shù)據(jù)集基準測試結(jié)果
自己測試一下
在本文中,我們介紹了fsspec.parquet模塊,它為打開遠程拼花文件open_parquet_file提供了一種支持格式的字節(jié)緩存優(yōu)化。基準測試清楚地表明,與fsspec中的默認文件打開行為相比,新的優(yōu)化可以提供顯著的性能改進,甚至可以接近 PyArrow 中針對部分 I / O 的優(yōu)化 C ++文件系統(tǒng)實現(xiàn)的性能。
自從在 2021.11.0 版本的 fsspec 中正式發(fā)布以來,open_parquet_file實用程序已經(jīng)被 RAPIDS cuDF 庫和 Dask -Dataframe 采用。
由于基于 cuDF 的工作流得到了顯著且一致的改進,此新功能已被cudf.read_parquet和dask_cudf.read_parquet采用為默認的文件打開方法。
對于沒有 GPU 資源的 Dask 用戶,現(xiàn)在可以通過向read_parquet傳遞open_file_options參數(shù)來選擇優(yōu)化的緩存方法。例如,以下代碼示例指示 Dask 使用parquet預(yù)緩存方法打開所有拼花地板數(shù)據(jù)文件:
import dask.dataframe as dd ddf = dd.read_parquet( path, open_file_options={“precache_options”: {“method”: “parquet”}}
)
鑒于這一早期的成功,我們希望擴展和簡化fsspec中可用的預(yù)緩存選項,并在所有文件打開函數(shù)中建立一個清晰的 precache_options API 。
關(guān)于作者
Rick Zamora 是 NVIDIA 在 RAPIDS 和 Dask 工作的高級軟件工程師。他有科學(xué)計算研究和并行軟件開發(fā)的背景。杜蘭特博士在牛津大學(xué)學(xué)習(xí)物理學(xué),在多倫多學(xué)習(xí)天體物理學(xué)。他在多個波長和廣泛的時間尺度上研究了脈沖星和其他緊湊型物體系統(tǒng)。
審核編輯:郭婷
-
接口
+關(guān)注
關(guān)注
33文章
8675瀏覽量
151556 -
API
+關(guān)注
關(guān)注
2文章
1508瀏覽量
62227 -
python
+關(guān)注
關(guān)注
56文章
4802瀏覽量
84889
發(fā)布評論請先 登錄
相關(guān)推薦
評論