네이버 D2 - 11번가 Spring Cloud 기반 MSA로의 전환 - 지난 1년간의 이야기

최창효·2022년 11월 23일
1

기업_IT블로그_리딩

목록 보기
7/14
post-thumbnail
post-custom-banner

들어가기 전에


해당 영상은 11번가에서 기존의 시스템을 MSA기반으로 옮기면서 알게된 내용, 현재의 운영방식을 공유한 강의입니다.

11번가가 MSA를 도입하기로 결심한 계기

11번가는 기존에 Monolithic System을 사용하고 있었습니다. 폭팔적인 성장을 하는 시기에 열심히 기능을 개발했지만, 8년이 지나고보니 레거시하고 비효율적인 것들이 많아지게 되었습니다.
한 예로 팀의 중복개발을 없애기 공통모듈이란걸 만들었었는데, 8년이 지나니 공통모듈의 개수가 200만이 넘게 되어 IDE에 뜨지도 못할 정도로 무거운 짐이 되어 있엇습니다. 하지만 이러한 문제는 개발자의 잘못이라기보다는 개발 환경과 문화의 잘못인 경우가 많습니다.

  • 타이트한 일정이나 기존에 엄청나게 벌어져 있는 코드 속에서 무언가를 개발해달라는 요청이 들어온다면, 당연하게도 가장 짧게 개발하는 방법인 기존 클래스를 복사하거나 완성된 클래스에 if문을 넣어 분기처리하는수밖에 없습니다.

이러한 나쁜 시스템은 나쁜 개발문화를 만들고 있었습니다.

  • 매주 밤을 새서 100명이 모여 배포하는게 당연시 되었으며
  • 한명의 실수로 100~200명의 개발자가 사용하는 걸 롤백해야 하고
  • 라이브러리 버전 하나 올렸다가 다른코드에 영향이 갈지도 모른다는 생각에
    -> 모두가 코드를 수정하거나 무언가를 변경하는걸 꺼려하게 되었습니다.

11번가는 비단 서비스 측면뿐만이 아니라 개발자의 측면에서도 나쁜 시스템이 나쁜 개발문화를 만들고 있었기 때문에 MSA로의 변환이 필요했습니다.

어떻게 MSA를 도입할 것인가

11번가는 필요한 기능들부터 MSA로 하나씩 분리해 나가면서 점진적으로 변화해 큰 Legacy를 수정해나가는 방법을 사용했습니다.

11번가는 기존 코드를 살려둔 채로 하나씩 기능들을 REST API로 분리해 호출하는 방식으로 코드를 변경하기 시작했습니다. 이 방법의 장점은 전환한 코드에 문제가 발생했을 때 언제든지 이전코드로 돌아갈 수 있다는 점입니다.

어떤 MSA 플랫폼 Solutions를 사용할 것인가?

11번가는 NETFLIX OSS를 선택했습니다. 그 이유는 Netflix에서 직접 사용하던 코드이기 때문에 비즈니스적으로 안전성 등의 검증이 끝났다고 생각했기 때문입니다.

핵심 개념

Hystrix

Hystrix는 Netflix가 만든 Fault Tolerance Library장애 전파를 방지해주며, Resilience를 보장해 줍니다.
Hystrix는 sprnig cloud없이 java만으로도 사용 가능합니다. 그렇기 때문에 팀 차원의 변경 없이 개인의 개발 영역에 독자적으로 활용하는 게 가능합니다.
Hystrix는 @HystrixCommand 또는 extends HystrixCommand<>로 적용할 수 있습니다.

Hystrix Command를 호출하면

  • 해당 메서드를 Intercept하여 대신 실행합니다.
    • Thread Isoliation, API Caller와 API Callee가 다른 thread에서 수행됩니다.
  • 메소드의 실행 결과 성공 혹은 실패(Exception) 발생 여부를 모두 기록하고 통계를 냅니다. 통계에 따라 Circuit Open여부를 결정하기도 합니다. - Circuit Breaker기능
  • 실패(Exception)한 경우 사용자가 제공한 메서드를 대신 실행합니다. - Fallback기능
    • ex) 상품 추천 서버를 호출했는데 반응이 없고 Exception이 난다면 고정된 상품목록을 대신 보여주는 방식으로 활용할 수 있습니다.
  • 특정시간동안 메소드가 종료되지 않은 경우 Exception을 발생시킵니다. - Timeout기능

Hystrix는 Circuit Breaker, Fallback, Thread Isolation, Timeout이라는 4가지 주요기능을 가집니다.

Circuit Breaker

서킷브레이커는 일정 시간동안 일정 개수 이상의 호출이 발생한 경우 일정 비율이상의 에러가 발생했을 때 Circuit Open(호출 차단)을 했다가, 일정 시간 경과 후에 단 하나의 요청에 대해 호출을 허용하며(Half Open) 이 호출이 성공하면 다시 Circuit Close(호출 허용)을 합니다.

