Node.js, PHP, Java로 분산된 서버를 Spring Boot 기반으로 통합한 실전 사례. 올라핀테크 백엔드팀의 서버 통합과 이벤트 기반 아키텍처 전환 기록.

빠르게 성장하는 스타트업, 그리고 함께 커진 과제

올라는 이커머스 셀러를 위한 선정산 서비스로 빠르게 성장해왔어요. 빠른 성장은 좋은 신호지만, 기술팀에게는 새로운 과제를 안겨주기도 했죠. 초기에는 빠른 개발과 검증을 위해 상황에 맞는 다양한 기술을 선택했어요. 어떤 서비스는 Node.js로, 어떤 서비스는 PHP로, 또 다른 서비스는 Java로 개발되었고, 각 기술은 당시의 요구사항에 맞는 최선의 선택이었습니다.

분산된_서버_구조와_운영_복잡성_올라핀테크

당시 서버 구성

  • Node.js 서버: 셀러가 직접 사용하는 핵심 API 서버
  • Node.js 배치 서버: 선정산 금액 회수, 실시간(분단위) 대사 등 금액 정합성 검증을 위한 백그라운드 처리
  • PHP 서버: 서버 사이드 렌더링 방식의 어드민 서버 API와 일부 셀러 API 공존
  • Java 서버들: 여러 버전의 JDK 로 분산된 서비스들

각 서버는 독립적으로 동작했고, 필요에 따라 서버 간 통신으로 데이터를 주고받는 구조였어요.

점점 복잡해지는 환경

하지만 서비스가 성장하면서 몇 가지 어려움이 생기기 시작했어요. 여러 언어와 프레임워크가 섞여 있다 보니, 하나의 기능을 개선하려 해도 여러 프로젝트를 오가며 확인해야 했죠.
특정 기능이 어느 서버에 있는지 찾는 일이 잦아졌고, 신규 팀원이 합류했을 때 온보딩에도 시간이 오래 걸렸어요.

더 큰 문제는 팀 구성의 변화였어요. Node.js와 PHP에 익숙한 개발자는 팀을 떠났고, Java 개발자들로 팀이 재편성되었죠. 하지만 서버는 여전히 여러 언어로 나뉘어 있었습니다.
여러 서버가 독립적으로 동작하다 보니 서비스 전체를 관통하는 일관된 관리가 어려웠고, 셀러분들이 사용하는 기능의 응답 속도나 안정성을 개선하고 싶어도 여러 시스템을 동시에 손봐야 하는 구조였어요.

MSA와_모놀리식_아키텍처_선택의_기로_올라핀테크

MSA? 모놀리식? 우리의 선택

이런 상황에서 우리는 고민했어요. “이대로는 안 되겠다. 시스템을 재정비할 때가 왔다.” 가장 먼저 마주한 질문은 이거였어요.
“MSA로 갈 것인가, 모놀리식으로 통합할 것인가?”

 

당시 많은 회사들이 MSA(마이크로서비스 아키텍처)로 전환하고 있었고, 우리도 그 방향을 검토했어요. 각 도메인을 독립적인 서비스로 분리하면 확장성도 좋고, 기술 스택도 자유롭게 선택할 수 있으니까요. 하지만 우리 상황에서는 오히려 역효과일 수 있었습니다. 이미 여러 서버로 분산되어 관리 복잡도가 높았는데, MSA로 가면 그 복잡도가 더 올라갈 수 있었죠. 서비스 간 통신, 분산 트랜잭션, 모니터링 등 고려해야 할 것들이 너무 많았어요.
그래서 우리는 모놀리식 통합을 선택했습니다. 셀러가 사용하는 클라이언트 서버를 하나의 견고한 모놀리식 애플리케이션으로 만들자.
일단 복잡도를 낮추고, 안정성을 확보한 뒤에 필요하면 그때 분리하자. 이게 우리의 결론이었어요.

왜 Java였을까

