반응형

시작에 앞서

이 포스팅 글은 제가 SA로 재직하면서 개인적으로 만든 AWS Workshop을 기반으로 작성되었습니다. 이 포스팅에서 언급되는 워크샵이라는 단어는 '실습' 정도로 해석하시면 됩니다.

Introduction

MSA(Micro Service Architecture)를 Loose Coupling하게 구축하기 위해 꼭 필요한 EDA(Event Driven Architecture)를 Amazon MSK와 Java로 실습해 보면서 이해하는 워크샵입니다.

시나리오

EDA(Event Driven Architecture) 워크샵에서 사용할 서비스는 고객(Customer)와 주문(Order) 2개의 서비스로 구성되어 있으며 신규 고객을 등록할때 이름(Name)과 그 고객이 사용수 있는 선지불금(Credit)을 입력합니다. 고객이 등록되고 나면 고객ID(Customer ID)를 리턴 받습니다. 주문(Order)은 이 고객ID를 이용해 할 수 있으나 보유한 선지불금(Credit) 내에서 할 수 있습니다. 만약 고객ID에 있는 Credit을 초과하는 주문을 했을 경우 주문은 취소되고 선지불금은 주문 이전의 금액으로 원복되어야 합니다.

 

이 시나리오의 유즈케이스 다이어그램은 아래와 같습니다.

 

이 워크샵 시나리오를 통해 살펴볼 내용은 고객(Customer) 서비스와 주문(Order) 서비스가 어떻게 Loose Coupling 되어 있는지 이해하도록 합니다. 또한 각 서비스(마이크로서비스)간 Happy Path 내에서 Transaction 관리를 어떻게 하는 지 이해하도록 합니다.

주) 이 예제에서는 2022년 6월 이후 AWS에 적용된 새로운 UI 환경 기준으로 설명합니다.
주) 주문(Order)서비스는 주문 테이블에 상태 플래그가 있으며 주문이 들어 왔을때는 (pending), 주문이 성공하면 (Success), 주문이 실패하면 (Fail) 을 표시할 수 있습니다.

 

워크샵 아키텍처

본 EDA 워크샵에서는 3개의 AZ에 1개의 Public Subnet, 2개의 Private Subnet을 구성할 것이며 Public Subnet에는 2개의 EC2 인스턴스가 서로 다른 AZ에 있도록 구성할 겁니다.
Private Subnet에는 Amazon MSK Cluster를 3개의 AZ에 걸쳐 구성할 예정이며 실습을 위해 1개의 파티션이 2개의 Topic을 구성해 MKS를 테스트해 볼 예정입니다.
Database는 Spring Boot에서 In-Memory DB인 H2 DB를 각각의 EC2 인스턴스에서 사용할 수 있도록 구성하는 것이 Defalut 실습이고 Optional로 H2을 대신해 Private Subnet에 Amazon Aurora(MySQL)를 이용해 2개의 Aurora Cluster를 구성해 실습하는 방법도 소개하고 있습니다.
 

 


 

Configuration

Network Setup

VPC 생성

VPC > Your VPCs > Create VPC

VPC settings 화면에서 필요한 네트워크 리소스를 한꺼번에 생성하기 위해 VPC and more 를 선택합니다. 각 항목은 아래와 같이 선택 및 입력합니다.
  • Auto-generate: msk-vpc
  • Number of Availability Zones(AZs): 3
  • Number of public subnets : 3
  • Number of private subnets : 3
  • NAT gateways: None
  • VPC endpoints: None

Network 구성요소가 생성 완료 되었습니다.

 

MSK VPC Security Group 생성

다음에 설치할 Amazon MSK 및 Public Subnet의 SpringBoot 인스터스들을를 위한 보안 그룹을 먼저 생성해 줍니다.

VPC > Security Groups > Create security group
Basic details > Security group name : msk-security-group
Basic details > Description : msk security group
Basic details > VPC > msk-vpc
Inbound rules > Type : Custom TCP, Protocol : TCP, Prot range : 2181, Source: Anywhere IPv4
Inbound rules > Type : Custom TCP, Protocol : TCP, Prot range : 9092, Source: Anywhere IPv4

 

EC2 VPC Security Group 생성

VPC > Security Groups > Create security group
Basic details > Security group name : internet-security-group
Basic details > Description : internet security group
Basic details > VPC > msk-vpc
Inbound rules > Type : Custom TCP, Protocol : TCP, Prot range : 8080, Source: Anywhere IPv4
Inbound rules > Type : SSH, Protocol : TCP, Prot range : 22, Source: Anywhere IPv4

