아티클

[영상] 11번가 Spring Cloud 기반 MSA로의 전환 - 지난 1년간의 이야기 정리

호키포키장 2025. 1. 8. 16:40
명강의로 유명한 발표 영상을 보고 내용을 정리해봤다.
명강의는 명강의인 이유가 있다. 발표를 진행해주신 용성님, 그리고 이 작업을 진행하셨던 구성원분들처럼 
내가 어떤 기술을 어떻게 활용하고 있는지 잘 알고있고, 오픈소스를 두려워하지 않고 사용하는 태도를 많이 배워야겠다 🔥

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 자동 생성

Eureka 에게 등록된 이름 “product”를 사용하면 편하게 호출 가능.

 

장애 시나리오

  • 설정에 따라 동작이 달라질 수 있기에 잘 알고 사용해야함.

 

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 는 어떻게 전달되고 있을까?

- 서킷 브레이커의 현 상황을 좀 더 구체적으로 모니터링할 수 있는 방법은 없을까?