commandKey속성은 메서드의 동작이 비슷하거나 함께 장애가 발생할 확률이 높은 메서드를 묶어 함께 동작하고 함께 통계처리 됩니다.

  • 그럽 범위를 너무 좁게 지정하면 간헐적으로 호출되는 API의 경우 장애가 발생했는지 확인하기 어려울 수 있으며, 범위가 너무 넓으면 하나의 오류로 상관없는 나머지 시스템까지 다 닫혀버릴 수 있습니다.

Fallback

어떤 기능이 제대로 동작하지 않을 때, 이에 대처하는 기능 또는 동작을 Fallback이라고 합니다.
Fallback은 다음과 같은 조건에서 실행됩니다.

  • Circuit Open
  • Any Exception(HystrixBadRequestException제외)
    • HystrixBadRequestException은 Fallback을 실행하지 않으며 Circuit Open을 위한 통계에도 집계되지 않습니다.
    • 메서드의 잘못이 아니라 Caller의 잘못인 경우(ex-파라미터를 잘못 넘김) HystrixBadRequestException이 실행됩니다.
  • Semaphore / ThreadPool Rejection
  • Timeout

Timeout

Hystrix는 Circuit Breaker 단위로(CommandKey 단위로) Timeout을 설정할 수 있습니다. Timeout은 Default값이 매우 짧으며, Semaphore Isolation인 경우 제 시간에 Timeout이 발생하지 않기 때문에 유의해서 사용해야 합니다.

Isolation

Semaphore Isolation과 Thread Isolation이 존재합니다.
Semaphore Isolation

Thread Isolation

Ribbon

Ribbon은 Netflix에서 만든 Software Load Balancer를 내장한 REST Library입니다. 한마디로 클라이언트 로드벨런서라고 정의할 수 있습니다.
스프링 클라우드에서는 Ribbon을 직접 활용하지 않습니다. Zuul API Gateway, Rest Template, Spring Cloud Feign을 통해 간접적으로 Ribbon을 사용합니다.

Ribbon은 로드밸런싱 개념을 완벽히 프로그래밍 할 수 있다는 장점이 있습니다.

유레카

유레카는 Netflix에서 만든 Dynamic Service Discovery입니다. 서버가 자신의 서비스 이름과 IP주소, 포트를 등록하면 다른 서비스에서 이름으로 해당 서버에 접속할 수 있습니다.

Eureka가 Spring Cloud와 함께 사용되면 아래와 같이 동작합니다.

  • 서버가 시작될 때 Eureka서버에 자동으로 자신의 상태를 등록(UP)합니다.
  • 주기적으로 HeartBeat를 날려 Eureka Server에 자신이 살아있다는 걸 알립니다.
  • 서버가 종료될 때 Eureka서버에 자신의 상태를 변경(DOWN)하고 자신을 목록에서 삭제합니다.

Eureka와 Ribbon이 Spring Cloud와 함께 사용되면 아래와 같이 동작합니다.

  • Ribbon Bean을 다음과 같이 바꿉니다.
    • ConfigurationBasedServerList -> DiscoveryEnabledNIWSServerList
    • DummyPing -> NIWSDiscoveryPing

11번가의 적용방식

API Gateway

  • API Gateway는 늘어나는 MSA서비스를 효율적으로 관리하기 위해 반드시 필요한 기능입니다.
  • 11번가의 고민은 자체 개발한 API Gateway를 그대로 쓸 것인가 아니면 Zuul을 사용할 것인가였습니다. 11번가는 Zuul사용을 선택했습니다.
    • 그 이유는 Spring Cloud Zuul에 Hystrix, Ribbon, Eureka가 잘 녹아있었기 때문입니다. 즉, Zuul은 Spring Cloud와 가장 잘 Integration되어있는 API Gateway라는 말입니다.
    • 또한 Zuul에서는 기본적으로 Semaphore Isolation이 구현되어 있었습니다. Product군별로 Semaphore가 생성되고 이로 인해 특정 API군의 장애가 발생해도 Zuul 자체의 장애로 이어지지 않았습니다.
  • 또 다른 고민은 Server to Server호출 시 모두 API Gateway를 거칠 것인지 였습니다. 11번가는 API서버들끼리 직접 호출하는 방식을 사용했습니다.
    • 모든 요청이 API Gateway를 거치면 자원의 호출을 엄격하게 관리할 수 있지습니다.
    • 하지만 하나의 Gateway가 많은 너무 많은 트래픽을 부담하게 되고, 이 Gateway가 죽었을 때 모든 서비스가 중지될 위험이 있습니다.
    • API서버를 직접 호출하는 방식의 문제점은 어디로 요청해야 할 지를 알아야 한다는 것인데, RibbonEureka를 통해 이러한 부분을 해결할 수 있었습니다. 또한 SpringCloud자체적으로 Ribbon + Eureka기반의 HTTP호출 방법인 RestTemplateSporing Cloud Feign이 있었기에 쉽게 사용할 수 있었습니다.

