MongoDB에서 Postgres로

참고: 이 블로그 पोस्ट는 내 MongoDB to Postgres _(2024-03-06)_와 Sequelize vs. Prisma _(2023-05-25)_의 합본입니다. 원본 블로그들은 제거되었고, 두 글이 본질적으로 같은 내용/정보를 담고 있었기 때문에 이 블로그가 그 자리를 대신하게 되었습니다. 마이그레이션은 **2023년 3월 초**에 시작되었고, 전환은 **2023년 11월 중순**에 이루어졌으며, 기존 MongoDB 시스템의 모든 인스턴스는 **2024년 1월 초**에 완전히 종료되었습니다.

소개

eBay에서 근무하던 동안, 저는 제 경력에서 가장 기술적으로 도전적인 문제에 직면했습니다. 바로 Storage Management System(STMS)을 MongoDB에서 Postgres로 마이그레이션하는 일이었습니다. 이는 단순한 데이터베이스 교체가 아니었습니다. eBay의 데이터 센터 전반에서 분당 150만 개 이상의 메트릭을 수집하는 핵심 시스템의 완전한 아키텍처 전환이었고, 무중단과 기존 기능 거의 전부의 유지가 요구되었습니다.

STMS란 무엇인가?

Storage Management System(STMS)은 eBay의 Service & Storage Infrastructure(SSI) 팀을 위한 중요한 내부 도구입니다. 이 시스템은 eBay의 데이터 센터 전반에 걸친 장치들을 모니터링하고 관리하며, 엔지니어들이 다음을 수행할 수 있게 합니다.

  • 수십 개의 배열, 스위치, 호스트, 디스크 그룹, 클러스터의 메트릭 모니터링
  • 스위치와 배열에 대한 알림 처리
  • 호스트 할당과 같은 고급 작업 완료
  • 다른 내부 eBay 서비스용 실시간 데이터 접근

STMS는 eBay의 3개 데이터 센터 전반에 걸쳐 70개가 넘는 배열, 60개의 스위치, 1100개의 호스트, 900개의 디스크 그룹, 200개의 클러스터를 관리합니다. eBay 인프라에서 매우 중요한 역할을 하는 만큼, 어떤 다운타임이나 기능 손실도 회사의 핵심 서비스와 비즈니스 운영에 직접적인 영향을 미칠 수 있었습니다.

과제

마이그레이션이 필요했던 이유

MongoDB에서 Postgres로의 마이그레이션 결정은 가볍게 내려진 것이 아니었습니다. MongoDB는 처음에는 STMS를 잘 지원했지만, 데이터 관계의 복잡성이 커지고 더 정교한 쿼리 기능이 필요해지면서 Postgres가 우리 사용 사례에 더 나은 장기적 해결책이 되었습니다.

이 문제가 어려웠던 이유

이 마이그레이션의 복잡성은 여러 근본적인 도전 과제에서 비롯되었습니다.

1. 근본적인 데이터베이스 차이 MongoDB와 Postgres는 본질적으로 다른 데이터베이스입니다. MongoDB는 문서 기반 데이터베이스(NoSQL)로, 데이터가 컬렉션 안에 JSON 형태로 저장되며, 마치 서류함에 들어 있는 문서처럼 다뤄집니다. Postgres는 관계형 데이터베이스(SQL)로, 데이터가 테이블의 행으로 저장되며, 마치 스프레드시트와 같습니다.

2. 코드베이스 아키텍처 STMS의 전체 백엔드는 데이터를 JSON으로 처리하고 관리하도록 만들어져 있었고, 데이터베이스 작업에는 MongoDB와만 호환되는 패키지들을 전용으로 사용하고 있었습니다. 이는 단순히 데이터베이스만 바꾸는 것이 아니라, 애플리케이션 전체가 데이터를 다루는 방식을 재구성해야 함을 의미했습니다.

3. 무중단 요구사항 내부 도구로서 STMS의 중요성을 고려하면, 마이그레이션 중 다운타임은 절대 허용될 수 없었습니다. 시스템은 전체 과정 동안 분당 150만 개 이상의 메트릭을 계속 처리해야 했습니다.

4. 촉박한 일정과 제한된 경험 마이그레이션은 처음에 명확한 실행 계획 없이 몇 달 안에 완료되어야 했습니다. 저와 동료들 모두 대규모 레거시 코드베이스를 NoSQL에서 SQL 데이터베이스로 마이그레이션한 경험이 없었고, 저 역시 Postgres에 대한 이전 경험이 제한적이었습니다.