보안그룹 생성이 완료되었습니다.

 


 

Amazon MSK Setup

MSK Cluster Setting

aws console에서 Amazon MSK를 찾아 MSK 화면으로 이동합니다.
 
다음의 순서대로 설정합니다.
Amazon MSK > Clusters > Create cluster
Create method > Cluster creation method : Custom create
Cluster name > Cluster name: eda-msk
Cluster type > Provisioned
Apache Kafka Version > Apache Kafka version > 2.6.2
Brokers> Broker type: kafka.t3.small
Brokers> Number of zones : 3
Brokers> Number of brokers per zon : 1
나머지는 기본 값 선택 후 Next
 
Next를 클릭합니다.

Networking

Amazon MSK >Clusters >Create cluster
Networking> VPC > msk-vpc
Networking> First zone > Zone > us-east-1a
Networking> First zone > Subnet > msk-vpc-subnet-private1-us-east-1a
Networking> Second zone > Zone > us-east-1b
Networking> Second zone > Subnet > msk-vpc-subnet-private1-us-east-1b
Networking> Third zone > Zone > us-east-1c
Networking> Third zone > Subnet > msk-vpc-subnet-private1-us-east-1c
Networking> Security groups in Amazon EC2 > msk-security-gruoup (default는 꼭 삭제)

Next를 클릭합니다.

Security

다른 항목은 모두 기본으로 두고 Access control methods의 Unauthenticated access와 Encryption영역의 Between clients and brokers 영역에 Plaintext만 체크합니다.
Amazon MSK > Clusters > Create cluster
Security settings> Access control methods> Unauthenticated access 체크
Security settings> Encryption > Plaintext 체크

Next를 클릭합니다.

 

Monitoring and tags

Amazon MSK > Clusters > Create cluster > Monitoring and tags
Monitoring > Amazon CloudWatch metrics for this cluster > Enhanced partition-level monitoring
Monitoring > Broker log delivery > Deliver to Amazon CloudWatch Logs
Monitoring > Broker log delivery > Log group> visit Amazon CloudWatch Logs console 클릭 MSK를 위한 CloudWatch Log Group을 만드는 브라우저 화면에서 아래와 같이 Log Group을 생성합니다.

로그 그룹 생성을 완료했으면 다시 MSK Cluster 생성 화면으로 돌아와서 Browse 버튼을 클릭해 방금 생성한 CloudWatch Log Group을 선택합니다.

제일 아래 Cluster tags - optional 에 Key : Name을 Value-optional에 MSK-EDA를 입력합니다.
나머지는 기본값으로 두고 Next
 

지금까지 입력한 값 리뷰 후 Create Cluster

생성시 최소 30분에서 60분 이상 소요됩니다.

 


Key Pairs

사용할 EC2의 원격 접속을 위한 Key Pairs를 생성합니다.

EC2 > Key Pairs > Create key pair를 선택합니다.

Key pair > Name : msk-key-pair

Create key pair를 클릭해 key pairs 파일을 다운 받아 놓도록 합니다.

 


EC2 Setup

실제 개발이나 운영환경이라면 컨테이너화 되어 ECS나 EKS등에 배포되겠지만 우리는 빠른 데모를 위해 Public Subnet에 있는 EC2 2개에 Public IP를 부여하고 각각의 EC2 인스턴스에 Custmer-Service와 Order-Service를 빌드해 EDA를 테스트할 예정입니다.

 

EC2 Setup

EC2 > Instances > Launch an instance

Name and tags> Name: customer-service #customer-service ec2를 모두 생성하면 나중에 order-service라는 이름으로 ec2를 아래의 순서대로 똑같이 하나 더 생성하도록 합니다.(붉은색 주석부분만 변경합니다.)
Application and OS Images(Amazon Machine Image) > Amazon Linux
Application and OS Images(Amazon Machine Image) > Amazon Machine Image(AMI) > Amazon Linux 2 AMI(HVM) - Kernel 5.10, SSD Volume Type
Instance type> Instance type: t2.medium

 

Network 설정

