
약 3개월 동안 진행했던 캠핑온탑 기능 보강 리팩토링 프로젝트가 끝났다.
그동안 아래의 여러 기능들을 구현하여 성공적으로 적용했다.
- 숙소 등록 시, 카카오맵 + 다음 우편번호를 이용해 도로명 주소로 위도, 경도 데이터 받기
- Redis 대기열을 이용한 선착순 쿠폰 발급
- Redis를 이용한 리프레시 토큰 발급
- AWS를 이용한 HTTPS 적용
- MongoDB, 웹소켓, STOMP를 이용한 실시간 일대일 채팅
- 카카오맵을 이용한 현 위치 기반 주변 숙소 조회
- 장바구니 내역 카카오페이 결제
- 할인 쿠폰 적용 결제
- 결제 내역 조회
- 결제 후 리뷰 작성
- 등등
최종 코드 병합 후 수정된 버전으로 배포를 완료했다.
그동안 갈고 닦은 실력을 오롯이 발휘하기 위해 낮과 밤을 가리지 않고 최선을 다했다.
그 결과, 리팩토링을 하기 전 계획했던 모든 기능들을 목표로 설정한 8월 내에 완료할 수 있었다.
내가 동생이지만 깍듯하게 팀장 대우를 해주고 군말없이 끝까지 함께해준 팀원 형님에게 무한한 감사를 보낸다.


지금 코드는 모놀리식으로 구성되어 있는데, 기능 보강 작업이 끝났기 때문에
이제 Micro Service로 전환하는 작업에 돌입하려고 한다.
현재 상황에서 내가 운영하고 있는 서비스의 도메인에 많은 사람들이 접속하고 있지 않기 때문에
사실 굳이 MSA로 전환할 필요는 없다.
하지만 이미 많은 회사들이 MSA 아키텍처 기반의 개발 환경을 갖추고 있고,
MSA 개발 경험을 갖춘 개발자에 대한 수요가 높아지고 있다.
게다가 이전에 MSA로 전환하는 연습을 할 때,
이메일 인증, 로그인 정도만 micro service로 전환하는 정도에서 중단했기에 내심 아쉬움도 있었다.
따라서 MSA로 리팩토링하는 작업을 하여 이에 대한 개발 경험과 노하우를 쌓아서,
입사 후 곧바로 적응할 수 있도록 준비를 해야겠다고 판단했다.
다만, MSA로 전환하면 나는 AWS의 프리티어 계정을 사용하고 있기에 리소스에 한계가 있어
모든 micro service들을 다른 서버에 배포할 수 없다는 맹점이 있다.
여러 개의 계정을 만들어서 할 수는 있지만, 현실적으로 유지보수를 하기 어렵다.
따라서 대안이 있는지 찾아보면서, 우선 로컬 환경에서 아래의 과정들을 진행하려고 한다.
- 기존의
monolithic에 있는 기능들을 하나씩micro service로 분리Vue로 구성되어 있는 프론트엔드의API호출 경로 변경DB이중화를 통한 읽기, 쓰기 서버 분리Eureka와API Gateway를 최대한 사용하기 위한 방식 연구 및 도입- 이 과정에서 사용될
Kafka,OpenFeign등을 이용한메세지 발행및구독방식 학습
아래 이론과 실습 내용은 부트캠프 수강 당시 실습한 내용을 첨부한 것이므로
캠핑온탑의 MSA 전환 화면은 맨 아래 성공 화면에서 보이도록 하겠다.
여담이지만 MSA 구조로 각 서버들이 이중화, 삼중화가 되어 있으면서
데이터베이스도 모두 이중화, 삼중화 등이 되어 있고
CI/CD Flow도 갖추어져 있어 자동 무중단 배포가 될 수 있는 환경에서 원없이 개발을 해보고 싶다.

