OMS의 최적화된 마이크로서비스 아키텍처 디자인

1 month ago 5

판매몰과 컬리 풀필먼트의 게이트웨이의 역할로써 OMS의 아키텍처 디자인의 변화 과정을 소개합니다.

이준환 게시 날짜: 2025.05.09.

들어가며

안녕하세요. OMS팀 이준환입니다.

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

OMS 시스템은 각 판매처의 결제완료 주문을 생산 및 배송할 수 있도록 컬리 풀필먼트가 이해할수 있는 주문 정보로 변환하는 역할을 하고 있습니다.

일종의 주문 인터프리터의 역할이라고 생각하시면 좋을 것 같습니다.

이 외에도 OMS는 각 판매처에 고객 배송지 주소를 기반으로 현재 결제완료 시 언제 몇시에 새벽에? 배송완료 예정 시간 등의 정보를 api로 제공하고 있고, 이 정보를 통해 각 관계사에서는 해당 서비스 고객에게 결제완료 전 단계에서부터 주문이행 계획 정보를 노출할 수 있습니다.

  • 판매처에 풀필먼트 이행 정보 제공

  • 판매처의 주문 라우팅

판매처 목록에 컬리몰도 포함이 되어있네?

맞습니다.

OMS의 현재 아키텍처는 최대한 특정 판매처 데이터에 커플링 되어 동작하지 않도록 설계되어 있습니다.

컬리몰 또한 마치 B2B 고객사처럼 간주하고 있습니다. (매우 노력하고 있습니다)

시스템 오염관점에서 1개의 판매처에 강하게 결합되면 향후 판매처가 다양해지는데 불리한 구조가 됩니다.

이를 잘 수행하기 위해서 OMS는

  • 컬리 풀필먼트를 문제없이 이행하기 위해 필수 데이터에 대해서는 판매처에 요구

  • 풀필먼트 이행 계획에 어긋나는 주문이 풀필먼트 내부로 전파되지 않도록 방어

  • 반대로 각 판매처에게 풀필먼트의 정보를 제공할때는 모든 판매처에 오해없는 용어로 데이터 서빙. (이 과정에서는 어쩔수 없이 특정 판매처를 위한 인터페이스가 불가피하게 필요 할 수도 있습니다.)

등의 역할을 잘 해주어야 풀필먼트 전체가 건강하게 유지될 것 입니다.

데이터 다양성에 대한 전략적 접근: 최소 동기화 & 재가공 서빙

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

위는 OMS팀에서 내/외부로 제공가능한 데이터입니다.

OMS에서는 풀필먼트 각 도메인으로부터 일부 데이터를 동기화 관리하기도 하고 때로는 직접 api를 호출하여 정보를 얻어옵니다.

이 과정에서 정상적으로 풀필먼트 처리에 필요한 최소한의 정보만을 동기화를 합니다.

현재 동기화 데이터를 OMS 자체 데이터와 결합여 의미있는 정보로 재가공하여 서빙을 해주기도 합니다.

그리고 그 api는 안정적인 응답속도가 보장되어야할때 필수적으로 최소한의 동기화를 고려합니다.

이런 이유 때문에 OMS에서는 컬리 풀필먼트에 속한 거의 모든 도메인의 크고 작은 데이터들이 존재하게 됩니다.

이를 유연하게 관리하기 위해 OMS 자체적인 마이크로서비스 아키텍처가 중요해졌습니다.

OMS 마이크로서비스 아키텍처

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

위 그림은 OMS 마이크로서비스 아키텍처의 오버뷰입니다.

팀 내에서는 OMS msa group 이라는 명칭으로 전체를 칭하고 있습니다.

msa 분리기준

OMS는 기능역할, 그리고 관리비용에 초점을 맞춰 도메인 분리하여 별도의 msa로 구성하고 있습니다.

