2016-06-29 45 views
2

我正在AWS EMR羣集中運行Apache Spark應用程序。應用程序從AWS SQS中檢索消息,根據消息數據進行一些計算,然後刪除每條消息。無法從EMR中運行的Spark應用程序中刪除AWS SQS消息

我在帶有NAT實例的專用子網上的VPC中運行EMR羣集。

我面臨的問題是我無法刪除郵件。我能夠檢索所有消息,並且能夠發送消息,但我無法刪除它們。

我使用EMR集羣 EC2 instance profile:EMR_EC2_DefaultRole EMR role:EMR_DefaultRole

每個角色有以下政策附着在下面的安全性: AmazonSQSFullAccessAmazonElastiCacheFullAccessAmazonElasticMapReduceFullAccessAmazonVPCFullAccess

我認爲這個問題是與權限,但AmazonSQSFullAccess授予完整的權限,所以我沒有選擇。

這是刪除消息的Java代碼:

public class SQSMessageBroker 
{ 
    private AmazonSQS _amazonSqs; 

    public SQSMessageBroker() 
    { 
     // Create the SQS client 
     createSQSClient(); 
    } 

    public void deleteMessage(String queueUrl, String receiptHandle) 
     { 
      DeleteMessageRequest deleteMessageRequest = new DeleteMessageRequest(queueUrl, receiptHandle); 

      _amazonSqs.deleteMessage(deleteMessageRequest); 
     } 

    private void createSQSClient() 
    { 
     _amazonSqs = new AmazonSQSClient(); 
     _amazonSqs.setRegion(Region.getRegion(Regions.EU_WEST_1)); 
    } 
} 

SQSMessageBroker是在我的應用程序是獨生子。 當我在本地運行相同的代碼時,一切都很好。本地我創建了一個AWS用戶,並且我已將密鑰和祕密添加到.aws文件中。


編輯

大量的研究後和測試這是我發現:

  1. 看來,它不是一個權限問題(至少不是爲由EMR啓動的EC2實例)。我連接到實例,安裝了aws cli,檢索到消息併成功刪除它。
  2. _amazonSqs.deleteMessage(deleteMessageRequest);代碼不會拋出任何異常。它看起來好像請求超時,但沒有超時異常被拋出。 deleteMessage之後的任何代碼都未執行。
  3. 我正在一個單獨的線程中處理每條消息,因此我爲每個線程添加了一個Thread.UncaughtExceptionHandler,但也沒有拋出異常。
  4. 我懷疑問題可能在ReceiptHandle,更準確地說,因爲我在多臺機器上運行Spark羣集,所以我認爲機器IP,名稱或類似的東西編碼在ReceiptHandledeleteMessage可能已經從另一臺機器上執行,所以這就是爲什麼它沒有工作。這就是爲什麼我只用一臺機器創建了一個Spark羣集。可悲的是我仍然無法刪除郵件。
+0

你檢查了嗎? http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/DeleteMessage.html – error2007s

+0

是的,我有紅色的。現在我開始想知道收據處理過期需要多長時間,如果這可能是這種情況? Spark應用程序需要一些時間(20-30秒)來完成計算。 –

+0

不幸的是,看起來,到期的令牌可能並非如此。我嘗試從另一個隊列中檢索郵件並立即刪除它們。它不起作用。我懷疑這個問題可能出在一些奇怪的許可問題上,但我仍然不知道它是什麼。 –

回答

1

經過大量的調試和測試後,我終於設法找出問題所在。

正如預期的那樣,它不是一個權限問題。問題是,由EMR啓動並運行Spark應用程序的EC2實例包含用於java的所有AWS軟件包(包括SQS軟件包)的特定版本。包含這些包的路徑被添加到Hadoop,Yarn和Spark。所以當我的應用程序啓動時,它使用了已經在機器上的軟件包,並收到錯誤消息。 (錯誤記錄在Yarn日誌中,花了我一些時間才弄清楚)

我正在使用Maven遮罩插件爲我的應用程序構建超級罐子,所以我認爲我可以嘗試遮擋(重新安置)AWS軟件包。這將允許我在我的應用程序中封裝依賴關係。可悲的是,這不是工作。看起來,亞馬遜在軟件包中使用了反射,並且他們對某些類的名稱進行了硬編碼,因此渲染陰影毫無用處(在我的陰影包中未找到硬編碼類)

因此,在發現更多的挫敗感之後,以下解決方案:

  1. 創建一個EMR步驟,將我的超級罐子從S3下載到機器。
  2. 創建具有以下火花提交選項星火應用程序的步驟:

--driver-class-path /path_to_your_jar/myapp.jar --class com.myapp.startapp

這裏的關鍵是​​選項。你可以閱讀更多關於它here。基本上我將我的超級jar添加到Spark驅動程序類路徑中,允許應用程序使用我的依賴關係。

到目前爲止,這是我找到的唯一可接受的解決方案。如果你知道另一個或更好的,請寫評論或答案。

我希望這個答案可以用於一些不幸的靈魂。它會爲我節省幾個痛苦的日子。

相關問題