이번 글에서는 AI 피처 스토어를 MongoDB와 Spring Cloud Stream으로 새롭게 구축한 이야기를 공유하려고 합니다. 간단히 요약하자면, 기존의 레거시 AI 피처 스토어 시스템에서 발생한 여러 문제를 해결하기 위해 MongoDB와 Spring Cloud Stream을 도입해 새로운 시스템을 개발해 레거시를 대체하는 과정을 다루려고 합니다.
우리는 새로운 목적으로 처음부터 새로운 시스템을 구축하기도 하지만, 기존 시스템을 인계받아 문제를 개선하거나 때로는 기존 시스템의 목적을 이어받는 완전히 새로운 시스템을 구축하기도 합니다. 즉, 종종 복잡하고 불완전한 레거시 시스템을 받아 이를 개선하고 대체해야 하는 상황과 마주칩니다. SNS에 올라오는 멋진 프로젝트들처럼 모든 개발 여정이 화려한 것은 아니죠. 이 글은 이와 같이 레거시를 대체하는 새로운 시스템을 개발하는 경험을 공유해 비슷한 상황에 처한 많은 개발자분들께 작은 도움이 되기를 바라며 작성했습니다.
이번 글은 특별히 저희 팀이 아닌 Mongo DB의 DBA이신 이세웅 님도 함께 작성해 주셨습니다. 이번 프로젝트의 핵심 과제 중 하나가 그 자체로 또 하나의 도전이라고 할 수 있을 정도로 전례 없는 규모의 대용량 MongoDB 샤딩된 클러스터(sharded cluster)를 구축하는 것이었기 때문입니다. 평소 MongoDB에 관심이 있었던 분들, 특히 대규모 MongoDB 운영 및 구축과 관련된 실제 업무 경험담을 찾고 계신 분들께 도움이 되기를 바라며 본격적으로 이야기를 시작해 보겠습니다.
프로젝트 소개
이번 프로젝트는 여러 문제를 안고 있던 레거시 피처 스토어(이하 레거시)를 대체할 수 있는 완전히 새로운 피처 스토어를 개발하는 프로젝트였습니다. 피처 스토어란 AI에서 사용하는 실시간 및 배치 데이터를 저장하고 처리해 피처를 재사용하고 일관성을 유지할 수 있게 만드는 시스템입니다. AI 모델 개발과 운영을 위한 피처 변환(feature transformation), 서빙, 스토리지 등의 기능을 제공합니다(피처 스토어의 역할이나 효용에 대한 보다 자세한 사항은 MACHINE LEARNING FEATURE STORES: A COMPREHENSIVE OVERVIEW를 참고하시기 바랍니다).
이전에 대용량 AI 실시간 임베딩 데이터를 효율적으로 다루기라는 글로 AI에 사용하는 실시간 임베딩을 제공하는 고성능 고효율 서버를 구축한 과정과 결과를 공유한 적이 있는데요. 이번에 소개하는 프로젝트는 이전에 소개한 프로젝트와 결합해 더 다양한 종류의 AI 데이터를 제공하는 역할을 담당하는 시스템을 개발하는 프로젝트입니다.
두 프로젝트가 다루는 AI 데이터의 성질이 다르고 그로 인해 시스템 구성도 완전히 다르기 때문에 이전 글을 보지 않으신 분들도 이 글을 이해하시는 데 전혀 문제는 없습니다. 다만 두 글을 모두 읽어보시면 데이터의 성질에 따라 시스템 구조가 얼마나 많이 달라지는지, 또한 각각 어떤 DB를 사용했고 그 이유가 무엇인지 비교해 보실 수 있기 때문에 아직 이전 글을 보지 않으셨다면 이전 글도 함께 읽어보시기를 권해 드립니다.
레거시 시스템 분석
개발자들은 간혹 기존에 존재하던 레거시를 인계받아 더 나은 시스템을 만드는 일을 맡게 됩니다. 이때 레거시 개발에 본인이 참여하지 않았다면 기존 시스템을 분석하는 일부터 시작해야 하며, 얼마나 정확히 분석하느냐가 이후 작업에 큰 영향을 미칩니다.
레거시 시스템을 분석할 때는 레거시의 기획 의도와 목적, 주변 시스템과의 관계, 인프라 환경과 같은 시스템 환경을 파악해야 하고, 만일 시스템에 문제가 있을 경우 문제의 원인을 정확히 진단해야 합니다. 그래야 기존의 역할을 충실히 수행하면서 문제를 해결할 수 있는 새로운 시스템을 만들 수 있습니다.
이번 프로젝트에서도 가장 첫 번째 단계가 레거시 시스템 분석이었으며, 레거시 시스템의 환경과 문제는 아래와 같았습니다.
레거시 시스템의 본래 목표
기존 레거시 AI 피처 스토어 시스템의 주요 목표 중 하나는 대용량 파케이(parquet) 파일을 적재하고 관리하는 것이었습니다. 조금 더 구체적으로 말하자면, 매일 또는 특정 주기에 맞춰 AI 서비스용 대용량 파케이 파일을 다운로드하고 이를 검증한 후 정해진 시간 내에 DB에 적재해 AI 모델의 훈련과 실제 서비스에 활용되도록 만드는 것이었습니다.
겉으로 보기에는 비교적 단순한 데이터 파이프라인처럼 보일 수 있지만 실제로는 다음과 같은 이유로 높은 성능을 요구하는 까다로운 과제였습니다.
- 시스템이 주기적으로 처리해야 하는 파케이 파일은 하나당 수 GB에서 수백 GB에 이르는 대용량 파일이었으며, 이런 파일을 동시에 혹은 순차적으로 수십 개에서 수백 개씩 처리해야 했습니다.
- 하루 동안 처리해야 하는 총 데이터량은 수 테라바이트를 초과했으며, 지속적으로 보관해야 할 데이터 규모도 수십 테라바이트에 달했습니다.
- 전체 프로세스(파케이 파일 준비 → 다운로드 → 압축 해제 → 검증 → DB 적재 → 상태 변경 및 TTL 만료 데이터 삭제)를 반드시 정해진 시간 안에 완료해야 했습니다.
- 만약 처리 지연이 발생할 경우 연관된 후속 작업과 관련 시스템에 연쇄적인 장애가 발생할 수 있어 안정적인 처리가 필수였습니다.
- 신규 데이터 적재 작업 중에도 서비스는 중단 없이 실시간 요청을 처리해야 했으며, 이때 응답 시간을 반드시 일정 수준 이내로 유지해야 했습니다.
결과적으로 대용량 데이터 처리와 엄격한 시간 제약, 실시간 응답이라는 세 가지 요구 사항을 모두 만족하는 아키텍처 설계가 프로젝트의 핵심 과제였습니다.
레거시 시스템 문제 분석
레거시 시스템은 앞서 말씀드린 목표를 충족하며 작동하고 있었지만 다소의 문제를 지니고 있었으며, 문제는 서버 및 애플리케이션 구성의 문제와, 메인 DB로 사용된 TiDB의 제약으로 나눌 수 있었습니다.
서버와 애플리케이션 구성의 문제
레거시 시스템의 첫 번째 문제는 서버와 애플리케이션 구성 때문에 서버 자원을 비효율적으로 활용하고 있다는 것이었습니다. 레거시 시스템 개발 시 선택된 서버들은 아래 설명할 파케이 파일에 대한 잘못된 접근법 때문에 CPU 대비 메모리 용량이 비정상적으로 큰 고가 장비들이었고, 단일 노드풀에 집중 배치돼 있었습니다. 그런데 이와 같이 고사양 서버를 다수 사용하고 있었지만 실제 애플리케이션 서버 리소스를 충분히 활용하지는 못하고 있었는데요. 이로 인해 쿠버네티스 환경에서 여러 종류의 파드를 세분화해서 배치하는 데 한계가 있었고, 메모리는 남는 반면 CPU는 부족해지는 비효율이 발생했습니다.
이 문제를 해결하기 위해서는 근본적인 인프라 구조를 개선할 필요가 있었습니다. 일부 장비를 반납하고 새로운 서버를 추가한 후 노드 풀을 나누는 식으로 조치한다면 부분적인 개선은 가능하겠지만 이는 근본적인 해결책이 아니라 그 한계가 분명했습니다. 결국 인프라 비용을 획기적으로 절감하고 운영 유연성을 확보하기 위해 고가 장비를 모두 반납하고 CPU/메모리 비율이 표준인 작은 VM 기반으로 전환하는 전략이 필요했습니다. 또한 서비스 무중단이라는 조건을 충족하기 위해 새로운 노드 풀을 별도로 구축하고 이전하는 방식이 현실적인 선택이었습니다.
TiDB 성능 한계와 애플리케이션 병목
레거시 시스템은 TiDB를 메인 DB로 사용했는데 TiDB의 쓰기 성능과 확장성 한계로 인해 애플리케이션 코드 곳곳에 이를 우회하거나 버티기 위한 비효율적인 구현이 있었습니다. 이런 방식은 시스템 전체의 복잡도를 높이고 프로젝트 전반의 품질을 저하시키는 원인이 되었습니다.
예외 상황 대응의 어려움
레거시 시스템은 대규모 파일 처리 작업에 취약점이 있어 예외 상황에 대응하기 어렵다는 문제도 있었습니다. 레거시 시스템은 매일 수십에서 수백 개의 대용량 파케이 파일을 다운로드해 압축 해제 후 검증하고 DB에 입력하는 과정을 반복했는데요. 파일 처리 도중 오류가 발생하면 정확한 상태를 추적하거나 자동 재시도하는 기능이 없어 사람이 직접 개입해야 했습니다. 이런 문제는 운영의 부담을 가중시켰고, 시스템 정합성에도 잠재적인 위험 요소가 되었습니다.
사용하는 DB(TiDB)의 문제
아래에 기술하는 레거시 시스템의 TiDB 관련 문제들은 TiDB의 특성과 제약에서 비롯된 것일 수도 있지만 다른 한편으로는 구성 방식에 기인한 문제일 가능성도 있습니다. 따라서 본 글에서 언급하는 문제들을 TiDB 전반의 문제로 일반화하는 것은 적절하지 않습니다.다만 유사한 환경에서 비슷한 어려움을 겪고 있는 분들에게는 저희의 경험이 실질적인 참고 자료가 될 수 있을 것이라고 생각합니다. 특히 시스템 설계나 DB 선택 과정에서 고려해야 할 포인트를 고민하고 계신다면 끝까지 읽어보시길 추천드립니다.
첫 번째 문제는 부하를 분산할 필요가 있었다는 것입니다.
매일, 매시간 대량의 신규 데이터가 레거시 시스템에 입력되면 TiDB의 CPU와 I/O 사용량은 한계에 근접했고 이 때문에 서비스 요청 처리에 어려움이 발생했습니다. TiDB는 래프트 합의 알고리즘을 기반으로 리더 노드가 쓰기(write) 요청을 처리한 후 로그를 팔로워(follower) 노드에 전파하고 이를 통해 데이터 일관성(consistency)을 보장합니다. 기본적으로 읽기와 쓰기 요청 모두 리더 노드가 처리하는 구조이기 때문에 대량 쓰기 작업이 집중되는 시간대에는 리더 노드의 부하가 급격히 증가해 서비스 응답 속도가 현저히 저하될 수 있으며, 과도한 작업 부하를 감당하지 못해 다운될 수도 있습니다. 만약 다운된다면 후보 노드 간 리더 선출 과정이 추가로 발생해 서비스 안정성에 부정적인 영향을 미칠 가능성도 존재합니다.
이 문제를 해결하려면 읽기와 쓰기 작업을 분리해 각각 다른 노드에서 처리하는 방식이 필요합니다. 일반적으로 복제(replication)를 지원하는 DB에서는 쓰기 요청은 리더 노드가 처리하고 읽기 요청은 레플리카 노드로 분산해 시스템 부하를 효과적으로 분산시킬 수 있습니다. TiDB도 팔로워 읽기 기능(참고)을 지원하는 버전부터는 해당 옵션을 사용 시 읽기 요청을 팔로워 노드에서 처리함으로써 리더 노드의 부하를 일부 분산할 수 있게 되었습니다. 다만 레거시 시스템의 경우 구축 시 부하 분산 관련 고려가 없었던 것으로 보였으며, 인계받은 후에는 조치를 취할 수 있는 상황이 아니었습니다.