팀원 전원이 Java 개발자였고, Spring Boot 생태계에 익숙했어요. 새로운 기술을 배우는 것보다 우리가 잘 다룰 수 있는 도구로 빠르게 개선하는 게 현실적이었죠. 핀테크 서비스는 안정성이 생명이에요. Spring의 성숙한 생태계와 검증된 보안 기능은 우리에게 큰 장점이었습니다. 기존 Java 서버들도 여러 JDK 버전에 걸쳐 있었는데, 이번 기회에 JDK 21 Spring Boot 최신 버전으로 기술 스택을 현대화하기로 했어요.

단계적으로 진행하자

단번에 모든 걸 바꿀 수는 없었어요. 서비스는 계속 운영되어야 했습니다. 셀러분들이 불편을 느껴서는 안 되었으니까요.

통합 계획

  1. Node.js 모놀리식 + 구형 Java + PHP 일부 API → Spring 통합
  2. Node.js 배치 서버 → 이벤트 기반 분리
    (PHP 어드민 서버는 현재도 운영 중)

핵심 서비스부터 차근차근 옮기되, 각 단계마다 충분한 검증을 거치기로 했어요.

5개월의 여정

Phase 1: Node.js 모놀리식 + 구형 Java + PHP 일부 API → Spring 통합

서버_통합을_위한_아키텍처_재설계_전략_올라핀테크

첫 번째 도전은 Node.js, 구형 Java 그리고 PHP 서버의 일부 셀러 API를 하나의 Spring 애플리케이션으로 통합하는 작업이었어요.

최종 아키텍처

  • Spring 모놀리식 서버: Node.js, 구형 Java, PHP 일부 API 통합
  • JDK 21 + Spring Boot 최신 버전
  • Gradle 빌드 도구

동시에 온프레미스에서 AWS 클라우드로의 이전도 함께 진행했어요. 서버 통합과 인프라 전환을 동시에 하는 건 쉽지 않은 결정이었지만, 한 번에 끝내자는 마음으로 시작했죠.

가장 어려웠던 것: 로직 분석

기존 다양한 언어로 구성된 비즈니스 로직을 Java로 옮기는 작업, 생각보다 훨씬 어려웠어요. 코드만 봐서는 “왜 이렇게 작성했을까?” 싶은 부분들이 많았고, 문서나 히스토리가 남아있지 않아 의도를 파악하기 어려웠죠. 기존 개발자분들도 남아 있지 않은 상태였고요.

결국 이 작업은 코드를 옮기는 일이 아니라, 이미 운영 중인 서비스를 다시 이해하고 재정의하는 과정에 가까웠어요. 그래서 저희는 서둘러 마이그레이션하기보다, 현재 서비스가 실제로 어떻게 동작하고 있는지를 하나씩 확인하는 방식으로 접근했습니다.

그래서 우리가 한 건:

  • 1단계: 소스 기반 현재 로직 분석
    - 
    실제 API 호출 로그를 분석하며 동작 패턴 파악
    - 코드 흐름을 따라가며 핵심 비즈니스 로직 추출
    - “이 코드가 실제로 하는 일”을 먼저 이해
  • 2단계: CX팀, 기획팀과 함께 재정의
    - 주기적인 미팅을 통해 “원래 의도”와 “현재 동작”을 대조
    - 
    CX팀: “실제 업무에서는 이렇게 처리해요”
    - 기획팀: “원래 기획 의도는 이거였어요”
    - 개발팀: “그럼 코드는 이렇게 개선할 수 있어요”
  • 3단계: Testcontainers로 안전하게 검증
    - 
    Docker Testcontainers를 활용한 독립적인 테스트 환경 구축
    - 외부 금융 API는 Mock으로, DB 저장/조회는 실제 컨테이너로 검증

이 과정은 단일 API 하나를 옮기는 데에도 많은 확인과 합의가 필요했어요. 로그를 통해 동작을 확인하고, 유관 부서와 의도를 맞추고, 테스트로 검증하는 작업을 모든 핵심 도메인에 반복해야 했죠.