5. 규모와 복잡성 이 마이그레이션에는 36개의 MongoDB 컬렉션을 74개의 Postgres 테이블로 변환하는 작업이 포함되었고, 관계, 인덱싱, 쿼리 최적화에 대한 세심한 고려가 필요했습니다.

올바른 ORM 선택: Sequelize vs Prisma

가장 먼저 내린 주요 결정 중 하나는 ORM(Object-Relational Mapping) 도구를 선택하는 것이었습니다. 우리 코드베이스는 이미 MongoDB용 Mongoose를 사용하도록 설계되어 있었기 때문에, ORM을 사용하는 것이 가장 매끄러운 전환 경로를 제공할 것이라고 판단했습니다.

요구사항 분석

프로젝트의 필요 사항을 면밀히 분석한 뒤, 어떤 ORM 솔루션이든 갖추어야 할 필수 기준을 정했습니다.

  • JavaScript 패키지여야 함(우리 코드 대부분이 JavaScript로 작성되어 있었음)
  • Postgres와 그 기능 대부분을 지원해야 함
  • 성능이 최소한 Mongoose와 동등하거나 더 좋아야 함
  • 오픈 소스이며 유지 관리되고 있어야 함

후보들

광범위한 조사 끝에, 저는 Sequelize와 Prisma라는 두 주요 후보로 범위를 좁혔습니다. Postgres용 Docker를 사용해 종합적인 테스트 환경을 만들었고, 우리의 가장 크고 복잡한 데이터셋을 문서 구조에서 테이블 구조로 변환했습니다.

테스트 방법론

각 ORM에 대해 저는 핵심 작업 전반의 성능을 측정했습니다.

  • 항목 생성 시간
  • 항목 업데이트 시간
  • 중첩 항목 업데이트 시간(관계 및 JSON 키-값)
  • 항목 삭제 시간
  • 항목 조회/가져오기 시간

결정: Sequelize

2023년 5월 15일경, 저는 Sequelize가 우리 사용 사례에 더 적합한 ORM이라고 결정했습니다. 이유는 다음과 같습니다.

Sequelize의 장점:

  • 진정한 오픈 소스이며, 자금 지원을 받는 스타트업에 의해 유지되지 않음
  • Postgres 기능 대부분을 지원함
  • 특히 Prisma와 비교했을 때 더 나은 성능
  • 10년이 넘는 개발 이력이 있는 성숙한 생태계
  • JavaScript 클래스 사용을 통한 유연한 모델/스키마 표현
  • Regex를 포함한 복잡한 조인 및 필터링 옵션 지원

성능 결과:

제 테스트에서 Sequelize는 Prisma를 크게 앞질렀습니다. 우리의 대용량 데이터셋 항목에 대해:

  • Sequelize: 항목당 약 2.26초
  • Prisma: 항목당 약 11.21초

우리 사용 사례에서 Prisma는 Sequelize보다 대략 5배 느렸습니다. 또한, 가장 큰 데이터셋에서 항목 하나를 삭제하는 데 Prisma는 거의 4분이 걸렸는데, 이는 우리의 요구사항에 전혀 맞지 않았습니다.

Sequelize의 과제:

  • 더 복잡하고 부풀려진 모델 표현(Mongoose 262줄 vs 564줄)
  • 특정 경우에 혼란스러운 문법
  • 데이터베이스 마이그레이션의 복잡성
  • Prisma에 비해 덜 포괄적인 문서

Sequelize와 Prisma의 장단점 비교

제가 왜 Sequelize를 선택했는지 더 완전하게 보여드리기 위해, 평가 과정에서 두 ORM에 대해 정리했던 상세한 장단점을 공유하고자 합니다. 또한 2023년 5월 15일 기준으로 스키마 표현과 커뮤니티 지원 측면에서 어떻게 비교되는지도 살펴보았습니다. 이 더 깊은 분석은 제 선택을 확고하게 해주었고, 비슷한 결정을 앞둔 다른 분들에게도 도움이 되기를 바랍니다.

