- ๋ชฉ์ฐจ
- Spring Boot ํ๊ฒฝ AWS SNS์ SQS๋ฅผ ์ด์ฉํ ์ด๋ฒคํธ ์ฒ๋ฆฌ
- 1 ์์ ์ฝ๋ ์์ฑ ๋ฐ ์์กด์ฑ ์ค์
- 2 SNS, SQS ๊ด๋ จ ์ค์
- 3 SNS ์ด๋ฒคํธ ๋ฐํ
- 4 SQS ์ด๋ฒคํธ ์์
- 5 ์์ฃผ ์ค์ํ๋ ๋ถ๋ถ
- ์ฐธ๊ณ
SQS๋ AWS์์ ์ ๊ณตํ๋ ๋ง์ดํฌ๋ก์๋น์ค, ๋ถ์ฐ ์์คํ ๋ฐ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ์ ๋ถ๋ฆฌํ๊ณ ํ์ฅํ ์ ์๋ ์์ ๊ด๋ฆฌํ ๋ฉ์์ง ํ(๋๊ธฐ์ด) ์๋น์ค์ด๋ค.
SNS๋ ํน์ ์ฃผ์ ์ ๋ํ ์๋ฆผ์ ๊ฒ์ํ ์ ์๋ pub-sub ๋ฉ์์ง ์์คํ ์ด๋ค.
๋ง์ ์๋น์ค์์ SNS์ SQS๋ฅผ ๊ฐ์ด ์ฌ์ฉํจ์ผ๋ก์จ ๊ฐ๊ฐ์ ํน์ง์ ํ์ฉํด ํจ์จ์ ์ด๊ณ ์์ ์ ์ธ ์ด๋ฒคํธ ์ฒ๋ฆฌ ํ๊ฒฝ์ ๊ตฌ์ถํ๋ค.
AWS์์๋ ์ถ์ฒํ๋ ์กฐํฉ์ด๋ฏ๋ก ๋ด๊ตฌ์ฑ๊ณผ ํ์ฅ์ฑ๋ฉด์์๋ ์ถฉ๋ถํ ๋ฏฟ๊ณ ์ฌ์ฉํ ๋งํ๋ค๊ณ ํ๋จ๋๋ค.
SNS์ SQS ๊ตฌ์กฐ.
SNS๋ SQS๋ง๊ณ ๋ ๋ค์ํ Subscription์ ์ง์ํ๋ค.
์ด๋ฒ ๊ธ์ Spring Boot ํ๊ฒฝ์์ AWS SNS์ SQS๋ฅผ ์ด์ฉํ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๊ณผ์ ์ ์ง์ ๊ตฌํํด๋ณธ๋ค.
์ด๋ฅผ ํตํด Spring ํ๊ฒฝ์์ SNS์ SQS๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์ดํด๋ณธ๋ค.
์ด๋ฒ ๊ธ์ AWS SNS์ SQS์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋ค๋ฃจ์ง์์ผ๋ฉฐ, Spring ๊ด์ ์์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง์ ๋ํด์๋ง ๋ค๋ฃฌ๋ค.
์ด์ ๋ํ ์์ธํ ๋ด์ฉ์ AWS SNS๊ฐ๋ ๊ณผ SQS ์ฐ๋, AWS SQS์ ์ฐธ๊ณ .
๋ํ, EC2์ Boot๋ฅผ ๋์์ ์ค์ตํ๋ค. ์ธ๋ถ ์๋ฒ์์์ ์ด๋ฒคํธ ๋ฐํ ๋ฐ ์๋น๋ ๋ค๋ฅธ ๊ธ์ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋๋ค.
์ด๋ฒ ๊ธ์์ ์ค์ตํ ๋ชจ๋ ์ฝ๋๋ Github์ ์ฐธ๊ณ .
๋จผ์ ์ค์ต์ ์ํด ๊ฐ๋จํ ์ด๋ฒคํธ ์์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ SNS, SQS๋ฅผ ํ์ฉํ๊ธฐ์ํ ์์กด์ฑ์ ์ค์ ํ๋ค.
์ด๋ฒ ๊ธ์์ ์ฌ์ฉํ ์ด๋ฒคํธ ์์ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
EventMessageSample.java
@Getter
public class EventMessageSample {
private Long id;
private String message;
private EventMessageSample() {
}
public EventMessageSample(Long id, String message) {
this.id = id;
this.message = message;
}
}
์ด๋ฒคํธ ๋ด์ฉ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ง๋ค ๊ต์ฅํ ์์ดํ๋ฏ๋ก, ์ด๋ฒ ๊ธ์์ ๊ฐ๋จํ id์ message๋ง์ ๋ด๋ ์ด๋ฒคํธ ๋ฉ์์ง๋ฅผ ๊ตฌํํ๋ค.
Spring Cloud AWS ๋ฉ์์ง ๋ชจ๋์ ๋ ๋ฆฝ ์คํํ ๋ชจ๋๋ก ์ ๊ณต๋๋ฉฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
dependencyManagement {
imports {
mavenBom("io.awspring.cloud:spring-cloud-aws-dependencies:2.4.4")
}
}
dependencies {
...
implementation 'io.awspring.cloud:spring-cloud-starter-aws-messaging'
...
}
Spring Cloud AWS๋ SQS ๋๋ SNS๋ฅผ ํตํ ๋ฉ์์ง pub, sub์ ๊ฐ์ํํ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
SQS๋ Spring 4.0์ ๋์
๋ ๋ฉ์์ง API (org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler
)์ ์ ์ ์ผ๋ก ์์กดํ๋ฏ๋ก ์ฝ๊ฒ ์ ๋
ธํ
์ด์
๋ง ์ฌ์ฉํ์ฌ ๊ตฌํ ๊ฐ๋ฅํ๋ค.
๋ฐ๋ฉด SQS๋ ๊ฐ๊ฐ์ ์๋ฆผ๋ง๋ค ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํด์ผํ ๋ถ๋ถ์ด์์ด ๋ถ๋ถ์ ์ผ๋ก ์กฐ๊ธ ๊ตฌํํด์ค์ผํ๋ค.
๐โโ๏ธ ์์กด์ฑ ๊ด๋ จ ์์๋๋ฉด ์ข์ ์์
์๋ง Spring ํ๊ฒฝ์์์ SNS, SQS ์์กด์ฑ๊ด๋ จ ๋ค์ํ ์๋ฃ๋ฅผ ์ดํด๋ณด๋ฉด ์๋ ๋ ๊ฐ์ง๊ฐ ๋์จ๋ค.
- org.springframework.cloud
- io.awspring.cloud
๋ฌด์์ ์ฌ์ฉํด์ผํ ์ง ํท๊ฐ๋ฆฐ๋ค.
๊ด๋ จํด์ ๊ตฌ๊ธ๋งํด๋ณด๋ฉด org.springframework.cloud๋ 2.2.x๊น์ง๋ง ์ง์ํ๋ฉฐ, ๊ทธ ์ด์๋ถํฐ๋ io.awspring.cloud๋ก ์ต์ ํ๋๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
๊ด๋ จ๋ ๋ด์ฉ์ ์ฌ๊ธฐ์์ ํ์ธ๊ฐ๋ฅํ๋ค.
์คํ๋ง ๋ฒ์ ์ ๋ฐ๋ฅธ ์์กด์ฑ ๋ฒ์ ๊ด๋ จํด์๋ Github - io.awspring.cloud์์ ์์ธํ ์ ์ ์๋ค.
์ด๋ฒ ๊ธ์์ ์๋ ๋ฒ์ ์ผ๋ก ์งํ๋๋ค.
- Spring Boot 2.7.14
- spring-cloud-starter-aws-messaging 2.4.4
๋ณธ๊ฒฉ์ ์ผ๋ก Spring Boot ํ๋ก์ ํธ์์ SNS์ ๋ฉ์์ง๋ฅผ Publishํ๊ณ SQS๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ Consumeํ๊ธฐ์ ์ SNS์ SQS์ ๋ํ ์ค์ ์ ๋จผ์ ํด์ฃผ๋ ๊ฒ์ด ์ข๋ค.
SNS์ SQS ์๋น์ค๊ฐ ๋์ํ๋ ๋ฆฌ์ ์ค์ ๊ณผ ์ธ์ฆ์ ๋ณด ์ค์ ์ ํด์ค๋ค.
AwsConfiguation.java
@Getter
@Configuration
public class AwsConfiguration {
@Value("${cloud.aws.credentials.access-key}")
private String awsAccessKey;
@Value("${cloud.aws.credentials.secret-key}")
private String awsSecretKey;
/**
* SNS ์ค์
*/
@Bean
public AmazonSNS amazonSNS() {
return AmazonSNSClient.builder()
// .withCredentials(getAwsCredentialsProvider())
.withRegion(Regions.AP_NORTHEAST_2)
.build();
}
/**
* AWS Credential ์ค์
*/
public AWSCredentials getAwsCredentials() {
return new BasicAWSCredentials(awsAccessKey, awsSecretKey);
}
public AWSCredentialsProvider getAwsCredentialsProvider() {
return new AWSStaticCredentialsProvider(getAwsCredentials());
}
/**
* SQS ์ค์
*/
@Bean
public AmazonSQSAsync amazonSqs() {
return AmazonSQSAsyncClientBuilder
.standard()
// .withCredentials(new AWSStaticCredentialsProvider(getAwsCredentials()))
.withRegion(Regions.AP_NORTHEAST_2)
.build();
}
}
ํ์์ ๊ฒฝ์ฐ AWS๋ด์ ๊ฐ์ ๋ฆฌ์ ๊ฐ์ VPC์์์ ๋์ํ๋ฏ๋ก, ์ธ์ฆ์ ๋ณด๋ ๋ชจ๋ ๋ฏธ๋ฆฌ IAM ์ค์ ์ํตํด ํด์คฌ์ผ๋ฏ๋ก ์ ์ค์ ์์ ์ฃผ์์ฒ๋ฆฌํด๋์๋ค.
๋ง์ฝ AWS๋ด์์ EC2, SNS, SQS๋ฑ์ IAM ์ค์ ์ ํ์ง์๊ณ , ์ฌ์ฉํ๋ค๋ฉด Credentials ์ค์ ์ ํด์ค์ผ SNS์ ์ด๋ฒคํธ๋ฅผ Publish ํ ์ ์๋ค.
์ธ๋ถ ์๋ฒ์์ ์ ์ํ๋ค๊ณ ํ ๋๋ ๋น์ฐํ Credentials ์ค์ ์ ํด์ค์ผํ๋ค.
๐โโ๏ธ Short Polling์ Long Polling
AWS๋ spring-cloud-starter-aws-messaging
๋ชจ๋์ SQS๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ์ ํตํฉํด๋์๋ค.
๊ฐ๋ฐ์๋ ๊ทธ์ @SqsListiner
๋ฅผ ์ด์ฉํ๋ฉด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
ํ์ง๋ง, ์๋ฌด ์ค์ ์์ด ์ฌ์ฉํ๋ฉด ๋ํดํธ๋ก Short Polling์ ํ๊ฒ๋๋ค.
Short Polling์ Consumer์์ ๋ฉ์์ง Polling์ SQS ์๋ฒ์ ํ์ ์ธํธ๋ฅผ ์ํ๋งํ๊ณ ํด๋น ์๋ฒ์์๋ง ๋ฉ์์ง๋ฅผ ํ์ํ์ฌ Pollingํด์จ๋ค.
๋ฐ๋ผ์ ๋ฉ์์ง๊ฐ ์กด์ฌํจ์๋ ReceiveMessage
์์ฒญ์ด ๋ชจ๋ ๋ฉ์์ง๋ฅผ ํ์ํ์ง ๋ชปํ ์ ์๋ค.
๋ฐ๋ฉด, Long Polling์ ์ผ์ ์๊ฐ๋์ ์ํ๋ง์ด ์๋ ๋ชจ๋ SQS ์๋ฒ๋ฅผ ์กฐํํ์ฌ ๋ฉ์์ง๋ฅผ ํ์ ๋ฐ ๋ฐํํ๋ค.
๋ฌด์จ ์ฐจ์ด๊ฐ ์๊ฒ ๋ํ๊ฒ ์ง๋ง, AWS ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ฉด ์๋์ ๊ฐ์ด ๋ช ์๋์ด์๋ค.
Long polling helps reduce the cost of using Amazon SQS by eliminating the number of empty responses (when there are no messages available for a ReceiveMessage request) and false empty responses (when messages are available but aren't included in a response)
์ฐธ๊ณ : https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html#sqs-long-polling
ํด์ํ๋ฉด Short Polling์ ๋น ์๋ต ์๊ฐ ๋ง์ SQS ์ฌ์ฉ ๋น์ฉ์ด ๋ ๋ง์ด ๋ถ๊ณผ๋๋ค๊ณ ํ๋ค.
๋ฐ๋ฉด, Long Polling ์ฌ์ฉ์ ๋น ์๋ต์ ์๋ฅผ ์ค์ฌ SQS ๋น์ฉ์ ์ ๊ฐํ ์ ์๋ค.
๐โโ๏ธ Long Polling ์ค์
AwsConfiguration.java
@Getter
@Configuration
public class AwsConfiguration {
// ... Credentials, Region ์ค์ ...
/**
* SQS๋ @SqsListener ์ด์ฉํ๋ฉด ์ฝ๊ฒ Consume ํ ์ ์๋ค.
*
* ๋ค๋ง, ๋ํดํธ๋ก๋ Short Pollingํ๋ค. ๊ทธ๋ฌ๋ฏ๋ก Long Polling ์ด์ฉํ๋ ค๋ฉด ์๋์ ๊ฐ์ด ์ค์ ํด์ค์ผํ๋ค.
*
* ๊ทธ์ธ์๋ Visibility ์ค์ ๋ฑ SQS์ ๋ฉ์์ง๋ฅผ Consume ํ ๋์ ๋ค์ํ ์ค์ ์ ํด์ค ์ ์๋ค.
*/
@Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSqs,
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor) {
SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
factory.setAmazonSqs(amazonSqs);
factory.setWaitTimeOut(10); // polling ์ค์
factory.setVisibilityTimeout(30);
factory.setTaskExecutor(simpleAsyncTaskExecutor);
return factory;
}
@Bean
public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
simpleAsyncTaskExecutor.setConcurrencyLimit(50);
return simpleAsyncTaskExecutor;
}
}
Consumer๊ฐ Pollingํ ๋์ ๋ชจ๋ ์ค์ ์ ์์ ๊ฐ์ด ํ ์ ์๋ค.
์์ ๊ฐ์ด Long Polling ์ธ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ฌ์ฉ๋๋ ์ค๋ ๋๋ VisibilityTimeout๋ฑ์ ์ค์ ํ ์ ์๋ค.
๋ง์ง๋ง์ผ๋ก SNS์ SQS๋ฅผ ํน์ ํ ์ ์๋ ์ค์ ์ properties์ ํด์ค๋ค.
application.yml
cloud:
aws:
credentials:
access-key: accesskey
secret-key: secretkey
stack:
auto: false
sns-topic:
binghe-test-sns: "arn:aws:sns:ap-northeast-2:385423560848:binghe-test-sns"
sqs-event:
binghe-test-sqs: "binghe-test"
์ค์ ์ด ์๋ฃ๋์๋ค๋ฉด, ๊ฐ๋จํ ์ด๋ฒคํธ๋ฅผ ์์ฑํ์ฌ SNS์ Publish ํด๋ณธ๋ค.
๐โโ๏ธ Publisher ๊ตฌํ
AwsSnsPublisher.java
@Slf4j
@Component
@RequiredArgsConstructor
public class AwsSnsPublisher {
private final AmazonSNS amazonSNS;
private final ObjectMapper objectMapper;
public void publishJson(String topic, Object message) {
try {
publishToSns(topic, objectMapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
log.error("[TOPIC::{}] Json serializing fail {}", topic, message, e.getMessage(), e);
}
}
private PublishResult publishToSns(String topic, String message) {
PublishRequest publishRequest = new PublishRequest()
.withTopicArn(topic)
.withMessage(message)
.addMessageAttributesEntry("contentType",
new MessageAttributeValue()
.withDataType("String")
.withStringValue(APPLICATION_JSON_UTF8_VALUE));
PublishResult result = amazonSNS.publish(publishRequest);
log.info("[TOPIC::{}] published MessageID : {}, message : {}", topic, result.getMessageId(), message);
return result;
}
}
๊ตฌํ ๋ฐฉ์์ ๊ฐ ์ํฉ์ ๋ง์ถฐ ๊ตฌํํด์ฃผ๋ฉด๋๋ค.
๐โโ๏ธ ๋ฉ์์ง ๋ฐํ ๊ฐ๋จ ์์ ๊ตฌํ
๋ฉ์์ง๋ฅผ ๊ฐ๋จํ ๋ฐํํด๋ณด๊ธฐ์ํด ๊ฐ๋จํ ํ ์คํธ API๋ฅผ ๋ง๋ค์ด Publish ํด๋ณธ๋ค.
@RestController
public class TestController {
private final AwsSnsPublisher publisher;
private final String topic;
public TestController(AwsSnsPublisher publisher,
@Value("${sns-topic.binghe-test-sns}") String topic) {
this.publisher = publisher;
this.topic = topic;
}
@PostMapping("/test")
public ResponseEntity<String> test(@RequestBody EventMessageSample eventMessageSample) {
publisher.publishJson(topic, eventMessageSample);
return ResponseEntity.ok("ok");
}
}
API๋ฅผ ํธ์ถํด๋ณด๋ฉด ์๋์ ๊ฐ์ด SQS์ ๋ฉ์์ง๊ฐ ์์ด๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด์ SQS ์ด๋ฒคํธ๋ฅผ Consumeํ๋ ์ฝ๋๋ฅผ ์์ฑํด๋ณธ๋ค.
๐โโ๏ธ ๋ฆฌ์ค๋ ๊ตฌํ
Consumeํ๋ ๋ก์ง์ @SqsListiner
๋ฅผ ์ด์ฉํ๋ฉด ์์ @Scheduler
๋ก Pollingํ์ง ์๊ณ ํธ๋ฆฌํ๊ฒ ์ด์ฉํ ์ ์๋ค.
๊ธฐํ ๋ฉ์์ง ์ญ์ ์ ์ฑ ๊ณผ ๊ฐ์ ์ต์ ๋ ์ ๊ณตํ๋ฏ๋ก ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
@Slf4j
@Component
public class AwsSqsConsumer {
@SqsListener(value = "${sqs-event.binghe-test-sqs}", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void consume(@Payload EventMessageSample event, @Headers Map<String, String> headers) {
log.info("[Consumed Message] id : {}, message : {}", event.getId(), event.getMessage());
// SqsMessageDeletionPolicy.NEVER ์ค์ ์ ๋ช
์์ ์ผ๋ก ์๋์ ๊ฐ์ด ๋ฉ์์ง๋ฅผ ์ญ์ ํ๋๋ก ack ์๋ต์ ๋ณด๋ผ ์ ์๋ค.
// ack.acknowledge();
}
}
์คํํด๋ณด๋ฉด ์๋์ ๊ฐ์ด ์์์ SNS๋ก Publishํ ์ด๋ฒคํธ ๋ฉ์์ง๋ฅผ Consumeํ ์ ์๋ค.
๐โโ๏ธ ์ญ์ ์ ์ฑ
๋ฉ์ธ์ง๋ฅผ Pollingํ๊ณ ์ฌ๋ฌ๊ฐ์ง ์ฒ๋ฆฌ๋ฅผ ์งํํํ์ ๋ฉ์์ง๋ฅผ ์ด๋ป๊ฒ ์ธ์ ์ญ์ ํ ์ง๋ฅผ ์ค์ ํ ์ ์๋ค.
ํ์๋ ON_SUCCESS
๋ง ์ฌ์ฉํด๋ณด๊ธดํ์ผ๋, ๋ก์ง์ ๋ฐ๋ผ ๋ค์ํ๊ฒ ์ค์ ํด์ ์ฌ์ฉํ ์ ์์ ๋ฏ ํ๋ค.
๊ตฌํํ๋ฉด์ ์์ฃผ ์ค์ํ๋ ๋ถ๋ถ์ ์ ๋ฆฌํ๋ค.
Spring Boot์์ SNS๋ก ์ด๋ฒคํธ๋ฅผ Publishํ ๋ ์ธ์ฆ ๊ด๋ จ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด, SNS ์ก์ธ์ค ์ฒ๋ฆฌ ๋ฐฉ์์ ์ดํด๋ด์ผํ๋ค.
SNS์์ ์ก์ธ์ค ์ฆ๋ช ํ ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ์์ ์ ๊ณตํ๋ค.
์ฐธ๊ณ : https://docs.aws.amazon.com/ko_kr/sns/latest/dg/sns-using-identity-based-policies.html
ํ์๋ ๋ชจ๋ AWS ํ๊ฒฝ์์ IAM ๊ธฐ๋ฐ์ผ๋ก ์ก์ธ์ค ์ฒ๋ฆฌ๋ฅผ ํ์ผ๋ฏ๋ก, ์ด์ ๊ด๋ จ๋ ๋ด์ฉ๋ง ๊ฐ๋จํ ์ ๋ฆฌํด๋ณด๋ฉด..
- EC2์์ SNS์ ์ด๋ฒคํธ๋ฅผ ์ ์กํ๋ ค๋ฉด IAM ์ค์ .
- SNS์ ๋ฉ์์ง๋ฅผ Publishํ๋ EC2๋ IAM์ SNS ๊ด๋ จ ๋ฉ์์ง Publish ๊ถํ์ด ์์ด์ผํ๋ฉฐ,
- SQS๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ Consumeํ๋ EC2๋ IAM์ ๋ฉ์์ง Consume ๊ถํ์ด ์์ด์ผํ๋ค.
๐โโ๏ธ Publisher, Consumer IAM ์ค์
SNS์ SQS์ ์ ๊ทผํ๋ Publisher์ Consumer ์๋ฒ์ ๋ชจ๋ IAM๋ฅผ ์ค์ ํด์ค๋ค.
ํ์๋ ์๋์ ๊ฐ์ด ๊ฐ์ ๊ณ์ ๋ด์ SNS์ SQS์ ํ ์ก์ธ์ค ๊ถํ์ ๋ถ์ฌํ IAM Role์ ์ค์ ํด์ฃผ์๋ค.
IAM๊ณผ ๊ด๋ จ๋ ์์ธํ ๋ด์ฉ์ IAM ๊ฐ๋ ๋ฅผ ์ฐธ๊ณ .
๐โโ๏ธ SNS Access Policy ์ค์
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__default_statement_ID",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive"
],
"Resource": "arn:aws:sns:ap-northeast-2:{source owner id}:binghe-test-sns",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "{source owner id}"
}
}
}
]
}
๊ทธ๋ฆฌ๊ณ SNS ์์ฑํ ๋๋ ์์ฑํ๊ณ ๋์ Acces Policy๋ฅผ ์ค์ ํ ์ ์๋๋ฐ, ์์ ๊ฐ์ด ๊ฐ์ ๊ณ์ ๋ด์์์ ์ก์ธ์ค ๊ถํ์ ๋ชจ๋ ๋ฑ๋กํด์ค๋ค.
๐โโ๏ธ SQS Access Policy ์ค์
๋ง์ง๋ง์ผ๋ก SNS -> SQS๋ก ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ์ ์๊ฒ, SQS์ SNS๋ก๋ถํฐ์ Access Policy๋ฅผ ์ถ๊ฐํด์ค๋ค.
{
"Version": "2012-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__owner_statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{source owner id}:root"
},
"Action": "SQS:*",
"Resource": "arn:aws:sqs:ap-northeast-2:{source owner id}:binghe-test"
},
{
"Sid": "topic-subscription-arn:aws:sns:ap-northeast-2:{source owner id}:binghe-test-sns",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "SQS:SendMessage",
"Resource": "arn:aws:sqs:ap-northeast-2:{source owner id}:binghe-test",
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:sns:ap-northeast-2:{source owner id}:binghe-test-sns"
}
}
}
]
}
SNS๋ SQS๋ก ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ๋ ์๋์ ๊ฐ์ด ์ฌ๋ฌ๊ฐ์ง ๋ด์ฉ์ Message Body์ ์ถ๊ฐํ์ฌ ์ ๋ฌํ๋ค.
Raw Message ์ค์ ์ ํ์ง ์๋ ๊ฒฝ์ฐ
{
"Type" : "Notification",
"MessageId" : "113432bb-e413-5c3b-8281-6f876adba7e4",
"TopicArn" : "arn:aws:sns:ap-northeast-2:{source owner id}:binghe-test-sns",
"Message" : "{\"id\":\"qwerqwer\",\"message\":\"test message 5\"}", // ๋ฉ์์ง ๋ด์ฉ
"Timestamp" : "2023-07-27T15:26:00.012Z",
"SignatureVersion" : "1",
"Signature" : "xxxx",
"SigningCertURL" : "https://sns.ap-northeast-2.amazonaws.com/SimpleNotificationService-xxxxxxxxxxxxx.pem",
"UnsubscribeURL" : "https://sns.ap-northeast-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-2:{source owner id}:binghe-test-sns:xxxxxxxxxx",
"MessageAttributes" : {
"contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"}
}
}
์ด๋ ๊ฒ๋๋ฉด Consumer์์ Consumeํ ๋ Jackson์ด ์ ๋๋ก ์ญ์ง๋ ฌํํ์ง๋ชปํด ๋ชจ๋ ๊ฐ์ null์ด ๋ค์ด๊ฐ ์ ์๋ค.
๊ทธ๋ฌ๋ฏ๋ก SNS -> SQS ์ฐ๋ํ๋ ์ค์ ์์ ์๋์ ๊ฐ์ด Enable Raw Message Delivery
์ค์ ์ ์ฒดํฌํด์ค์ผ ์ ๋๋ก ์ญ์ง๋ ฌํํ ์ ์๋ค.