Network settings > Edit
Network settings > VPC - required > msk-vpc
Network settings> Subnet > msk-vpc-subnet-public1-us-east-1a #customer-service ec2의 경우 msk-vpc-subnet-public2-us-east-1b를 선택합니다.
Network settings> Auto-assign public IP > Enable
Network settings> Firewall(security groups) > Select existing security group
Network settings> Common security groups > internet-security-group
Advanced detail> User Data
*모두 기본값으로 두고 아래의 쉘 스크립트 내용을 복사해 Advanced details의 User data에 복사해 둘 것
Advanced details> User data > #customer-service EC2는 아래를 User Data에 붙여 넣습니다.
#!/bin/bash 
#yum update
sudo yum update -y
sudo yum install java-11-amazon-corretto.x86_64 << EOF
y
EOF
#kafka library download
wget https://archive.apache.org/dist/kafka/2.6.2/kafka_2.12-2.6.2.tgz -P /home/ec2-user;
#extract archive file
tar -xzf /home/ec2-user/kafka_2.12-2.6.2.tgz -C /home/ec2-user/
#Install git in your EC2 instance
sudo yum install git -y;
#git repository clone
git clone -b customer-v1.0 https://github.com/sharplee7/amazon-msk-spring-boot-eda-exmple.git /home/ec2-user/amazon-msk-spring-boot-eda-exmple
sudo chown ec2-user:ec2-user /home/ec2-user -R

#order-service EC2는 아래를 User Data에 붙여 넣습니다.

#!/bin/bash 
#yum update
sudo yum update -y
sudo yum install java-11-amazon-corretto.x86_64 << EOF
y
EOF
#kafka library download
wget https://archive.apache.org/dist/kafka/2.6.2/kafka_2.12-2.6.2.tgz -P /home/ec2-user;
#extract archive file
tar -xzf /home/ec2-user/kafka_2.12-2.6.2.tgz -C /home/ec2-user/
#Install git in your EC2 instance
sudo yum install git -y;
#git repository clone
git clone -b order-v1.0 https://github.com/sharplee7/amazon-msk-spring-boot-eda-exmple.git /home/ec2-user/amazon-msk-spring-boot-eda-exmple
sudo chown ec2-user:ec2-user /home/ec2-user -R

모두 완료후 Launch instance 클릭

대쉬보드에서 방금 만든 EC2 Instance가 Pending > Running 에서 Initializaing에서 2/2 checks passed가 될때까지 대기합니다.

2/2 checks passed로 변경

여기까지 했으면 customer-service가 완료되었습니다.

 

이제, order-service 인스턴스를 지금과 같은 과정을 다시 한 번 진행해서 만들도록 합니다.(instance name과 user data는 빨간색 부분을 반드시 참조하세요)

2개의 EC2 Instance를 만드시면 아래의 이미지 같이 됩니다.


Amzon MSK Topic Creation

customer-service ec2 접속

EC2 관리 콘솔의 좌측 메뉴에서 Instances를 찾아 customer-service를 선택하고 상단의 Connect 버튼을 클릭합니다.

 

Kafka Topic 생성

cd /home/ec2-user/kafka_2.12-2.6.2
미리 만들었던 MSK(Managed Streaming for Apache Kafka)의 zookeeper endpoint를 확인하기 위해 Amazon MSK > Clusters > eda-msk를 클릭합니다.

eda-msk의 관리 화면의 우측 상단에 있는 "View client information" 버튼을 클릭합니다.

View client information 화면에서 Apache Zookeeper connection 항목의 Plaintext 엔드포인트를 복사합니다.

 

실습 위한 토픽 생성

아래의 명령구문에서 --zookeeper 다음의 값을 앞서 복사한 엔드포인트로 대체합니다.
토픽은 customerTopic과 orderTopic 2개를 만듭니다.
bin/kafka-topics.sh --create --zookeeper z-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181,z-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181,z-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181 --replication-factor 3 --partitions 1 --topic customerTopic
bin/kafka-topics.sh --create --zookeeper z-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181,z-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181,z-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:2181 --replication-factor 3 --partitions 1 --topic orderTopic

 

생성된 토픽 확인

msk 화면에서 이번엔 Bootstrap servers의 접속 엔드포인트를 복사해 옵니다.

아래의 명령어를 통해 생성된 토픽을 확인합니다. --bootstrap-server 다음의 url은 본인의 msk url로 변경합니다.

bin/kafka-topics.sh --bootstrap-server b-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092 --list

앞서 생성한 2개의 토픽을 확인 할수 있습니다.

 


 

Amazon Aurora Setup