Sequelize의 장점:

  • sync() 함수가 있어 테이블을 자동으로 생성하고 관리해 주므로 많은 수작업을 줄여줌.
  • 중첩 데이터에 대한 복잡한 조인을 처리할 수 있어 STMS 구조에 매우 중요했음.
  • Regex를 포함한 다양한 필터링 옵션을 지원하여 쿼리에 유연성을 제공함.
  • 모델/스키마 표현이 클래스 기반의 순수 JavaScript로 이루어져 있어 특정 요구사항에 맞게 매우 커스터마이징 가능함.
  • 여러 읽기 연결을 지원하는 것을 포함해 데이터베이스 연결을 매끄럽게 처리함.
  • 내부를 직접 다루어야 할 때 사용할 수 있는 raw SQL 쿼리를 지원함.
  • 2023년 5월 15일 기준 커뮤니티 통계: NPM에서는 14일 전에 마지막 업데이트되었고 주간 다운로드 수는 1,505,835개; GitHub에서는 어제 마지막 업데이트되었고 Fork 4.2천 개, Star 27.9천 개. 10년 넘게 MIT 라이선스로 오픈 소스로 유지되어 왔으므로 앞으로도 그럴 것이라 확신함.

Sequelize의 단점:

  • 모델/스키마 표현이 매우 복잡하고 부풀려질 수 있음. 예를 들어, 대용량 데이터셋의 Mongoose 표현은 약 262줄(공백 포함)이었지만, 같은 데이터셋은 Sequelize에서 564줄로 불어났음.
  • 특정 상황에서 문법이 혼란스럽고 복잡해, 때때로 작업 속도가 느려졌음.
  • 데이터베이스 마이그레이션이나 편집이 번거로움. sequelize-cli가 마이그레이션 스크립트를 생성해 주더라도 여전히 다루기 까다로운데, 이는 대부분의 ORM에서 흔한 고충이라는 것도 알게 되었음.
  • 문서가 그다지 훌륭하지는 않지만, 개선되고 있음. 다행히 ChatGPT 같은 도구는 Sequelize의 긴 역사 덕분에 꽤 잘 이해하고 있어서 부족한 부분을 메우는 데 도움이 되었음.
  • Prisma만큼 타입에 민감하지 않아 일부 프로젝트에서는 문제를 일으킬 수 있음.
  • TypeScript 지원이 제한적임. 이는 STMS에는 문제가 아니었지만, 다른 사람들에게는 결정적인 단점이 될 수 있음.

Prisma의 장점:

  • 자체 스키마 언어를 사용하여 모델 생성이 더 깔끔하고 간결함. 비교해 보면, Mongoose는 우리 대용량 데이터셋에 262줄이 필요했지만, Prisma는 221줄만으로 처리했음.
  • 데이터베이스 생성과 마이그레이션을 단순화하는 CLI 도구가 함께 제공되며, 비록 완벽하지는 않더라도 지금까지 본 ORM 중에서는 가장 좋았음.
  • 필요할 때 유연성을 제공하는 raw SQL 쿼리를 지원함.
  • Sequelize에 비해 코드 문법이 깔끔하고 이해하기 쉬워 배우기 쉬움.
  • 클라이언트를 통해 Node.js와 TypeScript용 쿼리 빌더를 자동 생성해 주는 점이 좋음.
  • 문서가 훌륭하고 깔끔함. ChatGPT는 Prisma에 대해 최신 정보가 덜했지만, 공식 문서가 종종 그 부족함을 보완해 주었음.
  • 2023년 5월 15일 기준 커뮤니티 통계: NPM에서는 6일 전에 마지막 업데이트되었고 주간 다운로드 수는 1,344,705개; GitHub에서는 3시간 전에 마지막 업데이트되었고 Fork 1.1천 개, Star 31.3천 개.

Prisma의 단점:

  • Postgres에서 Regex 필터링을 지원하지 않음. 다만 “contains”, “includes”, “startsWith” 같은 대안은 제공함.
  • 제 테스트에서는 성능이 큰 문제였음. 대용량 데이터셋에 항목을 생성하는 데 Prisma는 항목당 약 11.21초가 걸린 반면 Sequelize는 2.26초가 걸려, 대략 5배 느렸음.
  • 대용량 데이터셋에서 항목 하나를 삭제하는 데 거의 4분이 걸렸고, 이는 우리의 필요에선 결정적인 탈락 사유였음.
  • 세 층 깊이의 관계를 가진 복잡한 데이터셋에 대해 공정하게 비교했을 때도, 삭제에서는 Sequelize가 훨씬 빨랐음.
  • Prisma는 5,650만 달러의 자금 지원을 받는 스타트업이 뒷받침하고 있음. 핵심 ORM 코드는 Apache-2.0 하에 오픈 소스이지만, MongoDB에서 그랬던 것과 비슷하게 향후 라이선스 변경이 생길 가능성에는 경계하고 있음.

