Spring boot/spring-cloud-aws SQS 在部署到 AWS/EC2 环境时无法轮询消息
Spring boot/spring-cloud-aws SQS failing to poll messages when deployed to AWS/EC2 environment
Spring 启动应用程序工作正常运行 在本地连接到沙箱 S3 和沙箱 SQS,使用 DefaultAWSCredentialsProviderChain 并设置为系统 属性。
当应用程序部署到 EC2 环境并使用 ProfileCredentials 时,我在 CloudWatch 中收到连续的以下错误流:
{
"Host": "<myhost>",
"Date": "2016-12-20T21:52:56,777",
"Thread": "simpleMessageListenerContainer-1",
"Level": "WARN ",
"Logger": "org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer",
"Msg": "An Exception occurred while polling queue 'my-queue-name'. The failing operation will be retried in 10000 milliseconds",
"Identifiers": {
"Jvm-Instance": "",
"App-Name": "my-app",
"Correlation-Id": "ca9a556e-2fbc-3g49-9fb8-0e9213bb79bc",
"Session-Id": "",
"Thread-Group": "main",
"Thread-Id": "32",
"Version": ""
}
}
java.lang.NullPointerException
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:255) [spring-cloud-aws-messaging-1.1.1.RELEASE.jar:1.1.1.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_91]
问题归结为 SimpleMessageListenerContainer.java:255 :
ReceiveMessageResult receiveMessageResult = getAmazonSqs().receiveMessage(this.queueAttributes.getReceiveMessageRequest());
this.queueAttributes
为空。
我已经尝试了所有方法,包括 @EnableContextCredentials(instanceProfile=true)
,以设置 cloud.aws.credentials.instanceProfile=true,同时确保 access & secretKey 为空。 SQS 队列肯定存在,我已经通过 EC2 实例本身的 aws cli 验证了配置文件凭据存在并且有效。
此外,在 AWS 环境中,该应用程序还使用 S3 客户端为存储桶生成唯一密钥,这一切都有效。只有当应用程序尝试从似乎失败的 SQS 中轮询消息时才会出现这种情况。
我正在这样处理消息:
@SqsListener("${aws.sqs.queue.name}")
public void receive(S3EventNotification s3EventNotificationRecord) {
更多配置:
@Bean
public AWSCredentialsProvider awsCredentialsProvider(
@Value("${aws.credentials.accessKey}") String accessKey,
@Value("${aws.credentials.secretKey}") String secretKey,
JasyptPropertyDecryptor propertyDecryptor) {
if (!Strings.isNullOrEmpty(accessKey) || !Strings.isNullOrEmpty(secretKey)) {
Preconditions.checkState(
!Strings.isNullOrEmpty(accessKey) && !Strings.isNullOrEmpty(secretKey),
"Error in accessKey/secretKey config. Either both must be provided, or neither.");
System.setProperty("aws.accessKeyId", propertyDecryptor.decrypt(accessKey));
System.setProperty("aws.secretKey", propertyDecryptor.decrypt(secretKey));
}
return DefaultAWSCredentialsProviderChain.getInstance();
}
@Bean
public S3Client s3Client(
AWSCredentialsProvider awsCredentialsProvider,
@Value("${aws.s3.region.name}") String regionName,
@Value("${aws.s3.bucket.name}") String bucketName) {
return new S3Client(awsCredentialsProvider, regionName, bucketName);
}
@Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory() {
MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setStrictContentTypeMatch(false);
QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
factory.setArgumentResolvers(
Collections.<HandlerMethodArgumentResolver>singletonList(
new PayloadArgumentResolver(messageConverter)));
return factory;
}
我注意到的另一件事是,在应用程序启动时,会调用 ContextConfigurationUtils.registerCredentialsProvider
,除非您在 app.properties 中将 cloud.aws.credentials.profileName=
指定为空,否则此 class 将将 ProfileCredentialsProvider
添加到 awsCredentialsProviders
的列表中。我认为这可能有问题,因为我没有以这种方式在 EC2 实例上提供凭证,而是应该使用 InstanceProfileCredentialsProvider
。此更改无效。
原来问题是我在 AWS 中使用的服务(例如 SQS)对它们具有适当的访问权限,但 IAM 配置文件本身缺乏权限,甚至无法尝试应用程序需要进行的服务操作。
Spring 启动应用程序工作正常运行 在本地连接到沙箱 S3 和沙箱 SQS,使用 DefaultAWSCredentialsProviderChain 并设置为系统 属性。
当应用程序部署到 EC2 环境并使用 ProfileCredentials 时,我在 CloudWatch 中收到连续的以下错误流:
{
"Host": "<myhost>",
"Date": "2016-12-20T21:52:56,777",
"Thread": "simpleMessageListenerContainer-1",
"Level": "WARN ",
"Logger": "org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer",
"Msg": "An Exception occurred while polling queue 'my-queue-name'. The failing operation will be retried in 10000 milliseconds",
"Identifiers": {
"Jvm-Instance": "",
"App-Name": "my-app",
"Correlation-Id": "ca9a556e-2fbc-3g49-9fb8-0e9213bb79bc",
"Session-Id": "",
"Thread-Group": "main",
"Thread-Id": "32",
"Version": ""
}
}
java.lang.NullPointerException
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:255) [spring-cloud-aws-messaging-1.1.1.RELEASE.jar:1.1.1.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_91]
问题归结为 SimpleMessageListenerContainer.java:255 :
ReceiveMessageResult receiveMessageResult = getAmazonSqs().receiveMessage(this.queueAttributes.getReceiveMessageRequest());
this.queueAttributes
为空。
我已经尝试了所有方法,包括 @EnableContextCredentials(instanceProfile=true)
,以设置 cloud.aws.credentials.instanceProfile=true,同时确保 access & secretKey 为空。 SQS 队列肯定存在,我已经通过 EC2 实例本身的 aws cli 验证了配置文件凭据存在并且有效。
此外,在 AWS 环境中,该应用程序还使用 S3 客户端为存储桶生成唯一密钥,这一切都有效。只有当应用程序尝试从似乎失败的 SQS 中轮询消息时才会出现这种情况。
我正在这样处理消息:
@SqsListener("${aws.sqs.queue.name}")
public void receive(S3EventNotification s3EventNotificationRecord) {
更多配置:
@Bean
public AWSCredentialsProvider awsCredentialsProvider(
@Value("${aws.credentials.accessKey}") String accessKey,
@Value("${aws.credentials.secretKey}") String secretKey,
JasyptPropertyDecryptor propertyDecryptor) {
if (!Strings.isNullOrEmpty(accessKey) || !Strings.isNullOrEmpty(secretKey)) {
Preconditions.checkState(
!Strings.isNullOrEmpty(accessKey) && !Strings.isNullOrEmpty(secretKey),
"Error in accessKey/secretKey config. Either both must be provided, or neither.");
System.setProperty("aws.accessKeyId", propertyDecryptor.decrypt(accessKey));
System.setProperty("aws.secretKey", propertyDecryptor.decrypt(secretKey));
}
return DefaultAWSCredentialsProviderChain.getInstance();
}
@Bean
public S3Client s3Client(
AWSCredentialsProvider awsCredentialsProvider,
@Value("${aws.s3.region.name}") String regionName,
@Value("${aws.s3.bucket.name}") String bucketName) {
return new S3Client(awsCredentialsProvider, regionName, bucketName);
}
@Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory() {
MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setStrictContentTypeMatch(false);
QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
factory.setArgumentResolvers(
Collections.<HandlerMethodArgumentResolver>singletonList(
new PayloadArgumentResolver(messageConverter)));
return factory;
}
我注意到的另一件事是,在应用程序启动时,会调用 ContextConfigurationUtils.registerCredentialsProvider
,除非您在 app.properties 中将 cloud.aws.credentials.profileName=
指定为空,否则此 class 将将 ProfileCredentialsProvider
添加到 awsCredentialsProviders
的列表中。我认为这可能有问题,因为我没有以这种方式在 EC2 实例上提供凭证,而是应该使用 InstanceProfileCredentialsProvider
。此更改无效。
原来问题是我在 AWS 中使用的服务(例如 SQS)对它们具有适当的访问权限,但 IAM 配置文件本身缺乏权限,甚至无法尝试应用程序需要进行的服务操作。