線上使用者反饋使用presto查詢hudi表出現錯誤,而將hudi表的檔案單獨建立parquet型別表時查詢無任何問題,關鍵報錯資訊如下
40931f6e-3422-4ffd-a692-6c70f75c9380-0_0-384-2545_20200513165135.parquet, start=0, length=67108864, filesize=67108864, hosts=, forcelocalscheduling=false, partitionname=dt=2020-05-08, s3selectpushdownenabled=false} (start = 2.3651547291593433e10, wall = 163 ms, cpu = 0 ms, wait = 0 ms, calls = 1): hive_bad_data: not valid parquet file:
報hudi表中檔案格式不是合法的parquet格式錯誤。
開始根據使用者提供的資訊,模擬線上hudi資料集大小、presto和hudi版本(0.5.2-incubating)來復現該問題。
進行試驗發現當hudi表單檔案大小較小時,使用presto查詢一切正常。
構建hudi表中單檔案大小為100mb以上資料集,使用presto查詢。
可以看到,當hudi資料集中檔案大小為100mb時復現了not valid parquet file異常,通過presto的web ui可以看到具體的錯誤堆疊如下
通過錯誤堆疊可以進一步確認在讀取parquet檔案時校驗失敗,開始懷疑parquet檔案確實被損壞,但使用parquet-tools工具檢查本地parquet檔案,發現無問題。
經過上述步驟復現了問題,問題能夠復現就好排查。但presto對於合法parquet檔案檢查為何會報錯?帶著這個疑問開始在本地debug presto,首先在presto服務端和idea中進行相應的配置。
要想能夠連線到presto服務端,需要在presto_home根目錄下建立etc
目錄,然後建立jvm.properties
檔案,內容如下
-server
-xmx8g
-xx:+useg1gc
-xx:g1heapregionsize=32m
-xx:+usegcoverheadlimit
-xx:+explicitgcinvokesconcurrent
-xx:+heapdumponoutofmemoryerror
-xx:+exitonoutofmemoryerror
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
-xx:+traceclassloading
-xx:+traceclassunloading
-verbose:class
上述配置除了可以連線服務端進行debug外,新增的-xx:+traceclassloading
、-xx:+traceclassunloading
兩個配置項,還會列印每個類載入和解除安裝的日誌(這個在排查presto類載入器問題時非常有用,建議開啟)。
配置完presto服務端後,在idea進行如下配置即可。
idea中開啟了debug後,通過presto客戶端查詢時(select * from hudi_big_table
),就可以進行單步除錯,首先我們在backgroundhivesplitloader
類中打了些斷點(該類是載入split的關鍵類)。
通過shouldusefilesplitsfrominputformat
方法判斷是否直接通過註解(@usefilesplitsfrominputformat
)獲取filesplit。hudi與外部系統互動的hoodieparquetinputformat
和hoodieparquetrealtimeinputformat
兩個類都使用了該註解。
從上圖可以看到100mb的檔案被分成了四個inputsplit(按照32mb大小進行切分),後續presto會根據inputsplit
來構造對應的internalhivesplit
。
進一步在異常堆疊地方打斷點如下
根據上述**邏輯可知,從檔案中讀取magic與parquet檔案的magic不相等導致丟擲了異常。
值得注意的是filesize的大小為33554432
,表示乙個inputsplit的大小,而並非檔案大小,因此獲取metadatalength
時並不準確,導致並非讀取了parquet檔案的magic,而是讀取了inputsplit的資料,因此校驗時丟擲異常。理論上對於不同的inputsplit,該方法傳入的filesize大小應該等於檔案的大小,而非inputsplit的大小,那麼這個filesize的大小是在哪個步驟傳遞錯誤的呢?帶著這個疑問,繼續進行debug。
根據前面debug資訊得知presto會通過inputsplit
建立internalhivesplit
,繼續debug生成internalhivesplit
的邏輯
可以看到在上面構造internalhivesplit
時,傳遞的引數值為start=0、start + length=33554432,length=33554432,而internalhivesplit
本身的引數對應為start、end、filesize,可以看到錯誤地將length當成filesize傳遞了。
既然懷疑這個引數傳遞錯誤導致了異常,那麼修改引數為filesize後是否可以修復該問題?於是打包驗證觀察異常是否還會出現,即對presto-hive模組重新打包,放入$presto_home/plugin/presto-hive目錄中,重啟presto服務,再次進行驗證。
可以看到修改引數後,查詢一切正常!!!
另外對hudi的小檔案也進行了回歸測試,查詢也正常!自此可以發現是由於引數不對的bug導致了異常,鑑於這個bug對presto社群其他使用者也可能產生影響,於是檢視presto的master分支是否修復了該問題,若未修復,可將該patch回推到社群,於是檢視了presto的master分支對應**,發現已經有開發者修復了!
找到對應的pr:也僅僅只是修改了上述的一行**),在4月7號合入master分支,從這個pr得知,該bug是由引入。
由於該缺陷是在2023年5月引入presto社群,在2023年4月得以修復,期間發布的版本(0.221 ~ 0.235)都會受到影響,如本地測試0.227、0.231版本都有問題。最近社群發布了0.236版本修復了該問題,如果生產環境使用的版本在0.221 ~ 0.235之間,建議公升級或者cherry-pick對應的patch。
根據線上使用者反饋查詢hudi表問題,由於線上環境不好debug,需根據上線環境在本地模擬復現問題,然後快速debug排查修復問題。當然本篇文章省略了debug的旁路路徑,只給出了debug的關鍵路徑。
Presto踩坑筆記
1,連oracle的問題 presto社群 之後,官方版目前不支援oracle connector,社群版支援,但是由於中文的問題 failed non supported character set add orai18n.jar in your classpath zhs16gbk 把orai1...
記錄線上presto集群崩潰
公司線上presto集群在週末有大量的任務失敗,檢視了下機群的負載,除了coordinator,所有worker的cpu和記憶體基本上都耗盡了,檢視日誌,出現了很多worker節點被下線的情況,檢視jvn程序,出現了很多次full gc,而且時間非常長 首先我們判斷是不是網路問題,因為我們這邊的資料...
Presto查詢優化
合理設定分割槽 與hive類似,presto會根據元資訊讀取分割槽資料,合理的分割槽能減少presto資料讀取量,提公升查詢效能。使用列式儲存 presto對orc檔案讀取做了特定優化,因此在hive中建立presto使用的表時,建議採用orc格式儲存。相對於parquet,presto對orc支援...