이런 상세한 비교를 통해 Sequelize가 STMS의 요구사항, 특히 성능과 장기적 신뢰성 측면에서 더 잘 맞는다는 것이 분명해졌습니다. 그래도 이렇게 나눠서 설명하면 같은 선택을 고민하는 다른 사람들에게도 도움이 될 수 있을 것 같았습니다.

마이그레이션 과정

데이터 구조 변환

MongoDB의 문서 구조를 Postgres의 관계형 구조로 변환하는 작업은 신중한 계획이 필요했습니다. 저는 다음을 해야 했습니다:

  1. 관계 분석: MongoDB 문서들이 서로 어떻게 연관되는지 식별하고 적절한 외래 키 관계를 설계하기
  2. 데이터 정규화: 적절한 경우 중첩 문서를 별도의 테이블로 분해하기
  3. JSON 기능 보존: 유연하게 남아 있어야 하는 진정으로 비정형인 데이터에는 JSONB 열을 사용하기
  4. 인덱스 설계: 쿼리 성능을 위한 적절한 인덱스 생성하기

맞춤형 솔루션

마이그레이션에는 여러 맞춤형 솔루션을 개발하는 것이 필요했습니다:

1. 데이터 마이그레이션 스크립트 저는 다음을 위해 포괄적인 스크립트를 만들었습니다:

  • MongoDB 컬렉션에서 데이터 추출
  • 문서 구조를 관계형 형식으로 변환
  • 적절한 관계를 포함해 Postgres 테이블에 데이터 가져오기

2. API 호환성 계층 무중단을 유지하기 위해 저는 다음이 가능한 호환성 계층을 구축했습니다:

  • 마이그레이션 상태에 따라 요청을 MongoDB 또는 Postgres로 라우팅
  • 전환 기간 동안 데이터 일관성 보장
  • 폴백 메커니즘 제공

3. 맞춤형 미들웨어 MongoDB와 Postgres가 특정 작업을 처리하는 방식의 차이를 다루기 위한 미들웨어를 개발하여, 기존 API 엔드포인트가 수정 없이 계속 동작하도록 보장했습니다.

기술적 과제 극복

복잡한 관계 처리

가장 큰 과제 중 하나는 MongoDB의 임베디드 문서를 Postgres 관계로 변환하는 것이었습니다. 예를 들어, 단일 MongoDB 문서는 다음을 포함할 수 있었습니다:

  • 기본 속성
  • 관련 엔터티를 나타내는 중첩 객체
  • 임베디드 문서 배열

이는 다음으로 신중하게 분해되어야 했습니다:

  • 주요 엔터티를 위한 기본 테이블
  • 다대다 관계를 위한 조인 테이블
  • 일대다 연관을 위한 외래 키 관계

쿼리 최적화

MongoDB의 쿼리 패턴은 SQL로 직접 변환되지 않습니다. 저는 다음을 해야 했습니다:

  • 복잡한 집계 파이프라인을 SQL 조인으로 다시 작성하기
  • 새로운 쿼리 패턴에 맞게 인덱스 최적화하기
  • 쿼리 성능이 MongoDB 성능과 같거나 더 높도록 보장하기

데이터 무결성

마이그레이션 동안 데이터 무결성을 보장하기 위해 다음이 필요했습니다:

  • 포괄적인 검증 스크립트
  • 롤백 절차
  • 전환 기간 동안의 실시간 데이터 동기화

결과 및 영향

MongoDB에서 Postgres로의 STMS 마이그레이션은 거의 모든 기능과 성능을 유지한 채 무중단으로 성공적으로 완료되었습니다. 결과는 기대를 뛰어넘었습니다:

성능 향상:

  • 복잡한 관계형 쿼리의 쿼리 성능 향상
  • 더 나은 데이터 일관성 및 무결성
  • 더 효율적인 저장소 활용

운영상의 이점:

  • 모니터링 및 디버깅 기능 향상
  • eBay의 기존 SQL 기반 도구와의 더 나은 통합
  • 개선된 백업 및 복구 절차

팀에 미친 영향:

  • 관계형 데이터베이스에 대한 팀 지식 향상
  • 향후 데이터베이스 마이그레이션을 위한 패턴 확립
  • 재사용 가능한 도구와 프로세스 생성

얻은 기술 역량

이 프로젝트는 저의 기술적 전문성을 크게 확장시켰습니다:

