[英]Can a speculative task continue running shortly after a Spark job returned?
我的一個簡單Spark作業遇到了問題,經過簡化后看起來像這樣。
JavaRDD<ObjectNode> rdd = pullAndProcessData();
ManifestFilesystem fs = getOutputFS();
List<WriteObjectResult> writeObjectResults = rdd.mapPartitions(fs::write).collect();
fs.writeManifest(Manifest.makeManifest(writeObjectResults));
我對這段代碼的期望是,無論發生什么情況,只要且僅當所有任務均已完成並將其分區成功寫入S3時, writeManifest
調用writeManifest
。 問題在於,顯然,某些任務正在清單之后寫入S3,這是永遠不會發生的。
在ManifestFilesystem.write
,我刪除現有清單(如果有)以使其無效,因為正常的工作流程應為:
我懷疑在以下情況下可能會由於推測的任務而發生:
collect
結果返回給驅動程序 ManifestTimeslice.write
並在寫入分區之前刪除清單。 那會發生什么嗎? 有人對這種行為有另一個假設嗎?
注意:不能使用內置數據發布方法
注意2:實際上,我發現這傾向於證實我的直覺,但是進行確認仍然很不錯,因為出於這個問題范圍之外的原因,我沒有使用標准的HDFS或S3讀/寫方法。
Spark不會主動終止推測性任務。 它只是等待任務完成,然后忽略結果。 我認為您的推測性任務很可能在collect
調用之后繼續編寫。
在意識到從Spark的角度來看無法解決這個問題之后,我將回答我自己的問題:如何確保在有時間完成所有推測性任務之前就將其殺死? 實際上最好讓它們完全運行,否則它們可能會在寫入文件時被殺死,然后被截斷。
有不同的可能方法:
該線程中的一些消息表明,一種常見的做法是在執行原子重命名之前寫一個臨時嘗試文件(在大多數文件系統上都很便宜,因為它僅僅是指針切換)。 如果推測性任務試圖將其臨時文件重命名為現有名稱(如果該操作是原子操作,則不會同時發生),則重命名請求將被忽略,並且臨時文件將被刪除。
據我所知,S3不提供原子重命名。 另外,盡管上述過程很容易實現,但我們目前正在嘗試將自制解決方案限制在最大范圍內,並保持系統簡單。 因此,我的最終解決方案是使用jobId
(例如,作業開始的時間戳)並將其傳遞給從屬,並將其寫入清單中。 將文件寫入FS時,將應用以下邏輯:
public WriteObjectResult write(File localTempFile, long jobId) { // cheap operation to check if the manifest is already there if (manifestsExists()) { long manifestJobId = Integer.parseInt(getManifestMetadata().get("jobId")); if (manifestJobId == jobId) { log.warn("Job " + jobId + " has already completed successfully and published a manifest. Ignoring write request." return null; } log.info("A manifest has already been published by job " + jobId + " for this dataset. Invalidating manifest."); deleteExistingManifest(); } return publish(localTempFile); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.