특히 금액과 직결된 핀테크 서비스 특성상, 작은 차이도 오류로 이어질 수 있었기 때문에 “빠르게 옮기자”보다 “절대 틀리지 않게 이해하자”를 우선순위로 두었습니다.

@Test
void 출금_요청시_외부API는_Mock_DB저장은_실제_검증() {
    // Given: 외부 금융 API Mock 설정
    when(bankApi.requestTransfer(any()))
        .thenReturn(new TransferResponse("SUCCESS", "TXN123"));
    
    // Given: 출금 가능한 정산금이 이미 존재 (테스트 데이터 준비)
    Settlement settlement = settlementRepository.save(
        new Settlement(123L, 1_000_000L)
    );
    
    // When: 출금 요청 (실제 검증 대상)
    withdrawalService.request(settlement.getId(), 500_000L);
    
    // Then: 실제 DB에 Withdrawal이 제대로 저장되었는지 검증
    Withdrawal saved = withdrawalRepository
        .findBySettlementId(settlement.getId())
        .orElseThrow();
    
    assertThat(saved.getRequestAmount()).isEqualTo(500_000L);
    assertThat(saved.getStatus()).isEqualTo(WithdrawalStatus.COMPLETED);
}

시간은 오래 걸렸지만, 확실히 검증하고 넘어가는 게 중요했어요.

Phase 2: 이벤트 기반 아키텍처로 의존성 분리

모놀리식 통합도 중요했지만, Node.js 배치 서버는 별도 과제였어요.
하나의 배치 서버에 정산금 회수, 실시간(분단위) 대사 등 수십 개의 배치 작업이 모여 있었어요. 긴급하게 특정 기능을 수정해야 할 때가 가장 난감했죠. 배치 작업이 진행 중일 때는 서버를 재시작할 수 없었으니까요. 자칫하면 정산 금액이 잘못 계산되거나, 회수 데이터 처리가 누락될 수 있었어요. 그래서 배포할 때마다 이런 상황이 반복되었습니다.

  • “정산금 회수 배치 돌아가는 중… 30분 후에 배포”
  • “아, 대사 배치도 곧 시작하네… 1시간은 더 기다려야 할 듯”

긴급 이슈가 터져도 배치 로그를 보며 타이밍을 맞춰 배포해야 하는 상황. 이건 분명 개선이 필요했어요.

이벤트_기반_아키텍처와_비동기_처리_구조_올라핀테크

이벤트 기반 아키텍처로 전환

[이전 구조]
배치 서버 (모든 배치가 한 곳에 존재하여 배포 시 타이밍 잡아야 함)

[변경 후 구조]
이벤트 발행용 서버 → 이벤트 발행
                    ↓
                 이벤트 큐
                    ↓
           이벤트 구독용 서버 (배치 처리)

이제 배포가 자유로워졌어요

결과적으로

  • 긴급 배포가 필요해도 배치 타이밍을 기다릴 필요 없음
  • 정산 처리 중에도 발행 서버 배포 가능
  • 이벤트 큐가 버퍼 역할을 해서 트래픽 급증에도 안정적
  • 특정 배치만 수정하려면 구독 서버만 배포하면 됨

달라진 것들

서버_통합_이후_안정성과_확장성_성과_올라핀테크

#1 서비스 확장성과 안정성

이벤트 기반 아키텍처 덕분에 모놀리식 서버와 배치 서버가 독립적으로 동작하게 되었어요. 한쪽에 문제가 생겨도 다른 쪽은 정상 동작하는 구조가 되었죠.
여러 서버에 흩어져 있던 로그와 메트릭을 하나로 모니터링할 수 있게 되면서, 문제가 생겼을 때 원인을 찾는 시간이 크게 줄어들었습니다.

#2 셀러 경험의 개선