데이터베이스 기술:

  • Postgres 기능과 최적화에 대한 깊은 이해
  • SQL 쿼리 최적화 및 성능 튜닝
  • 데이터베이스 설계 패턴 및 정규화
  • Primary-standby 데이터베이스 구성

개발 도구:

  • Sequelize ORM 및 쿼리 구성
  • 데이터베이스 마이그레이션 전략
  • 성능 테스트 방법론
  • 데이터 검증 및 무결성 검사

아키텍처 패턴:

  • 무중단 마이그레이션 전략
  • API 호환성 계층
  • 데이터베이스 추상화 패턴
  • 모니터링 및 알림 시스템

개인적 및 직업적 성장

이 마이그레이션 프로젝트는 제 경력 개발에 변혁적인 경험이었습니다. 이는 저를 미개척 영역으로 밀어 넣었고, 다음을 요구했습니다:

리더십 역량:

  • 사전 경험 없이 복잡한 기술 프로젝트를 이끌기
  • 압박 속에서 중요한 아키텍처 결정을 내리기
  • 여러 팀 및 이해관계자와 조율하기

문제 해결 능력:

  • 복잡한 문제를 관리 가능한 구성 요소로 나누기
  • 전례 없는 도전에 대한 창의적인 해결책 개발하기
  • 여러 경쟁하는 요구사항과 제약 사이의 균형 맞추기

커뮤니케이션 및 팀워크:

  • 기술적 개념을 비기술적 이해관계자에게 설명하기
  • 미래 참고를 위해 프로세스와 결정을 문서화하기
  • 새로운 기술과 패턴에 대해 팀원들을 멘토링하기

배운 교훈

기술적 교훈

  1. 데이터베이스 선택은 중요하다: NoSQL과 SQL 중 선택은 특정 사용 사례와 장기적 요구사항에 기반해야 한다
  2. 성능 테스트는 매우 중요하다: 이론적 이점이 항상 실제 성능 향상으로 이어지지는 않는다
  3. 마이그레이션 계획: 복잡한 마이그레이션에는 포괄적인 계획과 테스트가 필수적이다
  4. 도구 투자: 초기에 적절한 도구를 구축하면 상당한 시간을 절약하고 오류를 줄일 수 있다

프로젝트 관리 교훈

  1. 이해관계자 커뮤니케이션: 정기적인 업데이트와 명확한 소통은 오해를 방지한다
  2. 위험 관리: 대체 계획과 롤백 절차를 갖추는 것은 필수적이다
  3. 일정 관리: 예상치 못한 도전과 학습 곡선을 위한 여유 시간을 두기
  4. 문서화: 철저한 문서화는 지식 이전과 향후 유지보수를 가능하게 한다

결론

STMS의 MongoDB에서 Postgres로의 마이그레이션은 제가 경력에서 해결한 가장 도전적이고 보람 있는 기술적 문제로 남아 있습니다. 이는 단지 기술적 전문성뿐 아니라 리더십, 계획, 적응성도 요구했습니다. 프로젝트의 성공은 적절한 계획, 철저한 테스트, 그리고 탁월함에 대한 헌신이 있다면 가장 복잡한 기술적 과제도 극복할 수 있음을 보여주었습니다.

이 경험은 소프트웨어 엔지니어링에 대한 저의 접근 방식을 근본적으로 바꾸었고, 다음의 중요성을 강조했습니다:

  • 기술적 결정을 내리기 전에 전체 맥락과 요구사항을 이해하기
  • 적절한 도구와 테스트에 시간을 투자하기
  • 복잡한 프로젝트 전반에 걸쳐 명확한 커뮤니케이션을 유지하기
  • 필요할 때 새로운 기술과 접근 방식을 기꺼이 배우기

마이그레이션의 성공은 STMS의 역량을 향상시켰을 뿐만 아니라, eBay의 인프라 프로젝트에 계속해서 이점을 제공하는 패턴과 프로세스도 확립했습니다. 이는 알 수 없는 도전을 받아들이고 그 도전 속에서 성공하는 것이 개인적 성장과 직업적 성장 모두의 핵심이라는 제 믿음을 강화했습니다.

돌이켜보면, 이 프로젝트는 제 경력의 전환점을 의미하며, 해결책을 구현하는 개발자에서 복잡한 기술 이니셔티브를 설계하고 이끌 수 있는 엔지니어로 저를 변화시켰습니다. 이 경험을 통해 얻은 자신감과 기술은 소프트웨어 엔지니어링에서 새로운 도전과 기회에 접근하는 제 방식을 계속 이끌고 있습니다.