4

我想調試在AWS EMR集羣上運行的Spark應用程序。如果我可以使用IntelliJ進行遠程連接和調試,那將會很棒。我已經搜索,但發現很少。AWS EMR - IntelliJ遠程調試Spark應用程序

是否有可能,如果有的話,有人可以指導我朝着正確的方向嗎?

謝謝。

回答

5

首先,由於AWS EMR的衆多錯誤和意外的使用情況,我會告誡你要做的事情基本上是不可能的。我強烈建議支付您可以運行工作的最大單一實例(它們的c4.8xlarge在負擔得起,而x1.32xlarge爲真正的瘋狂!),並簡單地在該實例中安裝spark並運行您的工作。

先決條件

  • 您的VPC必須正確配置爲允許任何連接到外部世界的。這意味着您的Internet網關工作正常。您可以通過啓動具有EC2密鑰對的羣集,修改主服務器的安全組以允許來自您計算機的SSH連接(他們自然不會默認執行此操作)並嘗試從您的計算機連接到主服務器來測試此情況。如果你不能這樣做,你將無法進行調試。我甚至無法在沒有額外配置的情況下在新的羣集上滿足這個先決條件!
  • 運行IntelliJ進行調試的機器必須可以從Internet訪問。要測試此操作,請修改主實例的安全組以允許在端口5005上出站連接到您的機器。然後,在您的機器上運行nc -l 5005。 SSH到你的主人並嘗試echo "test" | nc your_ip_address 5005。在您的機器終端上看到test之前,請勿繼續。

的IntelliJ設置

創建一個新的遠程配置。將調試器模式更改爲偵聽。命名配置並保存。當你點擊調試時,它會等待連接。在該窗口中,您將看到「運行遠程​​JVM的命令行參數」,讀書是這樣的:

-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:5005,suspend=y 

您可以刪除onthrowoncaught線像我一樣。假設您的調試機器可以通過Internet訪問24.13.242.141。假設它實際上是:

-agentlib:jdwp=transport=dt_socket,server=n,address=24.13.242.141:5005,suspend=y 

我們將用它來設置Spark進程的調試。

星火設置

有可調試兩個過程:駕駛過程(運行在您的SparkContext實例化的代碼)和執行過程。最終,您會將這些JVM選項傳遞給​​的特殊參數以使連接發生。爲了調試驅動程序,使用

spark-submit --driver-java-options -agentlib:jdwp=transport=dt_socket,server=n,address=24.13.242.141:5005,suspend=y --class ... 

出於調試執行過程中,你可以使用一個配置選項:

spark-submit --conf "spark.executor.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=n,address=24.13.242.141:5005,suspend=y" --class ... 

調試的執行者是多餘的棘手,因爲會有多個進程。你不能像你在IntelliJ中想象的那樣真正地調試多個進程。此外,即使您聲稱可以,您也無法將AWS EMR中的執行程序數量限制爲1。我相信如果其他執行程序會失敗(當它們無法連接到您的調試會話時它們將會失敗)。但這一步未經測試。

全部放在一起

可以修改參數​​既與SDK和Web控制檯。請注意,在SDK中,您不應該嘗試自己連接「參數」 - 將它們作爲數組項一樣將它們傳遞給您。

爲了調試驅動程序(同樣用slave的安全組來調試執行程序),您需要修改主機的安全組。創建一個安全組,允許出站連接到您的調試器的IP地址和端口(即TCP Outbound到24.13.242.141:5005)。您應該使用該條目創建安全組,並使用AWS SDK(.withAdditionalMasterSecurityGroups(...))將其添加到主/從屬作業流實例配置的安全組。我不確定如何從Web控制檯執行此操作。

一些常見的問題

  • 確保使用搖籃生產與classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4"插件陰影罐子。另外,啓用Zip64。您會將:shadowJar任務的結果上載到S3,以便在AWS EMR上實際執行。
buildscript { 
    repositories { 
     mavenCentral() 
     maven { 
      url "https://plugins.gradle.org/m2/" 
     } 
    } 
    dependencies { 
     classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4" 
    } 
} 

apply plugin: "com.github.johnrengelman.shadow" 

shadowJar { 
    zip64 true 
} 
  • 確保用--deploy-mode cluster--master yarn啓動星火應用程序(基本上沒有證件)。
  • 爲了從EMR的驅動程序或執行程序內部訪問S3,請執行而不是來修改sc.hadoopConfiguration()(例如,configuration.set("fs.s3n.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem");)。不要配置這些屬性! hadoop-aws默認情況下在EMR環境中正常工作,並具有自動設置的相應屬性。
  • 將您的log4j日誌選項設置爲僅報告WARN及更高版本。在此SDK,你將有做到這一點:
.withConfigurations(new Configuration() 
    .withClassification("spark-log4j") 
    .addPropertiesEntry("log4j.rootCategory", "WARN, console")) 
  • 檢查containers/applications_.../container.../stderr.gz日誌中的錯誤你懶得調試之前!
  • 如果在您的容器日誌中發現此錯誤,「WARN YarnClusterScheduler:初始作業未接受任何資源;請檢查您的集羣UI以確保工作人員已註冊且具有足夠資源」,請確保將配置屬性maximizeResourceAllocationspark分類。
new Configuration() 
     .withClassification("spark") 
     .addPropertiesEntry("maximizeResourceAllocation", "true")) 
  • 不要忘記在驅動程序(sc.close())年底前關閉您的上下文。否則,紗線永遠不會啓動。歡迎無證。
  • 陰影JAR中的資源只能由與資源相同的「JAR」內的類加載。換句話說,不要使用ClassLoader.getSystemClassLoader()。如果class A通常在a.jar想要訪問b.jar中的資源,並且class Bb.jar中的類,請使用B.class.getClassLoader().getResource...。此外,使用相對路徑(在資源引用的開頭省略正斜槓)。我會建議捕獲NullPointerException並嘗試這兩種方法,這樣無論它如何打包,您的JAR都能正常工作。
  • 如果您使用類實現Function接口和類似的類,請確保創建一個無參數構造函數來執行您可能依賴的所有初始化。 Spark對閉包和函數實例都使用Kryo序列化(而不是Java序列化),如果您忽略爲特定於應用程序的初始化代碼提供無參數構造函數(例如,從資源加載),則不會執行所有操作您期待的初始化。
+0

哇,非常感謝你這麼詳細的深入的答案 - 我會嘗試什麼似乎是一個徒勞的嘗試很快:D – null

+0

我甚至不想嘗試這個了。反正...非常好的迴應 – Cristian