오늘 100일 코드 챌린지 시리즈에서는 Amazon SQS를 사용하여 springboot로 개발된 마이크로서비스를 분리하는 방법을 보여 드리겠습니다.
Amazon SQS(Simple Queue Service)는 애플리케이션이 sendyg를 통해 통신하고 대기열에 메시지를 저장하고 수신할 수 있도록 도와주는 클라우드 서비스입니다. 이는 소비자가 처리할 준비가 될 때까지 저장되는 대기줄과 같습니다. 이렇게 하면 시스템이 과부하되는 것을 방지하고 메시지가 손실되지 않도록 할 수 있습니다.
SQS 대기열의 각 메시지를 처리하는 Spring Boot 앱을 생성하여 SQS 메시지를 사용하는 방법을 보여줍니다. CDK(Java)를 사용하여 구축된 인프라에는 다음이 포함됩니다.
CDK(Java)를 사용하여 필요한 인프라 설정
public class NetworkContruct extends Construct { private final IVpc vpc; public NetworkContruct(Construct scope, String id, StackProps props) { super(scope, id); this.vpc = new Vpc( this, "VpcResource", VpcProps.builder() .vpcName("my-vpc") .enableDnsHostnames(true) .enableDnsSupport(true) .createInternetGateway(true) .ipProtocol(IpProtocol.IPV4_ONLY) .ipAddresses(IpAddresses.cidr("10.0.0.1/16")) .maxAzs(1) .subnetConfiguration( List.of( SubnetConfiguration.builder() .name("Public-Subnet") .mapPublicIpOnLaunch(true) .subnetType(SubnetType.PUBLIC) .build())) .build()); } public IVpc getVpc() { return vpc; } }
이 CDK 구성은 다음을 생성합니다.
?? my-vpc라는 이름의 VPC와 DNS 호스트 이름 활성화가 활성화되었습니다.
?? 리소스가 퍼블릭 IP를 연결할 수 있도록 하는 Public-Subnet이라는 퍼블릭 서브넷(구성된 경우).
?? 인터넷 트래픽을 활성화하는 인터넷 게이트웨이입니다.
public class QueueConstruct extends Construct { private final IQueue queue; public QueueConstruct(Construct scope, String id, IVpc vpc, StackProps props) { super(scope, id); IQueue dlq = new Queue( this, "DeadLetterQueue", QueueProps.builder() .deliveryDelay(Duration.millis(0)) .retentionPeriod(Duration.days(10)) .queueName("my-queue-dlq") .build()); DeadLetterQueue deadLetterQueue = DeadLetterQueue.builder() .queue(dlq) .maxReceiveCount(32) .build(); this.queue = new Queue( this, "SQSQueueResource", QueueProps.builder() .queueName("my-queue") .retentionPeriod(Duration.minutes(15)) .visibilityTimeout(Duration.seconds(90)) .deadLetterQueue(deadLetterQueue) .build()); } public IQueue getQueue() { return queue; } }
위의 CDK 구성은 다음 리소스를 생성합니다.
// ComputerProps.java public record ComputerProps(IVpc vpc, String sqsQueueArn) {} // ComputerConstruct.java public class ComputerConstruct extends Construct { private final IInstance computer; public ComputerConstruct( Construct scope, String id, ComputerProps computerProps, StackProps props) { super(scope, id); SecurityGroup securityGroup = new SecurityGroup( this, "WebserverSGResource", SecurityGroupProps.builder() .allowAllOutbound(true) .securityGroupName("Webserver-security-group") .disableInlineRules(true) .vpc(computerProps.vpc()) .description("Allow trafic from/to webserver instance") .build()); securityGroup.addIngressRule(Peer.anyIpv4(), Port.SSH, "Allow ssh traffic"); securityGroup.addIngressRule(Peer.anyIpv4(), Port.tcp(8089), "Allow traffic from 8089 port"); KeyPair keyPair = new KeyPair( this, "KeyPairResource", KeyPairProps.builder() .keyPairName("ws-keypair") .account(Objects.requireNonNull(props.getEnv()).getAccount()) .type(KeyPairType.RSA) .format(KeyPairFormat.PEM) .build()); new CfnOutput( this, "KeyPairId", CfnOutputProps.builder().value(keyPair.getKeyPairId()).build()); Instance ec2Instance = new Instance( this, "WebServerInstanceResource", InstanceProps.builder() .securityGroup(securityGroup) .keyPair(keyPair) .instanceName("Webserver-Instance") .machineImage( MachineImage.lookup( LookupMachineImageProps.builder() .name("*ubuntu*") .filters( Map.ofEntries( Map.entry("image-id", List.of("ami-0e86e20dae9224db8")), Map.entry("architecture", List.of("x86_64")))) .windows(false) .build())) .vpc(computerProps.vpc()) .role(buildInstanceRole(computerProps)) .instanceType(InstanceType.of(InstanceClass.T2, InstanceSize.MICRO)) .associatePublicIpAddress(true) .blockDevices( List.of( BlockDevice.builder() .mappingEnabled(true) .deviceName("/dev/sda1") .volume( BlockDeviceVolume.ebs( 10, EbsDeviceOptions.builder() .deleteOnTermination(true) .volumeType(EbsDeviceVolumeType.GP3) .build())) .build())) .userDataCausesReplacement(true) .vpcSubnets(SubnetSelection.builder().subnetType(SubnetType.PUBLIC).build()) .build()); UserData userData = UserData.forLinux(); userData.addCommands(readFile("./webserver-startup.sh")); ec2Instance.addUserData(userData.render()); this.computer = ec2Instance; } public IInstance getComputer() { return computer; } private String readFile(String filename) { InputStream scriptFileStream = getClass().getClassLoader().getResourceAsStream(filename); try { assert scriptFileStream != null; try (InputStreamReader isr = new InputStreamReader(scriptFileStream, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr)) { StringBuilder content = new StringBuilder(); String line; while ((line = br.readLine()) != null) { content.append(line).append("\n"); } return content.toString(); } } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } private IRole buildInstanceRole(ComputerProps props) { return new Role( this, "WebserverInstanceRoleResource", RoleProps.builder() .roleName("webserver-role") .assumedBy(new ServicePrincipal("ec2.amazonaws.com")) .path("/") .inlinePolicies( Map.ofEntries( Map.entry( "sqs", new PolicyDocument( PolicyDocumentProps.builder() .assignSids(true) .statements( List.of( new PolicyStatement( PolicyStatementProps.builder() .effect(Effect.ALLOW) .actions( List.of( "sqs:DeleteMessage", "sqs:ReceiveMessage", "sqs:SendMessage", "sqs:GetQueueAttributes", "sqs:GetQueueUrl")) .resources(List.of(props.sqsQueueArn())) .build()))) .build())))) .build()); } }
위의 CDK 구성은 다음 리소스를 생성합니다.
// MyStack.java public class MyStack extends Stack { public MyStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); IVpc vpc = new NetworkContruct(this, "NetworkResource", props).getVpc(); IQueue queue = new QueueConstruct(this, "QueueResource", vpc, props).getQueue(); IInstance webserver = new ComputerConstruct( this, "ComputerResource", new ComputerProps(vpc, queue.getQueueArn()), props) .getComputer(); } } // Day17App.java public class Day017App { public static void main(final String[] args) { App app = new App(); new MyStack(app,"Day017Stack", StackProps.builder() .env( Environment.builder() .account(System.getenv("CDK_DEFAULT_ACCOUNT")) .region(System.getenv("CDK_DEFAULT_REGION")) .build()) .build()); app.synth(); } }
일을 단순하게 유지하고 인생을 복잡하게 만들지 않기 위해 Spring Cloud AWS Docs를 사용하겠습니다.[↗]
Spring Cloud AWS는 Spring Framework 및 Spring Boot 애플리케이션에서 AWS 관리형 서비스 사용을 단순화합니다. 잘 알려진 Spring 관용어와 API를 사용하여 AWS 제공 서비스와 상호 작용하는 편리한 방법을 제공합니다.
내 프로젝트에서 SQS 서비스를 구성하기 위해 구성 클래스에 다음 Bean을 추가하겠습니다.
@Configuration public class ApplicationConfiguration { @Bean public AwsRegionProvider customRegionProvider() { return new InstanceProfileRegionProvider(); } @Bean public AwsCredentialsProvider customInstanceCredProvider() { return InstanceProfileCredentialsProvider.builder() .build(); } }
모든 새로운 메시지를 캡처하고 해당 내용을 인쇄하는 청취자입니다.
@Slf4j @Component public class ExampleSQSConsumer { @SqsListener(queueNames = { "my-queue" }) // ?? public void listen(String payload) { log.info("******************* SQS Payload ***************"); log.info("Message Content: {}", payload); log.info("Received At: {}", Date.from(Instant.now())); log.info("************************************************"); } }
내 GitHub 저장소에서 전체 프로젝트를 찾을 수 있습니다[↗]
⚠️⚠️ 배포 명령을 실행하기 전에 호스트 컴퓨터에 Java가 설치되어 있는지 확인하세요. 이 인프라를 구축하기 위해 MacO에서 Java 21을 사용했습니다.
어디에서든 터미널을 열고 다음 명령을 실행하세요.
<p>git clone https://github.com/nivekalara237/100DaysTerraformAWSDevops.git<br> cd 100DaysTerraformAWSDevops/day_017<br> cdk bootstrap --profile cdk-user<br> cdk deploy --profile cdk-user Day017Stack</p>
GitHub Repo에서 전체 소스 코드를 찾을 수 있습니다↗
위 내용은 Amazon SQS를 사용하여 Spring Boot 소비자 애플리케이션 구축: CDK(클라우드 개발 키트)를 사용하여 인프라 설정의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!