금번 실습에서 DB는 별도의 설치 없이 Spring Boot 실행 시 In-Memory DB로 사용되는 H2 DB를 사용하고 있으나, Aurora를 사용할 경우 customer-db와 order-db 라는 두 개의 클러스터를 만들어 테스트해 볼 수 있습니다.

Aurora 설치

Amazon RDS > Dashboard > Create database

Create database > Choose a database creation method : Standard create

Engine options > Engine type> Amazon Aurora
Engine options > Edition> Amazon Aurora MySQL-Compatable Edition

Templates > Dev/Test

Settings > DB cluster identifier : customer-db (customer-db를 모두 완료하면 똑같은 순서로 order-db를 하나 더 만듭니다.)
Settings > Credentials Settings > Master username: admin
Settings > Credentials Settings > Master password: admin123
 
Instance configuration > DB instance class > Burstable classes(includes t classes)
Instance configuration > DB instance class > db.t3.small

Availability & durability > Multi-AZ deployment > Don't create an Aurora Replica

Connectivity > Compute resource > Connect to an EC2 compute resource
Connectivity > EC2 Instance > customer-service (order-db를 만들때는 order-service를 선택한다.)
Connectivity > VPC security group(firewall) > Create new
Connectivity > VPC security group(firewall) > New VPC security group name : aurora-security-group (두 번째 db인 order-db를 만들때는 Choose existing을 체크 customer-db에서 만든 aurora-security-group을 선택합니다.)

order-db 생성 시 security group 선택

