我正在AWS EMR集群中运行Apache Spark应用程序。应用程序从AWS SQS检索消息,根据消息数据进行一些计算,然后删除每条消息。
我在具有NAT实例的私有子网上的VPC中运行EMR群集。
我面临的问题是我无法删除邮件。我能够检索所有消息并且能够发送消息,但我无法删除它们。
我在EMR群集上使用以下安全性
EC2 instance profile:EMR_EC2_DefaultRole
EMR role:EMR_DefaultRole
这些角色中的每一个都附加了以下政策:
AmazonSQSFullAccess
,AmazonElastiCacheFullAccess
,AmazonElasticMapReduceFullAccess
,AmazonVPCFullAccess
我认为问题在于权限,但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
文件中。
修改
经过大量研究和测试后,我发现了这一点:
_amazonSqs.deleteMessage(deleteMessageRequest);
代码不会抛出任何异常。看起来好像请求超时,但不会抛出超时异常。 deleteMessage
之后的任何代码都未执行。Thread.UncaughtExceptionHandler
,但也没有抛出任何异常。ReceiptHandle
,更确切地说,因为我在几台机器上运行了一个Spark群集,所以我认为机器的IP,名称或其他类似的东西都编码在{ {1}}并且ReceiptHandle
可能已从其他计算机执行,因此这就是它无效的原因。这就是我用一台机器创建一个Spark集群的原因。可悲的是,我仍然无法删除该消息。答案 0 :(得分:2)
经过大量的调试和测试后,我终于找到了问题所在。
正如所料,这不是许可问题。问题是,由EMR启动并运行Spark应用程序的EC2实例包含Java的所有AWS包的某个版本(包括SQS包)。包含这些包的路径被添加到Hadoop,Yarn和Spark中。因此,当我的应用程序启动时,它使用了机器上已有的软件包并收到错误消息。 (错误记录在Yarn日志中。我花了一些时间才弄明白。)
我正在使用maven shade插件为我的应用程序构建超级jar,所以我认为我可以尝试着色(重新定位)AWS包。这将允许我将依赖项封装在我的应用程序中。可悲的是,这不行。似乎亚马逊正在使用包内的反射,并且他们对某些类的名称进行了硬编码,从而使着色无用。(在我的着色包中找不到硬编码的类)
因此,经过一些更多的挫折后,我找到了以下解决方案:
--driver-class-path /path_to_your_jar/myapp.jar --class com.myapp.startapp
此处的关键是--driver-class-path
选项。您可以阅读更多相关信息here。基本上我将我的超级jar添加到Spark驱动程序类路径中,允许应用程序使用我的依赖项。
到目前为止,这是我找到的唯一可接受的解决方案。如果你知道另一个或更好的,请写评论或答案。
我希望这个答案对一些不幸的灵魂有用。这会让我度过几个难以忍受的日子。