簡體   English   中英

Databricks/python - 創建強大的長期運行作業的最佳實踐方法是什么

[英]Databricks/python - what is a best practice approach to create a robust long running job

我找不到一個很好的概述如何創建一個失敗可能性中等的工作。

我是一位經驗豐富的開發人員,但我對 databricks/spark 比較陌生。 雖然我可以通過編程解決問題,但我正在尋找最佳實踐解決方案。

我的場景是從 Web API 中讀取大量行。 運行該作業大約需要 36 小時。 在這 36 小時內,我很有可能在與 API 交互時遇到致命錯誤(超時、讀取時斷開連接、無效/意外的返回值等)。 雖然我可以越來越多地使我的工作對這些錯誤具有魯棒性,但理想情況下,我不必再次運行整個工作來恢復。 理想情況下,我只需要運行失敗的案例。

我的基本流程是這樣的:

  • 讀入一組精選的 ID(10 萬個)
  • 對於每個 ID,調用 Web API 以獲取詳細信息
  • 將結果輸出寫入新表(ID + 詳細信息)

我評估過的方法:

  1. 嘗試以一攬子方式捕獲所有錯誤並將故障輸出到結果表中。 然后,恢復是在修補導致失敗的任何原因后讀取失敗的行作為 ID 的來源。
  2. 將初始數據集划分為多個文件,並將計划在各個分區上工作的東西拼湊在一起。 如果其中一個項目失敗,則重新運行單個分區。 全部成功后,匯總結果。 我認為這是可行的,但由於我對數據塊的了解有限,它看起來很混亂。 我會做自己的分區和任務調度。 我希望有更好的方法。

我在腦海中想象的解決方案是這樣的:

# Split the source table into 100 equal buckets
# Run only buckets 10,20,21 (presumably, those are the failed buckets)
# For each bucket, run the udf get_details
# If the bucket succeeds, put it's rows into aggregate_df.  Otherwise, into error_df
aggregate_df, error_df = df.split_table_evenly(bucket_count=100)
  .options(continue_on_task_failure=true)
  .filter(bucket=[10,20,21])
  .run_task_on_bucket(udf=get_details)

解決方案是使用支持流式查詢檢查點的Spark Structured Streaming Spark 指南非常詳盡地描述了如何在不同場景中使用結構化流。 它沒有明確涵蓋我的用例——按行分解數據集——我將在這里進行描述。

基本方法是將流分解為 Spark 所稱的“微批量”。 對於上面的場景,要理解的重要一點是,按時間觸發批處理,而我想按批處理。 Spark 有一種支持數據批處理的提供程序——Kafka 提供程序,它可以基於偏移量進行批處理。 由於我不想通過 Kafka 運行我的數據,所以我選擇不使用這種方法。

文件源確實有一個我們可以使用的工具:它能夠使用maxFilesPerTrigger選項設置批處理中文件的數量限制 我也使用latestFirst首先處理最舊的文件,但這不是必需的。

source_dataframe = self.sparksession.readStream.option('maxFilesPerTrigger', 1) \
.option('latestFirst', True) \
.format('delta') \
.load(path)

由於這僅適用於整個文件,因此我需要在生成時限制文件的大小。 為此,我只是使用會生成合適的存儲桶大小的密鑰對數據集進行分區。

因為對於大多數用途來說,擁有許多文件並不是超級高效,所以我選擇將此數據集寫入兩次,因此除非我在檢查點,否則不要支付讀取許多小文件的成本。 但是,這完全是可選的。

dataframe = # Some query
curated_output_dataframe = dataframe
generate_job_input_dataframe = dataframe.partitionBy('somecolumn')

curated_output_dataframe.write.format(my_format).save(path=my_curated_output_path)
generate_job_data_dataframe.write.format(my_format).save(path=my_job_data_path)

然后,您可以使用流式函數讀取和寫入數據集,幾乎可以開始了。

source_dataframe = self.sparksession.readStream.option('maxFilesPerTrigger', 1).format(input_path).load(input_path)
query = dataframe.writeStream.format(output_path).start('output_path')
query.awaitTermination()

但是,在您以穩健的方式執行此操作之前,還有一些事情需要處理。

如果您希望能夠恢復您的工作,則需要設置檢查點位置。

sparkSession.readStream.option('checkpointLocation','/_checkpoints/some_unique_directory')

如果您不更改某些設置,Spark 將變得貪婪並讀取您的所有輸入文件。
有關更多詳細信息,請參閱此答案

您應該估計您的費率並將起始目標費率設置為該費率。 我一開始就把我的設置得很低——spark 會從這個速率調整到任何它是可持續的。

sparksession.conf.set('spark.streaming.backpressure.enabled', True)
sparksession.conf.set('spark.streaming.backpressure.initialRate', target_rate_per_second)
sparksession.conf.set('spark.streaming.backpressure.rateEstimator', 'pid')
sparksession.conf.set('spark.streaming.backpressure.pid.minRate', 1)

除非您監視作業,否則 Spark 將永遠運行。 Spark 假設流作業無限期地運行,並且在數據集耗盡之前沒有明確支持運行。 您必須自己編寫代碼,不幸的是代碼很脆弱,因為在某些情況下您必須檢查作業狀態消息。

有關更多詳細信息,請參閱此答案 答案中的代碼對我來說並不是 100% 有效 - 我在消息表達式中發現了更多案例。 這是我目前正在使用的代碼(刪除了日志記錄和注釋):

while query.isActive:
    msg = query.status['message']
    data_avail = query.status['isDataAvailable']
    trigger_active = query.status['isTriggerActive']
    if not data_avail and not trigger_active:
        if 'Initializing' not in msg:
            query.stop()
    time.sleep(poll_interval_seconds)

其他注意事項這些不是檢查點微批次所必需的,但在其他方面很有用。

Spark 生成有用的日志——我發現在流執行中建立信任時,這兩個日志很有用:

22/05/18 23:22:32 INFO MicroBatchExecution: Streaming query made progress:
22/05/18 23:24:44 WARN ProcessingTimeExecutor: Current batch is falling behind. The trigger interval is 500 milliseconds, but spent 5593 milliseconds

可以通過以下方式啟用 PID 估計器的日志記錄

sparksession.conf.set('log4j.logger.org.apache.spark.streaming.scheduler.rate.PIDRateEstimator', 'TRACE')

Spark 最近添加了 RocksDB 對流狀態管理的支持,您需要明確啟用。 它對我來說很順利。

sparksession.conf.set('spark.sql.streaming.stateStore.providerClass', \                                    
    'org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM