명강의로 유명한 발표 영상을 보고 내용을 정리해봤다.
명강의는 명강의인 이유가 있다. 발표를 진행해주신 용성님, 그리고 이 작업을 진행하셨던 구성원분들처럼
내가 어떤 기술을 어떻게 활용하고 있는지 잘 알고있고, 오픈소스를 두려워하지 않고 사용하는 태도를 많이 배워야겠다 🔥
https://www.youtube.com/watch?v=J-VP0WFEQsY
문제 상황
2016년 11번가,,
- 초거대 monolitic system
- 200만 라인의 공통 모듈
→ 한 번의 배포, 하나의 리팩토링이 전사 장애로 이어지는 경우가 많았다.
MSA 분리의 시작
- legacy / MSA 동시 운영
- legacy 에서 MSA로 분리된 API 서버 호출토록함 + 플래그 이용해 스위치 가능하도록함.
- Spring Cloud, Netflix OSS 의 교차점인 “Hystrix”, “Ribbon”, “Eureka” 사용
Hystrix (장애전파방지 & Resilience)
- Circuit Breaker / Fallback / Thread isolation / Timeout
- CircuitBreaker
- Hystrix 의 circuit breaker 는 프로세스 별로 커맨드 키를 설정할 수 있으며, 커맨드 키 단위로 통계를 내고 동작한다.
- 너무 작은 단위, 너무 큰 단위의 설정은 좋지 않다.
- → 비즈니스 로직을 작성할 때 이 범위가 어느정도인지 고민해보는 것이 좋다.
- Fallback
- 잘못 사용하게되면 비즈니스 에러나, 장애상황을 감추게될 수 있어서 주의.
- 단, HystrixBadRequestException 의 경우 이 오류는 Fallback 실행하지않고, circuit 통계에도 집계되지 않으므로 활용 가능.
- Timeout
- “이 메소드가 언제까지 실행될 수 있는가”는 가늠이 어려울 때가 있음.
- 소켓 타임 아웃, JDBC 타임아웃 등 여러가지 타임아웃 값들이 조합되어 가늠이 어려움.
- 서킷 단위로 타임아웃 설정 가능
- “이 메소드가 언제까지 실행될 수 있는가”는 가늠이 어려울 때가 있음.
- Isolation
- Semaphore, Thread(default) 방식 지정 가능
- Semaphore Isolation
- 서킷 브레이커 1개당, 1개의 semaphore 를 만듬
- 뒷단의 적정 용량을 지정해주는 것.
- *caller thread 와 실제 메소드 실행되는 스레드가 같음.
- → ^ 따라서 *Timeout이 제 시간에 동작하지 않을 수 있음.
- 현재 Thread를 인위적으로 중단시키는건 어렵기 때문 (interrupt 에러 throw 하는 방식으로만 통해 가능.)
- 일단 코드가 돌고 있으면 중간에 멈추게 할 수 없음(?) / 22:46
- Thread Isolation
- ThreadPoolKey를 통해 N개의 circuit breaker 에 매핑 가능.
- *caller thread 와 실제 메소드 실행되는 스레드가 분리됨.
- → ^ 따라서 Timeout 시 caller 스레드는 바로 리턴되지만 메소드 실행되는 스레드는 더 오래 일하고 있을 수 있음.
- *Thread 가 분리되므로 Thread Local 사용 시 주의가 필요하다.
Ribbon (client load balancer)
- API caller 쪽에 로드밸런서를 둔다는 개념.
- 인프라팀의 도움 없이도 다수 서버를 로드밸런싱하며 호출할 수 있게됨.
- 다만 Spring Cloud 에서 Ribbon 클라이언트를 직접 사용하진않는다.. (Spring Cloud 가 잘 추상화 해두었다)
- 인프라 잘되어있는데, Ribbon 은 왜 써야하나요?
- 로드 밸런싱의 개념을 완벽히 프로그래밍할 수 있다.
Eureka (DNS Discovery)
- 서버가 뜰 때 Eureka 서버에 본인 정보를 등록함으로서 타 서버가 알 수 있도록 함.
- Ribbon 과 결합되어, 서버 정보를 가져오는데 사용함. Eureka ❣️ Ribbon
Histrix, Ribbon, Eureka 잘 적용해서 MSA 분리해보자! 근데,, API Gateway 필요함.
api gateway로 Spring Cloud Zuul 을 사용하자.
- api routing을 histrix, ribbon, eureka 를 이용해 구현.
- 각 “서버군”별로 command key를 지정
- Zuul은 isolation 기본값이 semaphore 기에, 각 서버군마다 하나씩 지정이 됨.
- timeout 개념을 잃어버리게되어 우려.
- thread isolation 으로 설정을 변경했을 때 오류가 생겨 zuul 코드 개선함
Server to Server 호출, 어떻게 구현할 것인가?
- 모든 API 호출은 Gateway로 통한다.
- → 게이트웨이 망가지면 SPOF 발생 (Single Point Of Failure). 리트라이 로직 있다면 더 악화됨.
- 내부 API 호출은 직접 해당 서버를 호출하도록 함.
- Eureka에 이미 등록이 되어있고, 로드밸런서 자체 조정도 가능하므로 문제가 없다고 판단하게됨. (Ribbon + Eureka 조합으로 P2P 호출)
Spring Cloud Feign (선언적 Http Client)
- Java interface + Spring annotation 사용해 http 호출 가능한 Spring bean 자동 생성
장애 시나리오
- 설정에 따라 동작이 달라질 수 있기에 잘 알고 사용해야함.
11번가(6년전이지만 ㅎ)와 Spring Cloud 를 이용한 시스템
- config를 별도 파일(전체 서버 공용, 서버군용, 특정 서버용 등)로 관리함으로서 코드와는 다른 생명주기를 갖게함.
모니터링
- 분산 tracing 에선 서버간 trace 정보의 전달이 필요함.
- 사용하고 있는 Protocol의 헤더를 통해 전달하는 방식으로 많이 사용함.
- 단 어플리케이션 안에서 조차도 Thread 변경으로 인해 정보 전달이 어려울 때가 있음. (Thread Local 저장방식이 어려움)
- → Spring Cloud Sleuth (distributed tracing 솔루션) 내외부 호출 구간에서 trace 정보를 생성 하고 전달해준다.
- 위의 라이브러리를 사용하면, application log에 trace id가 함께 출력된다.
- Zipkin
- Spring Cloud Sleuth 와 zipkin을 함께 사용하면, 시각화가 가능하다. (데이터독 만만세)
- ^ 단, DB에는 Spring Cloud Sleuth 가 적용되지 않으므로 AOP 를 사용해 trace 정보를 직접 생성
- 샘플링도 설정 가능.
- Turbine (Hystrix 모니터링)
마치며/회고
- open source 의 사용
- 코드가 있으니 무엇이든 할 수 있다!
- 수정과 문서 보강은 사용자의 몫. (용기를 가지자)
나의 액션 아이템
- 우리 프로젝트에서 trace_id 는 어떻게 전달되고 있을까?
- 서킷 브레이커의 현 상황을 좀 더 구체적으로 모니터링할 수 있는 방법은 없을까?
'아티클' 카테고리의 다른 글
[Kubernetes/JVM] 쿠버네티스 팟 안에서 동작하는 자바 프로세스 메모리 설정 (0) | 2025.02.18 |
---|