Spring Cloud Feign

  • Declarative Http Cient입니다.
    • Java Interface + Spring MVC Annotation선언으로 Http 호출이 가능한 Spring Bean을 자동 생성합니다.
    • Hystrix + Ribbon + Eureka와 연동되어 있습니다.
  • 다만 Spring Cloud Feign을 사용할 때는 Circuit Breaker의 단위나 Thread Pool의 단위가 Method단위로 잘게 분할되기 때문에 커스텀 설정이나 코드를 통해 같은 유형은 같은 Circuit Breaker, Threa Pool을 사용하도록 조정해줘야 합니다.

장애 시나리오

예시1) 3개의 인스턴스로 서버군을 구축했는데 그 중 하나의 인스턴스가 다운된 경우

  • Eureka는 Hearbeat송신이 중단됨으로써 일정 시간 후 목록에서 해당 서버를 지웁니다.
  • Ribbon은 IOException이 발생한 경우 다른 인스턴스로 Retry를 시도합니다.
  • Hystrix - Circuit이 Open되지 않습니다.
    Circuit Open의 기본옵션은 50%이기 때문에 Circuit이 작동하지 않습니다. 다만 Fallback, Timeout은 동작합니다.

예시2) 3개의 인스턴스로 서버군을 구축했는데 특정 API가 비정상적으로(시간이 매우 오래걸리게) 동작하는 경우

  • Hystrix - 해당 API를 호출하는 Circuit Breaker 오픈. Fallback 및 Timeout도 동작

11번가의 MSA 환경 구성

  • 맨 앞단에 Zuul Gateway가 존재하며 Zuul Gateway안에 Hysrix, Ribbon, Eureka가 탑제되어 있습니다.
  • 모든 API Server에는 Spring Cloud Feign이 탑제되어 있어 모든 API끼리 통신합니다.

  • Config Server를 전체 MSA 서버에 도입했습니다.
  • 적용할 때는 우선순위를 유의해서 사용해야 합니다.

  • 모니터링 시스템으로는 Zipkin, Turbine, Spring Boot Admin을 사용하고 있습니다.

기존의 모니터링 환경에서는 분산 Tracing에 부족함이 있었습니다. 어떤 API는 엄청나게 다양한 서버를 거쳐서 호출하게 되는데, 맨 앞단에서 API를 호출하는 개발자는 해당 API가 뒷단에서 어떤 API를 호출하게 되는지 모릅니다. -> 이러한 문제를 해결해주는 게 트위터에서 개발한 Open Source인 Zipkin이 있습니다. Zipkin은 특정 서버에서 UUID와 Tracing정보를 생성하고 해당 정보를 HTTP Header에 계속 가지고 다닙니다.

모니터링에 유용한 또 다른 기능으로 Spring Cloud Sleuth가 있습니다.

  • 이러한 정보를 시각화 할 때도Zipkin을 사용하면 됩니다.

팀장님의 회고

  • Open Source를 사용한다는 건
    • 당연히 Bug고 있고 문서도 부실할 수 있습니다.
    • Bug Report, 수정과 문서의 보강은 사용자의 몫입니다.
  • Spring Cloud 덕분에 최소의 인원으로 프로젝트를 진행할 수 있었습니다.

QnA

트랜잭션 문제를 어떻게 해결하셨나요?

  • MSA단위로 나눠지면 API레벨에서 Transaction단위로 관리하는 건 불가능 합니다.
  • 그렇기 때문에 API 디자인을 보다 신경써야 합니다. 11번가에서는 Transaction관련 이슈를 없애기 위해 UPDATE가 필요한 API를 가능하다면 멱등성있게 작성했습니다.
    • 멱등성있게 작성해 최대한 Retry를 하는걸 권장하고 있습니다.
    • 보상 API를 작성하는 걸 권장하고 있습니다.

마치며

  • 제가 정리한 글은 강의의 많은 부분이 생략된 내용입니다. 해당 내용에 관심이 있으신 분은 원본영상을 보시는 걸 추천드립니다.
  • MSA를 이제 막 입문한 입장에서 내용을 완벽히 이해하는 게 쉽지 않았습니다. 하지만 덕분에 MSA가 실무에서 어떻게 적용되는지를 배울 수 있어 좋았습니다.
  • 직접 MSA와 관련된 프로젝트를 진행해봐야 조금 더 많이 공감할 수 있다는 생각이 들었습니다.
profile
기록하고 정리하는 걸 좋아하는 개발자.
post-custom-banner

0개의 댓글