예를들면 OMS는 냉동/냉장/상온 타입으로 분리된 상품 정보도 관리하고 있습니다. 다만 풀필먼트 상품 도메인을 특정 msa로 분리하지 않았습니다.

그 이유는 order (주문관리) 도메인 내에서 상품정보 매핑 외에 판매재고관리와 같은 추가적인 기능이 없기에 상품정보 도메인은 현재까지는 관리비용 자체가 높지않기 때문입니다. 향후 상품 재고정보를 활용하여 주문 이행에 관여하는 높은 관리비용이 예상되는 기능이 추가된다면 그때 분리를 계획하면 됩니다.

OMS msa에서 shared cache의 목적은 간단합니다.

이걸 특정 상황을 비유해서 설명하자면 나한테 직접 물어보지말고 공용 게시판에 써놨으니 그거 봐보고 애매하면 물어봐 입니다.

OMS msa 전체적으로 자주 활용될 수 밖에 없는 데이터에 대해서는 담당 msa에서는 shared cache에 write할 수 있고 나머지 도메인에서는 read only 로만 조회할 수 있습니다. 이것은 데이터 소유권을 명확히 지정하고 실제 개발과정에서도 반드시 지켜야하는 팀 컨벤션입니다.

캐시 히트되지않는 경우나 일정 수준의 캐시 커넥션 타임아웃이 발생시에는 해당 msa로 직접 호출하여 데이터를 제공받습니다.

호출 트래픽을 내부 msa까지 전파하지 않는 구조를 만들어줍니다.

아래 이미지는 oms에서 '주문정보 조회'를 예를들어 차이점을 비교하고 있습니다.

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

내/외부 에 실시간 api를 제공하여 높은 트래픽이 존재하는 operation api server의 경우 거의 대부분이 cache only로 응답이 가능하기에 내부 msa에 호출로 인한 네트워크 비용조차 발생하지 않습니다.

현재 컬리 주문특성상 마감 시간인 23시에 도달할수록 peak 수치를 기록하는 operation api와는 별개로 peak응답에 가장 많은 관여를 하고있는 권역 서비스의 메트릭 지표는 너무도 평온합니다.

그로인해 operation api를 제외한 다른 msa의 인스턴스 스펙은 서비스 특징을 고려하여 각각 최소한의 스펙으로 낮출수 있습니다. (여기서 고백하나 하자면 과거 권역 서비스 배포 과정의 문제로 몇분동안 503에러가 발생한 적이 있었으나, shared cache에서 거의 대부분의 요청을 털어내줘서 슬랙 문의조차 오지않았던…)

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

캐시가 고장나면 대형사고

평상시 shared cache를 믿고 각 msa는 최소한의 스펙을 유지하였기 때문에, 캐시 데이터의 문제 혹은 실제 캐시 클러스터 자체 장애가 발생하게 되면 높은 트래픽이 각 msa로 그대로 흘러갑니다.

이때 피해를 최소화 하기 위해서는 각 msa의 auto scale out 룰은 기존보다도 훨씬 보수적으로 잡아놓아야 합니다.

또한 트래픽이 거의 없다고 해서 너무 낮게 잡기보다는 만약의 상황을 고려해 AS-IS의 지표를 기준으로 잡아야합니다. auto scale out 트리거가 발동된 후 추가 인스턴스에 트래픽이 동작할 때 까지 충분히 버티기 가능한 수준을 의미합니다.

그리고 캐시 히트율 대비 메모리 사이즈가 큰 데이터가 있는지, shared cache에 담을 만큼 범용적인 데이터인지, ttl 만료시간이 과하게 보수적인 것은 아닌지 판단하여 메모리사용을 최적화 해놓아야 합니다.

OMS 에서는 shared cache 또한 데이터의 성격 그리고 메모리 사용량 대비 캐시 히트수치 그리고 캐시 한 곳의 문제 발생시에도 판매처의 큰 영향이 있는 api는 문제없이 동작 할 것인지 등을 복합적으로 고려하여 2개의 캐시 클러스터를 따로 운영하고 있습니다.