두 번째 문제는 레거시 시스템의 TiDB는 HA(high availability) 구성이 완벽하다고 할 수 없었다는 점입니다.
아무리 인프라 환경이 좋고 안정적이라고 하더라도 운영하다 보면 하드웨어 문제를 비롯한 여러 문제가 발생할 수밖에 없습니다. 따라서 DB와 서버 등 인프라 환경의 HA 구성은 필수입니다. DB 종류에 따라 약간의 차이는 있지만 HA로 구성해 놓았을 경우 장애 감지부터 대응까지 모든 과정이 자동으로 순식간에 이뤄지기 때문에 사용자가 장애를 체감하지 못하거나 아주 짧은 순간 동안만 접속이 불가능해질 뿐입니다. 만약 HA 구성을 하지 않거나 구성에 문제가 있다면 장애 감지와 대응의 일정 부분 이상을 사람이 대응해야 하는데요. 수동으로 대응하면 속도나 정확도 등 여러 가지 면에서 불리할 수밖에 없습니다.
또한 매우 드문 경우이긴 하지만 HA 구성을 해놓았다고 해도 세컨더리 장비까지 동시에 문제가 발생하거나 천재지변 등으로 장비가 파손될 수도 있습니다. 따라서 데이터를 안전하게 백업해 놓거나 다른 복구 수단 및 시나리오도 준비해야 합니다. 발생할 수 있는 다양한 장애 시나리오에 얼마나 만전을 기해 대비했느냐에 따라 비상 상황 시 복구에 걸리는 시간이 수초에서 수일까지 늘어날 수도 있고 아예 복구에 실패할 수도 있습니다. 레거시 시스템은 자체 진단 결과 이런 면에서 저희가 생각하는 완벽한 지점에 이르기 힘들다고 판단했으며, 이는 다른 DB로 대체하기로 결정한 주요 원인 중 하나였습니다.
세 번째 문제는 TiDB 전문 담당 조직과 DBA의 부재였습니다.
TiDB는 전통적인 메이저 DBMS와 비교할 때 상대적으로 인력 풀이 작은 DBMS입니다. 따라서 TiDB의 전담 DBA나 전문 조직이 마련되어 있는 경우가 많지 않습니다. 이는 레거시 시스템이 개발된 당시 상황은 모르겠지만 인계받은 시점에서는 큰 부담으로 다가오는 문제였으며, 이 또한 TiDB를 대체할 다른 DB를 도입하기로 결정한 이유 중 하나였습니다.
이와 같이 레거시 시스템의 문제는 애플리케이션과 DB 부분으로 나눌 수 있었으며, 이에 따라 해결 방안도 두 갈래로 나눌 수 있었습니다. 먼저 애플리케이션 문제를 어떻게 해결했는지 말씀드리고, 이후 TiDB에서 비롯된 문제를 해결하기 위해 대용량 MongoDB 샤딩된 클러스터를 구축하고 최적화한 과정을 설명하겠습니다.
레거시 시스템의 문제 해결하기 1: 서버와 애플리케이션 문제 해결하기
서버와 애플리케이션 문제를 해결하기 전에 앞서 소개한 문제들의 근본적인 원인을 먼저 살펴보겠습니다. 저희는 이를 통해 문제의 핵심을 이해하고 해결 방안을 도출할 수 있었습니다.
문제의 근본 원인: 파케이 파일에 대한 잘못된 접근법
수백 기가바이트에 달하는 대용량 파케이 파일 데이터는 전략적으로 접근해 적절