기술적 개선은 결국 사용자 경험으로 이어졌어요.
여러 서버를 거치던 API 호출이 하나의 시스템 안에서 처리되면서 응답 시간이 개선되었어요. 셀러분들이 정산금을 조회하거나 출금을 요청할 때 더 빠른 경험을 제공할 수 있게 되었죠.

#3 개발 생산성 향상

신규 팀원이 합류했을 때, 이제는 하나의 기술 스택만 익히면 됩니다. 여러 프로젝트를 오가며 혼란스러워하던 모습은 이제 찾아볼 수 없죠.
새로운 기능을 개발할 때도 하나의 프로젝트 안에서 작업이 완료되어, 여러 서버에 코드를 나눠 작성하고 배포하던 번거로움이 사라졌습니다.

전환 과정에서 함께 개선한 것들

Node.js와 PHP 코드를 Java로 옮기면서 단순 변환을 넘어 여러 부분을 개선했어요.

쿼리 튜닝
기존 코드를 분석하다 보니 성능 지연을 일으키는 쿼리들이 보였어요. WHERE 조건에 사용되는 컬럼에 인덱스를 추가하고, 불필요한 JOIN을 제거 및 애플리케이션에서 처리 등으로 개선하였어요.

테스트 환경 구축
Docker Testcontainers를 활용해 독립적인 테스트 환경을 만들었어요. 특히 출금 기능처럼 외부 금융 API 연동이 필요한 경우, Mock 테스트만으로는 안정성을 보장하기 어려웠어요. 실제 DB에 저장하고 조회하는 통합 테스트를 통해 데이터 정합성까지 함께 검증했죠.
이미 다른 방식으로 대체되었는데 코드만 남아 있던 기능들도 많았어요. 과감히 제거하면서 코드베이스를 정리할 수 있었죠. 단순히 언어만 바꾼 게 아니라, 누적된 기술 부채를 정리하는 기회가 되었습니다.

AWS와 동시 작업
서버 통합과 AWS 이전을 동시에 진행하다 보니, 어느 쪽에서 문제가 생긴 건지 파악하기 어려울 때가 있었어요.
각 단계를 명확히 나눴어요. 먼저 로컬과 개발 환경에서 Java 전환을 완전히 검증한 뒤, AWS로 배포하는 순서로 진행했죠. 한 번에 너무 많은 변수를 두지 않으려 노력했습니다.

돌아보며

5개월의 여정을 돌아보면, 쉽지 않은 선택이었지만 확실히 나아졌어요.
하나씩 검증하며 단계적으로 진행한 것이 성공의 열쇠였습니다. 한 번에 모든 걸 바꾸려 했다면 실패했을 거예요.
히스토리 없는 코드를 분석하며 문서화의 중요성을 뼈저리게 느꼈어요. 이제 우리는 모든 주요 의사결정과 비즈니스 로직을 문서로 남기고 있습니다.
그리고 무엇보다, 이벤트 기반 아키텍처로 전환하면서 서버 간 의존성을 낮춘 것이 가장 큰 수확이었어요. 향후 서비스가 더 성장하더라도, 필요한 부분만 분리해서 확장할 수 있는 유연한 구조를 만들었죠.

아직 진행 중인 이야기

현재 Node.js 모놀리식 서버, 구형 Java 서버, 그리고 PHP 일부 API의 Spring 통합과 Node.js 배치 서버의 이벤트 기반 전환이 완료되어, AWS 환경에서 안정적으로 운영 중이에요.
PHP 어드민 서버는 현재도 운영 중이며, 향후 서비스 요구사항에 따라 추가 통합 여부를 검토할 예정입니다.

완벽한 시스템은 없습니다. 하지만 우리는 계속 나아갈 수 있어요.
더 나은 서비스를 위한 기술팀의 끊임없는 도전, 그리고 아직 진행형이지만 확실한 변화를 만들고 있습니다.

 

+ Recent posts