Additional configuration> Database options > Initial database name : customerdb (#order-db 클러스터 생성시에는 orderdb라고 입력)

모든 항목을 입력했으면 create database를 클릭해 DB 클러스터를 생성완료한다.
customer-db 클러스터를 생성했으면 order-db 클러스터를 하나 더 생성 하도록 합니다. (하나의 클러스터를 생성하는데 20 ~ 30분이 소요되므로 생성 후 완료될 때 까지 기다리지 말고 새로운 클러스터 생성을 권장합니다.)
 

Aurora 구성이 완료되었습니다.

 

 


 

EBA with Spring Boot and MSK

우리가 구성하는 이 데모 시스템의 최종 아키텍처는 다음과 같습니다.

최종 아키텍처 구성

 


 

Customer-Service 구현

Architecture

 
customer-service EC2 Instance 접속
EC2 > Instances > customer-service 를 차례대로 선택하고 우측 상단의 Connect 버튼을 클릭합니다.

EC2 Instance Connect > Connect를 클릭해 customer-service EC2 Instance에 접속합니다.

EC2 Instance Connect이용해 EC2 콘솔 작업을 진행할 수 도 있지만 Instant Connect는 Session 유지 시간이 짧은 단점이 있습니다. 만약 보다 긴 Session 유지 시간을 원하시는 분들은 앞서 생성한 Cloud9을 통해 접속해 작업하는 것을 권장합니다.(ssh를 통해 Customer EC2 및 Order EC2 개별 접속 필요)
Connect MSK
EC2 instance의 홈 디렉토리에 있는 amazon-msk-spring-boot-eda-exmple/customer-service 디렉토리로 이동합니다.
 
cd amazon-msk-spring-boot-eda-exmple/customer-service/

customer-service의 구조를 살펴 봅니다.

위와 같이 콘솔상에서 디렉토리 구조를 보고 싶다면 tree를 설치하도록 합니.
sudo yum install -y tree
설치가 끝났다면 tree 명령어로 디렉토리 구조를 살펴 봅니다.

MSK(Kafka)의 접속을 위한 접속 정보는 위 캡처에서 'Configuration' 영역의 applicaiton.yml 파일에서 작성합니다. vi를 이용해 applicaiton.yml 파일을 열도록 합니다.

server:
  port: 8080
  servlet:
    context-path: /customer-order/customer-service

spring:
  application:
    name : customer-service
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
    username: sa
    password:
  h2:
    console:
      enabled: true
      path: /console
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    database: H2
    show-sql: true

customer:
  topic:
    name: customerTopic

order:
  topic:
    name: orderTopic

kafka:
  bootstrapAddress: #여기를 수정

bootstrapAddress의 localhost:9092 부분을 이전에 설치한 eda-msk 클러스터의 bootstrap 주소로 변경합니다. (bootstrap 정보는 Amazon MSK > Clusters > eda-msk > View client information에서 복사 할 수 있습니다.)

Customer-service Compile
Aurora DB를 사용하지 않고 내장된 H2 DB를 사용할 경우 아래와 같이 실행합니다.
Aurora DB를 사용하는 경우는 아래의 Aurora DB(Optional)으로 이동합니다.
*컴파일을 완료하면 customer-service테스트로 이동합니다.
 
customer-service 를 아래와 같은 명령어를 입력해 컴파일 하도록 합니다.
cd $HOME
cd amazon-msk-spring-boot-eda-exmple
cd customer-service
./gradlew build

컴파일이 정상 완료되었다면 customer-service를 다음의 명령어로 실행해 봅니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/customer-service/build/libs
java -jar customer-service-0.0.1-SNAPSHOT.jar

콘솔에 에러가 없이 정상적으로 실행되었다면 웹 브라우저를 통해 swagger-ui 및 H2 DB console에 접속해 보도록 하겠습니다.
EC2 > Instances > customer-service > Details > Public IPv4 address 에서 Public IP를 확인합니다.
http://18.234.x.x:8080/customer-order/customer-service/swagger-ui/

Amazon Aurora DB를 사용(Optional)

vi 등의 편집기를 이용해 아래와 같이 build.gradle 파일의 h2 db 라이브러리를 mysql로 변경합니다
cd $HOME/amazon-msk-spring-boot-eda-exmple/customer-service
vi build.gradle

plugins {
	id 'org.springframework.boot' version '2.2.6.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.kafka:spring-kafka'
	implementation 'commons-lang:commons-lang:2.6'
	implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
	implementation 'io.springfox:springfox-swagger-ui:3.0.0'
	implementation "io.springfox:springfox-boot-starter:3.0.0"
	
	runtimeOnly 'mysql:mysql-connector-java'
//	runtimeOnly 'com.h2database:h2'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}


tasks.named('test') {
	useJUnitPlatform()
}
Aurora MYSQL 라이브러리를 사용하겠다고 선언했다면 이제 spring boot에서 사용할 datasource와 JPA 설정에 대한 변경을 할 차례입니다.
Amazon RDS > databases > customer-db > Related > Endpoints > Writer instance의 End Point를 복사해 둡니다.

application.yml 파일이 있는 디렉토리로 이동합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/customer-service/src/main/resources
vi 등의 에디터를 이용해 기존 application.yml의 datasource와 그 하의 설정, 그리고 h2와 그 하위 설정 마지막으로 jpa와 그 하의 설정 영역을 삭제 혹은 #으로 주석 처리합니다.
application.yml의 aurora mysql을 위한 datasource 영역은 다음과 같이 작성합니다. 여기에서 엔드포인트는 앞서 복사한 Writer instance의 End Point를 적고 포트번호는 3306을 데이터베이스는 customerdb라고 입력합니다.
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://{엔드포인트}:{포트번호}/{(초기)데이터베이스}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: {마스터 사용자 이름}
    password: {마스터 암호}

또한 jpa 영역은 다음과 같이 입력합니다.

  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    database: mysql
    generate-ddl: true
    show-sql: true

실제 예)

server:
  port: 8080
  servlet:
    context-path: /customer-order/customer-service

spring:
  application:
    name : customer-service

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://customer-db.cluster-cxuhzmhetcvn.us-east-1.rds.amazonaws.com:3306/customerdb?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: admin
    password: admin123
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    database: mysql
    generate-ddl: true
    show-sql: true
    
#  datasource:
#    driver-class-name: org.h2.Driver
#    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
#    username: sa
#    password:
#  h2:
#    console:
#      enabled: true
#      path: /console
#  jpa:
#    database-platform: org.hibernate.dialect.H2Dialect
#    database: H2
#    show-sql: true

customer:
  topic:
    name: customerTopic

order:
  topic:
    name: orderTopic

kafka:
  bootstrapAddress: b-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092

변경된 내용으로 새롭게 컴파일 하도록 합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/customer-service/
./gradlew build

새로 컴파일된 라이브러릴 다시 시작해 보도록 합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/customer-service/build/libs
java -jar customer-service-0.0.1-SNAPSHOT.jar

 

customer-service 테스트

http://18.234.x.x:8080/customer-order/customer-service/swagger-ui/

POST의 customers를 클릭하고 'Try it out'을 클릭해서 amount(금액)와 name(고객명)을 입력 후 Execute를 클릭해 등록되는 값을 확인합니다.(응답된 값에서 customerId를 확인합니다.)

마찬가리조 swagger-ui 화면에서 GET을 클릭해 아래와 같이 customerId에 앞서 확인한 customerId를 입력 후 Execute 버튼을 클릭해 방금 입력한 데이터가 조회되지는 확인해 봅니다.

Aurora DB 접속을 통한 데이터 직접 조회

sudo yum install https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
sudo yum install mysql-community-server

customerdb 접속 및 데이터 등록된 데이터 확인

mysql -u admin -p -h [customer-db cluster end point]

show databases;
use customerdb;
show tables;
select * from customer;

# linux에서 현재 열린 포트의 프로세스 번호를 조회합니다.
netstat -tnlp
# linux에서 현재 
kill -9 [PROCESS_ID]
# 테스트 없이 빠른 컴파일
./gradlew build --exclude-task test

 

Order-Service 구현

Architecture

 

order-service EC2 Instance 접속

EC2 > Instances > order-service 를 차례대로 선택하고 우측 상단의 Connect 버튼을 클릭합니다.

EC2 Instance Connect > Connect를 클릭해 customer-service EC2 Instance에 접속합니다.

 

Connect MSK

EC2 instance의 홈 디렉토리에 있는 amazon-msk-spring-boot-eda-exmple/order-service 디렉토리로 이동합니다.

cd amazon-msk-spring-boot-eda-exmple/order-service/

vi를 이용해 applicaiton.yml 파일을 열도록 합니다.

vi /home/ec2-user/amazon-msk-spring-boot-eda-exmple/order-service/src/main/resources/application.yml

 

server port 8080으로 변경을 포함해 kafka bootstrapAddress를 다음과 깉아 변경합니다.

server:
  port: 8080
  servlet:
    context-path: /customer-order/order-service

spring:
  application:
    name : order-service
#  datasource:
#    driver-class-name: com.mysql.jdbc.Driver
#    url: jdbc:mysql://order-db.cluster-cxuhzmhetcvn.us-east-1.rds.amazonaws.com:3306/orderdb?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
#    username: admin
#    password: admin123
#  jpa:
#    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
#    hibernate:
#      database: mysql
#      generate-ddl: true
#      show-sql: true
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
    username: sa
    password: 
  h2:
    console:
      enabled: true
      path: /console
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    database: H2
    show-sql: true

customer:
  topic:
    name: customerTopic

order:
  topic:
    name: orderTopic

kafka:
  bootstrapAddress: b-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092

bootstrapAddress의 localhost:9092 부분을 이전에 설치한 eda-msk 클러스터의 bootstrap 주소로 변경합니다. (bootstrap 정보는 Amazon MSK > Clusters > eda-msk > View client information에서 복사 할 수 있습니다.)

 

order-service Compile

Aurora DB를 사용하지 않고 내장된 H2 DB를 사용할 경우 아래와 같이 실행합니다.
Aurora DB를 사용하는 경우는 아래의 Aurora DB(Optional)으로 이동합니다.
*컴파일을 완료하면 order-service테스트로 이동합니다.
 
customer-service 를 아래와 같은 명령어를 입력해 컴파일 하도록 합니다.
cd $HOME
cd amazon-msk-spring-boot-eda-exmple
cd order-service
./gradlew build

컴파일이 정상 완료되었다면 order-service를 다음의 명령어로 실행해 봅니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/order-service/build/libs
java -jar order-service-0.0.1-SNAPSHOT.jar

콘솔에 에러가 없이 정상적으로 실행되었다면 웹 브라우저를 통해 swagger-ui 및 H2 DB console에 접속해 보도록 하겠습니다.
EC2 > Instances > order-service > Details > Public IPv4 address 에서 Public IP를 확인합니다.

http://54.89.x.x:8080/customer-order/order-service/swagger-ui/

 

Amazon Aurora DB를 사용(Optional)

vi 등의 편집기를 이용해 아래와 같이 build.gradle 파일의 h2 db 라이브러리를 mysql로 변경합니다
cd $HOME/amazon-msk-spring-boot-eda-exmple/order-service
vi build.gradle

plugins {
	id 'org.springframework.boot' version '2.2.6.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.kafka:spring-kafka'
	implementation 'commons-lang:commons-lang:2.6'
	implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
	implementation 'io.springfox:springfox-swagger-ui:3.0.0'
	implementation io.springfox:springfox-boot-starter:3.0.0

	runtimeOnly 'mysql:mysql-connector-java'
//	runtimeOnly 'com.h2database:h2'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}


tasks.named('test') {
	useJUnitPlatform()
}
Aurora MYSQL 라이브러리를 사용하겠다고 선언했다면 이제 spring boot에서 사용할 datasource와 JPA 설정에 대한 변경을 할 차례입니다.
Amazon RDS > databases > order-db > Related > Endpoints > Writer instance의 End Point를 복사해 둡니다.
 

application.yml 파일이 있는 디렉토리로 이동합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/order-service/src/main/resources
vi 등의 에디터를 이용해 기존 application.yml의 datasource와 그 하의 설정, 그리고 h2와 그 하위 설정 마지막으로 jpa와 그 하의 설정 영역을 삭제 혹은 #으로 주석 처리합니다.
application.yml의 aurora mysql을 위한 datasource 영역은 다음과 같이 작성합니다. 여기에서 엔드포인트는 앞서 복사한 Writer instance의 End Point를 적고 포트번호는 3306을 데이터베이스는 customerdb라고 입력합니다.
 
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://{엔드포인트}:{포트번호}/{(초기)데이터베이스}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: {마스터 사용자 이름}
    password: {마스터 암호}

또한 jpa 영역은 다음과 같이 입력합니다.

  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    database: mysql
    generate-ddl: true
    show-sql: true

실제 예)

server:
  port: 8080
  servlet:
    context-path: /customer-order/order-service

spring:
  application:
    name : order-service
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://order-db.cluster-cxuhzmhetcvn.us-east-1.rds.amazonaws.com:3306/orderdb?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: admin
    password: admin123
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    hibernate:
      database: mysql
      generate-ddl: true
      show-sql: true
#  datasource:
#    driver-class-name: org.h2.Driver
#    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
#    username: sa
#    password:
#  h2:
#    console:
#      enabled: true
#      path: /console
#  jpa:
#    database-platform: org.hibernate.dialect.H2Dialect
#    database: H2
#    show-sql: true

customer:
  topic:
    name: customerTopic

order:
  topic:
    name: orderTopic

kafka:
  bootstrapAddress: b-1.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-2.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092,b-3.edamsk.8orhx7.c17.kafka.us-east-1.amazonaws.com:9092
#kafka:
#  bootstrapAddress: localhost:9092

변경된 내용으로 새롭게 컴파일 하도록 합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/order-service/
./gradlew build

새로 컴파일된 라이브러리 다시 시작해 보도록 합니다.

cd $HOME/amazon-msk-spring-boot-eda-exmple/order-service/build/libs
java -jar order-service-0.0.1-SNAPSHOT.jar

 

order-service 테스트

http://18.234.x.x:8080/customer-order/customer-service/swagger-ui/

POST의 customers를 클릭하고 'Try it out'을 클릭해서 amount(금액)와 name(고객명)을 입력 후 Execute를 클릭해 등록되는 값을 확인합니다.(응답된 값에서 customerId를 확인합니다.)

마찬가지 swagger-ui 화면에서 GET을 클릭해 아래와 같이 customerId에 앞서 확인한 customerId를 입력 후 Execute 버튼을 클릭해 방금 입력한 데이터가 조회되지는 확인해 봅니다.

 

Aurora DB 접속을 통한 데이터 직접 조회

sudo yum install https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
sudo yum install mysql-community-server

orderdb 접속 및 데이터 등록된 데이터 확인

mysql -u admin -p -h [order-db cluster end point]

show databases;
use orderdb;
show tables;
select * from order;

# linux에서 현재 열린 포트의 프로세스 번호를 조회합니다.
netstat -tnlp
# linux에서 현재
kill -9 [PROCESS_ID]
# 테스트 없이 빠른 컴파일
./gradlew build --exclude-task test

Customer-Order의 EDA 이해

고객(Customer) 등록

  1. customer-service 의 swagger-ui에 접속합니다. http://[customer-service]:8080/customer-order/customer-service/swagger-ui/
  2. POST API를 클합한 후 Drop down된 화면에서 Try it out 버튼을 클릭합니다.
  3. Request Body 창의 amount에 10000 을, name에 hong gil dong을 입력한 후 Execute 버튼을 클릭합니다. (hong gil dong이란 회원을 등록하며 credit을 10000원 설정했습니다.)
  4. Server에서 Response된 Response body로 수신된 customerId를 기억해 둡니다.
 
 
 
 
(화면의 예에서 회신 받은 customerId는 3입니다.)
화면의 예에서 회신 받은 customerId는 3입니다.
 

주문(Order) 등록

  • order-service 의 swagger-ui에 접속합니다. http://[order-service]:8080/customer-order/order-service/swagger-ui/
  • POST API를 클합한 후 Drop down된 화면에서 Try it out 버튼을 클릭합니다.
  • Request Body 창의 customerId에 앞서 고객(Customer) 등록 할 때 회신 받은 customerId를 입력하고, orderTotal amount에 1000을 입력합니다. 모든 입력이 끝났으면 Execute 버튼을 클릭합니다.
  • order-service 서버로부터 응답 받은 orderId와 order 상태를 확인합니다.
 
(예에서 서버로부터 받은 orderId는 1번이고 주문 상태는 'PENDING'입니다.)
 
 

고객(Customer) Credit 차감 확인

  • 다시 customer-service의 swagger-ui 화면으로 돌아가서 GET 메뉴를 클릭한 후 Try it out 버튼을 클릭합니다.
  • customerId 항목에 아까 등록한 고객(Customer)의 id를 입력하고 Execute를 클릭합니다.
  • 앞서 주문(Order)에서 1000을 사용했기 때문에 10000에서 9000으로 줄어든 Credit을 확인 할 수 있습니다.
 

 

주문(Order) 상태 확인

  • 1000원의 주문으로 고객(Customer)의 Credit이 차감된 것을 확인했습니다. PENDING 상태였던 주문 상태를 확인하기 위해 order-service의 swagger-ui로 전환합니다.
  • GET 메뉴를 클릭한 후 Try it out 버튼을 클릭한 후 orderId 란에 앞서 주문할때 서버로 부터 응답 받은 orderId를 입력한 후 Execute 버튼을 클릭합니다.
  • 주문 상태가 APPROVED 인 확인합니다.
 
 

초과 주문(Order)

  • order-service의 swagger-ui 화면에서 POST API를 클합한 후 Drop down된 화면에서 Try it out 버튼을 클릭합니다.
  • Request Body 창의 customerId에 앞서 고객(Customer) 등록 할 때 회신 받은 customerId를 입력하고, orderTotal amount에 10000을 입력합니다. 모든 입력이 끝났으면 Execute 버튼을 클릭합니다.
  • order-service 서버로부터 응답 받은 orderId와 order 상태(PENDING)를 확인합니다.
 

고객(Customer) Credit 확인

  • customer-service의 swagger-ui 화면으로 전환하여 GET 을 클릭 후 Try it out 버튼을 클릭합니다.
  • customerId에 앞서 등록한 고객의 customerId를 입력한 후 Execute 버튼을 클릭합니다.
  • customer의 현재 보유한 credit이 9000인지 확인 합니다.
 

주문(Order) 상태 확인

  • 고객(Customer)의 보유한 Credit 보다 초과 주문을 해서 실제 차감이 발생하지 않은 것은 확인했습니다. PENDING 상태였던 주문 상태를 확인하기 위해 order-service의 swagger-ui로 전환합니다.
  • GET 메뉴를 클릭한 후 Try it out 버튼을 클릭한 후 orderId 란에 앞서 주문할때 서버로 부터 응답 받은 orderId를 입력한 후 Execute 버튼을 클릭합니다.
  • 주문 상태가 REJECTED 인 것 확인합니다.
 

Loose coupling

  • customer-service EC2를 중지 시킵니다.
  • order-service swagger-ui에서 앞서 등록한 customerId로 1000원을 추가 주문합니다.
  • order-service 로 부터 받은 orderState 가 'PENDING'인 것을 확인합니다.
  • order-service의 swagger-ui 화면에서 GET을 클릭해 다시 한번 orderId의 상태가 PENDING인 것을 확인합니다.
  • customer-service EC2 인스턴스와 customer-service****.jar 파일을 다시 시작합니다.
  • order-service의 swagger-ui 화면에서 GET을 클릭해 앞서 주문한 orderId의 상태를 다시 한 번 확인합니다.(APPROVED)
  • customer-service의 swagger-ui화면에서 GET을 클릭 한 후 customerId에 앞서 우리가 테스트 중인 customerId를 입력 후 Execute 버튼을 클릭합니다.
  • creditLimit이 8000으로 변경된 것을 확인합니다.
 
지금까지 EDA 아키텍처의 동작 방식과 트랜잭션 처리에 대해 간단히 알아 보았습니다. 현재의 예제가 어떻게 동작하는지 개인별 토론을 권장합니다.

 

반응형

+ Recent posts