🍃 Communication Types
- Synchronous HTTP communication ( 동기 )
- 요청이 들어오면 해당 요청을 처리 할 떄 다른 서비스의 내용이 필요하면 내용을 가져다가 요청을 처리하는 과정을 한 프로세스로 보고 진행
- Astnchronous communication over AMQP ( 비동기 )
- AMQP 를 사용해서 비동기 방식으로 요청을 메세지 브로커로 전달하고 각 서비스에 들어온 요청을 전달하여 각 서비스가 해당 요청을 처리하면서 하는 비동기 방식으로 사용하는 것
- 유저서비스가 오더서비스에게 요청할 데이터가 있다면 eureka에 등록된 서비스의 이름을 찾아서 해당 요청을 전달하여 반환받는 방식
- 랜덤하게 만들어진 포트때문에 같은 서비스로써 여러개가 등록되어 있다면 라운드로빈의 특성을 사용해서 번갈아가며 사용한다.
Round Robin 이란?
시분할 시스템을 위해 선점형 스케줄링의 하나로써 프로세스들 사이에 우선순위를 두지 않고, 순서대로 시간 단위로 CPU를 할당하는 방식의 CPU 스케줄링 알고리즘이다
모든 프로세스들에게 공정하게 부여하기 위한 방법으로 일정시간을 할당하고 끝나면 다른 프로세스에게 전달하는 방식을 이야기 한다.
🍃 RestTemplate
- 전통적으로 많이 사용되는 API로써 기존의 자바로 만들어진 웹 어플리케이션 간에 GET, POST의 방식으로써 또 다른 API를 부를 수 있는 방식이다
- 인스턴스를 생성하고 GET,POST 정하고 파라미터가 필요하다면 등록하고 반환받아올수있다.
- 사용자의 정보를 요청했다고 가정해보자
- 유저 서비스는 요청을 처리하는데 이때 사용자가 주문한 데이터가 필요하여 오더 서비스를 호출해야한다
- 이때 REST template 를 사용해서 오더 서비스의 API로 요청하게 된다.
♪ 사용법
● Userservice에 RestTemplate 등록
● UserServiceImpl 변경
- 기존에 order내용을 굳이 넣지 않고 반환했다면 RestTemplate 를 이용해서 반환하기
- restTemplate 를 이용해서 오더서비스에 데이터를 요청하는 것을 확인 할 수있다. 또한 Enviroment 에 orderservice의 url을 설정해주어야 한다.
- 이후 오더 서비스에서 반환하는 내용을 확인해보자
● TEST
- 이제 사용자의 정보와 주문한 내용이 오더 서비스를 통해 가져와졌고 Response값에 잘 들어온것을 알 수 있다.
- 이런식으로 Eureka 서버에 등록된 이름으로 변경을 해줘도 정상적으로 작동을 하는 것을 알 수있다. 물론 restTemplate 에 LoadBalanced 라는 어노테이션을 붙여주어야 한다.
🍃 FeignClient 사용하기
- RestTamplate 보다 훨씬 직관적이고 간단하다.
- FeignClient ▶ HTTP Client
- REST Call 을 추상화 한 Spring Cloud Netflix 라이브러리이다.
- 사용방법
- 호출하려는 HTTP EndPoint에 대한 Interface를 생성한다.
- @FeignClient 어노테이션을 선언해주면 된다
- Load Balance도 지원한다
♪ 사용법
● 라이브러리 추가
- openfeign 라이브러리르 추가한다
● UserServiceApplication
● Client.OrderServiceClient
- FeignClient 를 사용할땐 인터페이스를 사용해서 원하는 요청을 전달하는 것이다.
- 오더 서비스와 연결되어 있는 OrderServiceClient는 @FeignClient를 통해 연결되고 name은 해당 서비스의 이름이여야 한다.
- 원하는 메소드의 이름을 정하고 해당 서비스의 endPoint를 MethodMapping을 하여 진행한다. 반환값또한 해당 API와 같은 값으로 해주어야 한다.
● UserServiceImpl
- 인터페이스를 사용하기 위해 선언을 해주고 의존성을 주입해준다.
- 이렇게 단 한 줄로 RestTemplate에서 사용한 내용을 전부 사용 할 수 있다. 매우 편리해진 것을 알 수 있다.
● TEST
- 변경된 것은 RestTemplate를 사용하다가 FeignClient로 변경된것 뿐이다 과정은 여전히 똑같다.
- 결과가 같다는 것을 확인 하는 것으로 정상 작동한다는 것을 확인 할 수 있다.
만든 사람은 굉장히 작업하기 편한 라이브러리인 것을 확인 할 수 있지만 협업을 통해 다른 사람들이 보는 코드로 따진다면 생각보다 불편한 방법이 될 수 있다. 때문에 편리하다는 이유로 무작정 사용한다기 보다는 적재적소에 잘 선택하여 사용하는 것이 올바르다고 할 수 있다.
🍃 FeignClient 의 예외 처리
♪ FeignClient 사용 시 발생한 로그 추적
● application.yml
● UserServiceApplication
- bean 으로써 등록을 해야하는데 이때 import 가 feign.Logger이다.
♪ FeignClient 사용 시 발생한 예외 처리
● 예외 발생 시키기
- 기존에 정상적으로 작동하던 FeignClient의 EndPoint를 orders가 아닌 orders_ng로 바꿔 잘못된 값으로 전달하게 만든다.
♪ 발생한 로그와 예외
● 로그 확인
- FeignClient를 사용하였을때 발생하는 로그를 볼 수 있다.
- 이때도 잘못된 주소를 받은 것을 확인 할 수 있다.
- 전달한 헤더 값과 반환 받은 payload 가 무엇인지도 확인 할 수 있다.
● 예외 발생
- 주문을 하고 주문한 내역을 확인하는 과정을 똑같이 진행하였을 경우 나오는 경고 메세지가 나타난다
- 해당 문구는 orders_ng 라는 EndPoint를 찾을 수 없다는 것이다. 또한 status 또한 500으로 서버의 문제로 보인다.
● 예외 처리 ( 해결 )
- 발생한 예외 (FeignException)을 catch하는 방식으로 제작된 에러를 잡아 메세지를 log로 보이게 바꿔준다.
- 그 결과 사용자에게는 정상적으로 200OK 의 값이 전달되고 log로 설정한 에러 메세지가 서버에게 전달되는 것을 볼 수 있다.
♪ FeignErrorDecode
- 위처럼 FeignClient에서 발생한 에러가 어떤 에러인지 상태 코드를 통해 어떤 결과값을 나타낼지 작업 할 수 있도록 한다
● error.feignErrorDecoder
- 에러가 발생 했을때 어떻게 처리를 할 지 정의해주는 클래스가 필요하다.
- ErrorDecoder 를 implements 하여 필수 구현 메소드인 decode를 만들어주고 switch를 통해서 각 상태에 따라 어떤 반환값을 만들어 줄 것인지 정의한다
- 우리는 앞서 발생한 에러가 404이기 때문에 404에 대한 처리를 해줄 것이다. getOrders로 요청했기 때문에 contains를 통해 확인하고 해당 에러가 발생하면 사용자의 쇼핑 목록이 없다는 것을 반환한다.
- default로는 그냥 에러를 이유만 적어 보낸다.
● UserServiceImpl
- 예외처리를 해준 덕분에 Impl에서 굳이 예외처리를 다시 해줄 필요가 없다 때문에 다시 코드가 원상 복구 된 것을 알 수 있다.
● TEST
- 기존에 방식은 500 status 를 반환하는 404에러가 발생하는 것을 알 수 있다. 하지만 예외처리를 하고 status를 404로 넘겨주면서 해당 오류는 서버가 아닌 클라이언트 쪽에 있다는 것을 확인시켜 줄 수 있다. 또한 메세지에 사용자의 주문이 없다 라고 메세지 까지 보내는 것을 확인 할 수 있다.
♨ TIP
- 이러한 메세지는 Config 설정에서도 다룰 수 있다.
- 설정파일을 사용하기 위해 FeignErrorDecoder부분도 수정을 해야했다
- @Component를 통해 빈을 등록해주었고 환경설정을 의존성을 주입해 사용하는 것을 볼 수 있다. 또한 FeignErrorDecoder 가 빈으로 등록되면서 기존에 @Bean을 통해 등록된 내용은 더 이상 사용되지 않아 삭제해도 된다는 것을 알 수 있다
- 똑같은 방식으로 진행하면 이렇게 오류가 똑같이 발생하는 것을 알 수 있다.
🍃 데이터 동기화 문제
♪ 문제의 발생
- 하나의 마이크로 서비스는 여러 방법으로 작동을 할 수 있고 그로 인해 하나의 서비스를 다른 포트로써 여러개 작동 할 수가 있다.
- 만약 오더 서비스를 두개 이상으로 켜놨을때 어떻게 데이터를 동기화 할 수 있을까? 무슨말이냐면 서비스를 두 개 이상 작동해놓으면 라운드로빈에 의해 번갈아가며 사용된다는 것을 알 수 있다. 하지만 그것은 서버의 입장이고 사용자의 입장에서는 각각의 서비스에 저장된 데이터를 내가 주문했다면 전부 불러와야 한다는 것이다.
- 이런식으로 각각의 DB를 가진 두개의 서비스에서 사용자의 구매 목록을 가져올때 자신의 데이터만을 가져올 수 밖에 없는 것이다.
● 분산된 데이터를 가져왔을때의 문제
- 이렇게 문제가 발생하는 것이다. 각각의 서비스는 각각의 DB에 사용자의 주문 목록을 저장해 놓을테고 이를 불러올때도 번갈아가며 불러오기 때문에 어떨때는 1번 어떨때는 2번 이런식으로 가져오게 되는 것이다.
♪ 해결 방법
1. 하나의 DB를 사용하기
- 물리적으로 떨어져있는 인스턴스의 내용을 하나의 DB에 저장하기 위해서는 트랜잭션 처리를 정말 잘 해주어야 한다.
2. DB를 동기화 한다. ( RabbitMQ, Kafka )
- 이전에 배웠던 RabbitMQ라던가 이후에 배울 Kafka를 통해 서로의 DB를 동기화 하는 것이다. 저장될 내용을 메세지 큐에 담아 한쪽에서 발생한 데이터를 전달해서 연결된 서비스가 있다면 해당 서비스의 DB를 업데이트 해주는 것이다.
3. 1번과 2번의 방법을 통합 ( Message Queuing + 한개의 DB )
- 데이터가 들어온다면 DB를 신경쓰지 않고 Message Queuing Server에 전달하고 Message Queuing Server는 해당 데이터를 DB에 전달한다. 각각의 인스턴스는 DB로 접근해서 데이터를 가져오는데 이때 DB는 하나이기 때문에 동시성 문제도 해결 할 수 있다.
- Message Queuing Server는 1초에 수만건의 데이터를 처리 할 수 있을만큼 대용량 데이터 처리에 특화되어 있기 때문에 순차적으로 메세지를 사용하고자 하는 곳에 바로 전달하는 능력이 된다 때문에 동시성 문제가 바로 해결이 된다.
'MSA > MSA 강좌 - 이도원 강사님' 카테고리의 다른 글
👨👧👦11. 데이터 동기화를 위한 Apache Kafka활용하기 (2) (0) | 2024.04.11 |
---|---|
👨👧👦10. 데이터 동기화를 위한 Apache Kafka활용하기 (1) (0) | 2024.04.09 |
👨👧👦8. 설정 정보와 암호화 처리 (Encryption 과 Decryption) (1) | 2024.04.03 |
👨👧👦6. Spring Cloud Config (0) | 2024.04.01 |
👨👧👦5. User Microservice 와 API Gateway - Security와 Filter 적용 (0) | 2024.03.30 |