Micro Service Architectureduplicate 해야한다.Java, 한 쪽에서는 Python 등Cloud가 등장하면서 많이 해결되었고 CI/CD 방식을 사용한 자동화 방식도 도입되었기 때문에MSA 방식이 현재 시점에서는 가장 좋은 Architecture이다. MSA 방식으로 할 필요는 없다.MSA 방식으로 바꾸는 방식으로 프로젝트를 진행한다. 

NETFLIX OSS라는 것을 만들어서 자체적으로 MSA 방식으로 구성한다.Eureka, Ribbon, … Circuit Breaker (차단기)circuit breaker 기능을 하는 프로그램 Spring이 위 open source를 보고 Spring Cloud를 만들어서Eureka, Hystrix, Ribbon 등을 Netfilx oss와 함께 사용할 수 있고, Spring cloud에서는 Config, Stream, Sleuth 등을 추가적으로 개발해서 제공하기에MSA 방식으로 개발을 더 편하게 할 수 있다. Spring Cloud에서 제공하는 기능들을 이용해서 구현한다. Zuul은 Spring Cloud API Gateway로 대체되었다.API Gateway에 각종 URL을 등록해놓고 gateway에서 어떤 서버로 가라고 알려 준다.)MSAAPI Gateway를 사용하는 곳도 있고 사용하지 않는 곳도 있다.API Gateway가 shut down되면 전체 서비스가 마비되는 것이기 때문에API Gateway를 이중화, 삼중화해서 사용하는 경우도 있다.AxonFramework - Event Handling LayerKafkaCI/CD와 서버가 많이 필요하면 클라우드가 단점을 보완해준다. MSA Architecture, Java 파일도 변경되어야 한다. controller, Service, Repository 구성으로 되어 있는데 (monolithic 구조이니까)MSA에서는 구조상 아래의 장점을 극대화할 수 있다.3 layer가 종속되어 있는데 Java에서 종속성을 느슨하게 만들어주는 문법 예제이다.
List<String> a = new ArrayList<>():
ArrayList 객체를 만들어서 할당해 주었는데
원래는 ArrayList가 List에 종속되어 있어야 한다.
하지만 List에는 ArrayList 뿐만 아니라 다른 List들도 객체를 만들어서 할당할 수 있다.
⇒ 종속성이 느슨한 것이다.
MSA에서는 service를 interface로 만들고 serviceImpl로 구현하는 방식으로 하고controller에서 interface의 의존성을 주입 받아서 사용하는 방식으로 사용한다.
Web Adapter→Controller
Use case→Service
Persistent Adapter→Repository
⇒package를Adapter,Application,Domain으로 나눌 것.
입력 포트의 interface를 통해야 한다. client에게 요청을 받고 db에 저장하고 client에게 반환하는 것 뿐만 아니라micro service들 간에 통신이 필요하다. 외부 시스템 어댑터 - 입력 포트 - 유즈 케이스 - 출력 포트 - 외부 시스템 어댑터port에 어댑터를 연결해서 사용하는 구조controller라고 이름 불러서 부르는 것과 같다. Port, Adapter가 가장 중요한 개념이다.
Hexagonal Architecture로 구현해보자.MSA 아님!! 입력 포트출력 포트 웹 어댑터에서 입력 포트로 들어오는 것도 있고외부 시스템 어댑터에서 입력 포트로 들어오는 것도 있다.
웹 어댑터→/adapter/in/web입력 포트→/application/port유즈 케이스→/application/service출력 포트→/application/port영속성 어댑터→/adapter/out/persistence(repository)
웹 어댑터에서 들어와서 입력 포트 → 유즈 케이스 → 출력 포트 → 출력 어댑터 유즈 케이스웹 어댑터는 입력 포트를 가져와서 사용하는 것이기 때문에 변경될 일이 없다.유즈 케이스에 입력 받은 데이터가 들어오기 전에 검증을 한다.검증 dto를 만든다. Domain부터 만들고 시작한다. 