판매처의 특징을 고려한 msa 구성

컬리 풀필먼트 구조 오버뷰 (그림: 컬리, © 2023. Kurly. All rights reserved.)

현재 oms는 컬리몰 뿐만 아니라 외부몰의 주문에 대해 풀필먼트 대행(생산, 배송)서비스가 예정되어있고 일부는 이미 진행 중입니다.

KLS

  • 컬리와 직접 계약된 3PL업체 풀필먼트 대행 서비스
  • N개의 판매처를 각각 고려할 수 없기에 컬리에서 연동 인터페이스를 일정부분 강제하는 방식
  • 계약된 판매처를 위한 별도의 백오피스 제공

NFA

  • 네이버 스토어의 샛별배송 풀필먼트 대행 서비스
  • 이미 네이버 스토어에 입점한 N개의 판매처를 한번에 연동이 가능한 장점
  • 네이버 스토어에서 이미 제공하는 연동 인터페이스를 기준으로 별도 규격을 고려해야함

위 두개의 공통점은 oms msa group의 밖에서 동작하는 서비스이며, 언제든지 oms팀이 아닌 다른 팀의 프로젝트로 넘겨 주 있도록 설계되어있습니다. (언제든지 가져가세요)

아키텍처에 따른 OMS팀 개발 문화의 변화

현재 시점에 OMS는 1명의 PM과 4명의 엔지니어가 있습니다. 엔지니어 수보다 msa개수가 더 많지만 각각 독립적인 기능을 담당하기에 개발 티켓 할당에서부터 PR리뷰 그리고 배포 & 모니터링 모든 구간에서 효율적입니다.

동일 기능 동시 개발

작년 주문 반품/회수 기능 개발과정을 소개하면 좋을 것 같습니다. OMS팀은 가장 먼저 반품/회수 기능의 전체 요구사항을 모두 공감하고 필요한 데이터 관리 주체를 다같이 정의합니다. 이후 반품/회수 기능을 서빙하기 위해서는 아래 3가지의 하위 티켓을 산정하게 되고 누가 어떤 티켓을 담당할 지는 현재 가지고있는 티켓들의 난이도를 기준으로 분배합니다.

  1. 회수주문 접수 -> operation api
  2. 택배사 회수접수 -> order
  3. 택배사 회수상태, 회수물건 검수 상태 관리 -> tracking

위 3개는 각각 다른 msa에서 기능이 제공되어야 하고 개발에 앞서 어떤 msa에서 어떤 인터페이스를 스펙을 제공할지만 팀내 논의 후 1,2,3번의 기능을 각각 다른 엔지니어가 동시에 개발이 가능합니다. 그리고 각각 다른 서비스 레포를 건드리기 때문에 소스코드 컨플릭 이슈도 없습니다.

PR리뷰 간소화

각각 msa에서 제공 하는 독립적인 기능에 대해서만 PR이 올라오기 때문에, 변경 소스코드의 절대량이 줄어들면서 일단 리뷰 스트레스가 없어지는 긍정적인 효과가 있습니다.

정기배포 -> 상시배포

OMS팀은 현재 상시 배포를 진행하고 있고, 개발 티켓 자체가 항상 작은 단위이기에 최종적인 기능을 서비스하기 위해서는 하위 msa에서의 수많은 작은 선 배포들이 먼저 진행 되어야 합니다.

이런 하위 배포들은 실제로 준비만 해놓은 상태이며 동작하는 운영 환경에는 영향이 없기에 각각 배포 후 전체적인 동작을 미리 조립한 후 테스트 및 검증 절차를 진행해 볼 수도 있습니다.

이후 최종 기능 오픈은 호출하는 호출 최상단의 msa에서부터 카나리 배포 -> 전체배포 순서로 안전하게 기능을 오픈합니다.

