들어가기 전에
이번 프로젝트에서는 "MSA를 적용해서 해보자" 라는 이야기가 나왔을 때, MSA가 무엇인지조차 몰랐다. 그래서 MSA에 대해 찾아보고, 알아보았는데 이미 많은 회사들이 MSA로 전환을 시도했다는 사실을 알게 되었다.
MSA의 기본 개념은 간단하다. Micro Service Architecture 라는 이름 그대로, "하나의 어플리케이션을 다수의 독립적인 서비스들의 집합으로 구성하는 것" 이다. MSA에 대한 자세한 내용은 다음글을 참고하면 된다.
https://savingbe.tistory.com/42
[Architecture] 유잔씨의 MSA 이모저모 알아보기
들어가기 전에이번 프로젝트는 MSA 구조로 하자!! 라는 말이 나왔을 때 MSA가 뭐야?? 라는 생각부터 들었다. 계속 공부해도 이렇게 모르는게 많다니. 그래도 일단 모르면 공부해서 적용 해야지 뭐
savingbe.tistory.com
문제점
나쁜 시스템이 나쁜 개발 문화를 만든다
- 많은 개발팀의 코드를 한번에 배포 : 많은 시간과 인력 필요
- 개발자들이 새로운 기술 접할 기회가 없다
- IDE에 띄우는 것 조차 버거운 개발 환경 : 200만 라인의 공통코드로 메모리 부족
Project Vine : 11번가 점진적 MSA 전환 프로젝트
가운데 나무를 200만 라인의 공통코드라 하고 그 주변의 덩굴처럼 MSA로 개발하다보면 가운데 공통코드는 사라지고 MSA 로만 서비스를 유지할 수 있을 것이다.
점진적인 MSA 전환 방법
기존 시스템은 로그인 부터 주문서 들어가기 전까지 모든 내용들이 하나의 서버에 들어있었다. 가장 간단한 웹서비스 개발 방법. 웹/모바일은 따로 있었지만 거의 하나의 거대한 WAS에 존재했다.
MSA로 분리
- 업부 도메인 별로 서버 분리
- MSA 문제가 생기면 언제든 기존 코드로 돌아갈 수 있게 하였다
구축하는 과정에서 가장 중요한 것은 넷플리스에서 제공하는 다음 3가지이다.
- Hystrix
- Ribbon
- Eurka
Hystrix
넷플리스가 만든 Fault Tolerance Library
- Circuit Breaker
- Fallback
- Thread Isolation
- Timeout
Hystrix 적용하기
Hystrixs는 spring cloud와 무관하다. 개발자들이 팀차원의 결정없이 개인이 결정해서 적용할 수 있다.
1) Hystrixs Annotation 사용
2) HystrixsCommand 상속
Hystrixs Command 호출할 때 벌어지는 일
1) 이 메소드를 Intercept 하여 대신 실행한다.
: Thread Isolation
2) 메소드의 실행 결과 성공 혹은 실패(Exception) 발생 여부를 기록하고 통계를 낸다. 통계에 따라 Circuit Open 여부 결정.
: Circuit Breaker
3) 실패한 경우 사용자가 제공한 메소드를 대신 실행한다.
: Fallback
4) 특정시간 동안 메소드가 종료되지 않는 경우 Exception을 발생시킨다.
: Timeout
Circuit Breaker
일정시간 동안 일정 개수 이상의 호출이 발생한 경우, 일정 비율이상의 에러가 발생하면 → Circuit Open(호출차단)
누전 차단기와 동일. 서킷이 오픈되면 메소드 호출했음에도 디버그 찍어오면 메소드 바디안에 안들어온다. 누군가 가로채서 exception에 바로 튕겨낸다. 서비스 안정성에 매우 도움된다. 장애가 전파되지 않아야 한다.
일정 시간 경과 후 단 한개의 요청에 대해 호출을 허용하며(Half Open), 이 호출이 성공하면 → Circuit Close(호출허용)
단위는 신중하게 정해야 한다. Circuit Breaker는 Command Key 단위로 생성된다.
Fallback
Fallback으로 지정된 메소드는 다음의 경우에 원본 메소드 대신 실행된다. 정상적이지 않은 것 동작하면 무조건 fallback.
- Circuit Open
- Any Exception (HystrixBadRequest Exception 제외)
- Semaphore / ThreadPool Rejection
- Timeout
그러나 잘못 사용하면 비즈니스 로직의 에러나 장애 상황을 감추게 된다.
HystrixBadRequest Exception - Hystrix가 정의한 특수한 예외상황
사용자의 코드에서 HystrixBadRequest Exception을 발생시키면,
이 오류는 Fallback을 실행하지 않으며,
Circuit Open을 위한 통계에도 집계되지 않는다
로직 상에서 생긴 문제가 아니라 로직을 호출한 caller가 잘못한 일 (ex) null을 넘기거나 parameter를 잘못 넘기거나)은 HystrixBadRequest Exception로 wrapping 해서 Throw 해야 한다.
Timeout
Hystrix에서는 Circuit Breaker 단위로(CommandKey 단위로) Timeout을 설정할 수 있다.
Isolation
Circuit Breaker 별로 지정 가능
- Semaphore
Circuit Breaker 별로 semaphore가 하나씩 붙어있다. Semaphore 별로 최대 동시 요청 개수를 지정한다.
특정 시스템에 지연이 일어나서 전체 시스템의 지연으로 이어지는 것을 막기 위해 시스템 뒤에서 적정 용량을 제한함으로써 적정 이상의 request가 들어가면 reject가 일어난다. → Fallback 실행
Command를 호출한 Caller Thread에서 메소드를 실행한다.
※ Timeout이 제 시간에 발생하지 못함
- Tread (default)
Circuit Breaker 별로 사용할 Thread Pool을 지정(ThreadPoolKey)한다.
Circuit Breaker : Thread Pool = N : 1 관계 가능
최대 개수 초과시 Thread Pool Rejection 발생한다. → Fallback 실행
Command를 호출한 Thread가 아닌 ThreadPool에서 메소드 실행한다.
※ 실제 메소드의 실행은 다른 Thread 에서 실행되므로 Thread Local 사용 시 주의 필요
Ribbon
넷플릭스가 만든 Software Load Balancer를 내장한 REST Library - Client Load Balancer with HTTP Client
하드웨어 인프라 도움 없이도 다수의 서버 목록을 Road Balancer에서 호출 할 수 있게된다.
Spring Cloud에서는 옵션이나 설정으로만 접하고 Riboon 클라이언트를 사용자가 직접 사용하지 않는다.
Spring Cloud에는 HTTP 통신이 필요한 요소에 내장되어 있다.
- Zuul API
- Rest Template(@LoadBalanced)
- Spring Cloud Feign - 선언적 Http Client
Eureka
넷플릭스가 만든 Dynamic Service Discovery
- 등록 : 서버가 자신의 서비스 이름(종류)와 IP 주소, 포트를 등록
- 조회 : 서비스 이름(종류)을 갖고 서버 목록을 조회
Eureka를 Spring Cloud에 탑재하게 되면 Spring Application의 Life Cycle과 맞물려 돌아간다.
1) Server 시작 시 Eureka 서버에 자동으로 자신의 상태를 등록 (UP)
2) 주기적 HeartBeat으로 Eureka Server에 자신이 살아 있음을 알림
3) Server 종료 시 Eureka 서버에 자신의 상태 변경(Down) 혹은 자신의 목록 삭제
4) Eureka 상에 등록 된 이름은 'spring.application.name'
Ribbon이랑 결합해 Riboon이 서버 목록 가져오는데 사용이 된다.
Eureka + Ribbon in Spring Cloud
하나의 서버에 Eureka Client와 Ribbon Client가 함께 설정되면 Spring Cloud는 다음의 Ribbon Bean을 대체
1. ServerList<Server>
-- 기본 : ConfigurationBasedServerList
-- 변경 : DiscoveryEnabledNIWSServerList
2. IPing
-- 기본 : DummyPing
-- 변경 : NIWSDicoeryPing
서버의 목록을 yml에서 직접 설정으로 명시하는 대신 Eureka를 통해서 Look Up 해오는 구현 가능
이 3가지를 잘 적용하면 MSA 환경에서 Server들 간의 통신에 큰 문제가 없지 않을까?
다음과 같은 방법으로 적용하였다
API Gateway
MSA 환경에서 API Gateway의 필요성
- Single Endpoint 제공 : API를 사용할 Client 들은 API Gateway 주소만 인지
- API의 공통 로직 구현 : Logging, Authentication, Authorization
- Traffic Control : API Quota, Throttling
Spring Cloud Zuul
Zuul은 API Routing을 Hystrix + Ribbon + Eureka를 통해서 구현하였다.
Spring Cloud와 가장 잘 Integration 되있는 API Gateway 이다.
Hystrix Circuit Breaker in Zuul
Zuul에서는 Circuit Breaker는 서버군별로 생성된다.
Hystrix CommandKey는 각 서버군 이름이 사용된다.
Hystrix Isolation in Zuul
Zuul에서는 semaphore가 default
특정 API군의 장애/지연 등이 발생하여도 Zuul 자체의 장애로 이어지지 않는다.
그러나 semaphore를 사용하게 되면 Timeout이라는 기능을 잃게 된다.
그래서 Tread Isolation으로 바꾸었다.
그러나 바꾸면 Server 전체에 한개의 Thread Pool이 생겨버리게 구현이 된다. 그래서 수정하여 머지하였다.
다음과 같은 옵션을 주게 되면 Thread Pool이 하나씩 분리된다.
zuul :
threadPool:
useSeparateThreadPools : true
threadPoolKeyPrefix : zuulgw
Server to Server 호출
[ 모든 API 호출에 Zuul GW를 호출하는 방법 ] 모든 API 호출을 통제할 수 있다. 허락되지 않은 호출을 막고 통제할 수 있따. 그러나 GW가 죽으면 모든 서버가 죽게 되고 크기가 커지면 엄청난 트래픽을 맞이하게 된다. |
[ API 서버들끼리 직접 호출하는 방법 ] 상대방의 서버 목록을 어떻게 알지? => Eureka + Ribbon API 서버끼리 P2P로 호출 할 수 있게된다. |
Spring Cloud에서는 두개의 Ribbon + Eureka 기반의 Http 호출 방법을 제공한다
- @LoadBalanced Rest Template
이 어노테이션을 붙이면 REST Template이 Ribbon + Eureka 기능을 가지게 된다.
- Spring Cloud Feign
선언적인 Http Client 이다. Java Interface + Spring MVC Annotation 선언으로 Http 호출이 가능한 Spring Bean을 자동 생성한다. Hystrix + Ribbon + Eureka 와 연동 되어 있다.
Spring Cloud Feign with Eureka and Ribbon
name은 클라이언트의 네임 = 내가 찌를 서버의 이름.
Eureka에게 product라는 서버를 받아다가 메소드를 호출할 때마다 알아서 Load Balancing
Spring Cloud Feign with Hystrix
Hystrix 연동하기
- Hystrix가 Classpath에 존재
- feign.hystrix.enabled = true
Spring Cloud Feign with Hystrix and Eureka and Ribbon
- 호출하는 모든 메소드는 Hystrix Command로 실행 (Circuit Breaker, Timeout, Isolation, Fallback 적용)
- 호출할 서버는 Eureka를 통해서, Ribbon으로 Load Balancing 되어 호출
마무리
이 이후는 장애 시나리오 및 모니터링 내용이다. 다음 글에서 작성하도록 하겠다.
영상 참고
https://www.youtube.com/watch?v=J-VP0WFEQsY
'Infra' 카테고리의 다른 글
[Architecture] 유잔씨의 MSA 이모저모 알아보기 (0) | 2024.08.25 |
---|---|
[AWS] 유잔씨의 CloudFront 알아보기 (0) | 2024.08.18 |
간단하게 알아보는 openVidu v3 (4) | 2024.07.28 |
몽수의 Redis 알아보기 (0) | 2024.07.20 |
정만씨의 포워드 프록시와 리버스 프록시 (1) | 2024.07.14 |