/adapter/in/web/RegisterMemberController 실행/application/port/in/RegisterMemberUseCase의 구현체인/application/service/RegisterMemberService 실행/application/port/out/RegisterMemberPort의 구현체인/adapter/persistence/MemberPersistenceAdapter 실행SpringJpaEntity 이용해 저장
저장하고 영속성 어댑터에서 출력 포트를 거쳐서 유즈 케이스를 거쳐 엔티티 갔다가 다시
입력 포트로 와서 웹 어댑터를 통해 client로 최종 반환한다.

나중에는 application layer만 변경하고 맨 앞, 뒤 layer는 코드를 변경하지 않아도 된다.

Bean으로 등록해야 하니까 @Componet로 등록했는데
@Persistence라는 annotation을 만들어서 달아주자.
New → module (프로젝트 안에 또 다른 project 생성)
아직 monolithic이고 MSA이 방식 아니다.

common에 사용할 주요 module들을 추가하고 annotation을 변경한다.
(controller, service)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface WebAdapter {
@AliasFor(annotation = Component.class)
String value() default "";
}

그리고 기존 src는 삭제하고 안에 main, test를 새롭게 module 만들어서 그 안의 src에 복사한다.
**New modules**로 해야 한다!!(Spring Initializer x)
기존에는 /abc라면 결제 기능인데 /def로 새롭게 따로 만들어서 구현한 후
프론트엔드에서 url 바꿔주고 잘 되면 기존 monolithic에서 작동하던 결제 코드를 삭제한다.
기존 프로젝트에서 하나씩 떼서 개발해자.
cf.) Stored Procedure 스토어드 프로시저
MSA에는 분산 트랜잭션 처리를 해야 하는데 이 부분이 어렵다. DB에 저장하고 다른 곳에도 똑같이 저장한다.Elastic Search로 검색 속도 향상 및 DB 부하 분산 AWS Dynamo DBBatch 처리 Kafka 서버로 메세지를 보내고 받을 것.Transaction 처리를 Axon Framework로 처리할 것. Command and Query Responsibility Segregation)도메인을 가장 중점적으로 생각해서 Hexagonal Architecture로 만들고Kafka 등으로 어떻게 주고 받을 수 있게 할 것인지 고민하는 과정 DDD Query), 명령(Command) 단으로 분리해서Query)에서 그 event를 consume해서db를 조회하는 것이다.db에서 가져와서 조회 단에서 client로 전달하는 것이 아니다.→ Kafka를 통해 message queue를 통해서 진행한다.
Kafka 책 추천.message queue 역할을 하는 대표적인 시스템이 Kafka monolithic에서 MSA로 넘어갈 때 어떤 message queue를 사용할까?RabbitMQ, Redis queue 등도 있다. message queue에 쌓아 놓으면 서버가 뻗어도 데이터를 가져오는 기능이 Kafka가 좋다. Message queue 자체가 뻗으면…?RabbitMQ는 사라지는데 Kafka는 디스크 기반이라 사라지지 않는다.(하지만 메모리에서 동작) RabbitMQ는 메모리 방식이라 속도는 빠르지만 뻗으면 사라진다. (안전 X)RabbitMQ는 주로 캐시 서버를 사용한다. message를 주고 받아야 하는데 그럼 이 message를 주고 받는AWS Kafka / Confluent Kafkagateway라는 이름의 module 추가하고 pom.xml에 spring cloud dependency 추가<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.3</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
Spring Cloud의 version을 잘 맞춰서 적용해야 한다.
GatewayApplication class 파일 추가
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
Spring Cloud Gateway의 실행 프로그램이 되는 것. 8080으로 실행될 테니까
server:
port: 9999
Adapter annotation 수정 pom.xml에 dependency 메인 pom.xml과common의 pom.xml, gateway의 pom.xml 변경micro service에서 사용하는 라이브러리들만 알맞게 추가해주는 것이 좋다. lombokspring-boot-starter-testcommonspring-boot-starter-validationspring-boot-starter-webspring-boot-starter-data-jpamysql-connector-jspring-boot-starter-validationcommonserver:
port: 9999
application:
name: GATEWAY-SERVICE
cloud:
gateway:
routes:
- id: main-service
uri: lb://MAIN-SERVICE
predicates:
- Path=/main/**
application.yml
MSA에서는 어떻게 구현할 것인가<방법 1>
인증 및 인가 MSA를 만들고 (회원 가입, 로그인)response 받아야 함.<방법 2>
Spring Security에서는 Filter를 만들어서 토큰을 검증한다.
API Gateway에 토큰을 확인하는 모듈을 만들어서 개발한다.
port를 9999로 해서 gateway에 요청했고 gateway - application.yml 설정에 따라
8080/member/signup으로 요청이 가서 최종 회원 가입이 된 결과를 확인했다.
Kafka 서버는 2대만 있으면 된다. Kafka 서버가 죽었는지 살았는지 관리하는 서버 messaging queue 서버의 메인 역할zookeeper가 정상적으로 관리를 해야 잘 작동됨. (zookeeper에 종속되어 있다.) Spring에서 Producer 개발해야 함.message 보내는 역할 Spring에서 Consumer 개발해야 함.message 받는 역할 3대만 준비하라고 한 이유는 zookeeper를 apache kafka에서 사용하지 않을 거라고 해서.Zookeeper 서버와 Kafka 브로커 서버를 1개의 서버에서 실행할 것이다. HDFS(hadoop), HBase, mahout, …
Kafka 설치wget https://downloads.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz
tar -xvzf kafka_2.13-3.6.1.tgz
cd kafka_2.13-3.6.1
java11 설치
실무에서는
Kafka 최소 3대zookeeper 최소 3대우리는 서버 1대에 한 것이다.
./bin/zookeeper-server-start.sh ./config/zookeeper.properties
./bin/kafka-server-start.sh ./config/server.properties

zookeeper, kafka 실행 완료.
3대로 구성할까?IDC 센터를 보면 서버 장비들이 막 들어가 있는데 서버를 넣어 놓는 큰 칸을 rack이라고 한다.rack에 2대를 놓고 다른 rack에 1대를 놓는다.rack에 넣어 놓으면 서버가 뻗었을 때, 다 뻗어 버리기 때문에1대는 다른 rack에 넣고 살려 둔다. 대표가 있고 상의를 해서 결정한다.3대 간에도 투표를 해서 결정하는데 짝수면 결정이 나지 않으므로cluster 구성을 할 때, 대부분 3대, 5대, … 이런 식으로 서버를 늘리는 것이다. 브로커/zookeeper 서버 Producer Consumer <!-- producer -->
./bin/kafka-console-producer.sh --topic test --bootstrap-server SERVER12_IP:9092
<!-- consumer -->
./bin/kafka-console-consumer.sh --topic test --bootstrap-server SERVER12_IP:9092
vi config/server.properties
advertised.listeners=PLAINTEXT://SERVER12_IP:9092
서버에서 변경

zookeeper, kafka 정상 실행 확인 완료

producer → consumer message 전송 성공

Eureka 서버, main-service(기존 monolithic) 등 실행 화면
이제 Monolithic이었던 프로젝트를 MSA 구조가 될 수 있도록 준비만 마쳤다.
단순히 Monolithic프로젝트를 하나의 서비스로 전환하고,
Eureka 서버와 API Gateway 등만 추가한 것이다.
아직 설치한 Kafka를 사용하지도, OpenFeign으로 메세지를 주고 받는 작업도 하지 않았다.
앞으로 유저 이메일 인증, 로그인 기능부터 하나씩 뜯어서
개별적인 Micro Service로 전환하는 작업을 할 것이다.