OMS에서 최종 기능 오픈이란 마치 잘 준비된 동작의 스위치를 켜고 끄는 수준에서 배포됨을 의미하는 경우가 많습니다. 모든 하위 기능 동작은 앞선 모든 선 배포과정에서 이미 여러차례 QA 및 테스트가 완료되었기 때문에 자심감을 갖고 배포를 진행할 수 있습니다.

현재 OMS팀은 일단위 최소 1~2번 많을때는 10번이상 작은단위로 배포버전을 관리하고 있습니다.

효율적인 라이브러리 버전관리

어떤 서비스든 장애가 발생하면 안되겠지만, 스프링 버전업이나 관련 dependency 버전업을 진행함에 있어서 가장 장애 전파 영향이 적은 서비스로 먼저 버전업 테스트를 진행해 볼 수 있습니다. 과거 모놀리식 구조에서는 서비스단위 스케일이 크기 때문에 영향도 체크에 많은 시간을 할애했던 것에 비하면 보다 안전하게 전체 버전을 최신화 할 수 있는 장점이 있습니다.

한마디로 가장 만만한 서비스로 카나리 버전업을 해보는 개념으로 이해하면 편할 것 같습니다.

현재 OMS msa 는 각 서비스마다 동시요청 추이나 관리 데이터 특징을 고려해 spring mvc, spring webflux 구성 비율이 거의 N빵으로 혼용되어 구성되어 있습니다.

주의할 점

모든 엔지니어는 모든 msa를 팔로업 하고 있어야 합니다. 모두가 같은 컨텍스트를 유지해야하는 부담이 있습니다. 만약 msa 각각 개발 담당자를 나누게 되면 운영환경 랜딩 계획 부터 인터페이스 스펙 설계 단계까지 비효율적입니다. 가장 큰 위험은 각 msa에서 자칫 불필요한 중복 데이터를 관리하게 될 수 있습니다.

이를 위해 oms팀은 일부러라도 티겟을 더 작게 나눈 후 데이터 저장 로직과 저장 된 데이터를 서빙하는 로직을 각각 다른 엔지니어가 순서대로 개발하기도 합니다. 이 방식은 PR리뷰에도 효율적인 장점이 있습니다.

개인적으로 위 아키텍처 운영방식에 가장 적합한 팀 인원은 최대 6명이 적당하지 않을까 생각입니다.

이유는 모든 엔지니어가 모든 msa에 동일한 컨텍스트를 지속적으로 유지하는 것이 베스트이기 때문에 그렇습니다.

OMS팀이 위 아키텍처로 가장 많은 이득을 보고있는 단계는 설계 단계입니다. 특정 기능을 개발하기위해 코드부터 검토하는 단계가 사라지고 어떤 데이터를 어떤 서비스에서 어떤 스펙으로 인터페이싱할지만 결정하기만 하면됩니다. 이 대화는 자연스럽게 운영환경 랜딩계획까지도 이어집니다.

위 대화가 효율적으로 이루어지는 전제 조건은 대화 당사자들의 동일한 msa 이해도가 필수 준비물입니다.

서비스들의 호출 관계는 마치 다른 조직끼리 협업하는 모양새를 띄지만 우리팀은 그 관계들을 가장 높은곳에서 똑같이 내려다보며 대화 할 수 있어야 합니다

마무리

OMS팀은 소개된 shared cache 중심 아키텍처를 특정 시점에 전환하지는 않았습니다.

세월에 걸쳐 팀내 공통적인 의사결정이 쌓이고 쌓여 위와같은 모양새를 띄게 되면서 일관된 개념으로 압축되고 있었습니다.

컬리의 OMS팀과 유사한 성격의 팀이 혹시 존재한다면 소개된 방법도 한번 고려해보시면 좋을 것 같습니다.

지금까지 긴 글 읽어주셔서 감사합니다.

Read Entire Article