Blue가 B2B SaaS에서 Rust와 확장 가능한 아키텍처 및 전략적 기술 선택을 사용하여 CSV 가져오기 및 내보내기를 10배 확장한 방법을 알아보세요.
Blue에서는 프로젝트 관리 소프트웨어에서 가능한 것의 경계를 지속적으로 확장하고 있습니다. 수년간 우리는 수백 가지 기능을 출시했습니다.
우리의 최신 엔지니어링 성과는 무엇일까요?
우리의 CSV 가져오기 및 내보내기 시스템을 완전히 개편하여 성능과 확장성을 극적으로 개선했습니다.
이 게시물에서는 우리가 이 도전에 어떻게 대처했는지, 우리가 사용한 기술, 그리고 우리가 달성한 인상적인 결과를 뒷이야기로 소개합니다.
여기서 가장 흥미로운 점은 우리가 원하는 결과를 얻기 위해 일반적인 기술 스택에서 벗어나야 했다는 것입니다. 이는 신중하게 결정해야 할 사항입니다. 왜냐하면 장기적인 결과가 기술 부채와 장기 유지 관리 비용 측면에서 심각할 수 있기 때문입니다.
기업의 요구에 맞춘 확장
우리의 여정은 이벤트 산업의 한 기업 고객의 요청으로 시작되었습니다. 이 고객은 Blue를 이벤트, 장소 및 연사 목록을 관리하는 중앙 허브로 사용하며, 이를 웹사이트와 원활하게 통합합니다.
그들에게 Blue는 단순한 도구가 아닙니다 — 그들의 전체 운영에 대한 단일 진실의 원천입니다.
우리는 고객이 이러한 미션 크리티컬한 요구를 위해 우리를 사용한다는 이야기를 듣는 것이 항상 자랑스럽지만, 빠르고 신뢰할 수 있는 시스템을 보장해야 할 책임도 큽니다.
이 고객이 운영을 확장하면서 그들은 중대한 장애물에 직면했습니다: 100,000에서 200,000개 이상의 레코드가 포함된 대형 CSV 파일의 가져오기 및 내보내기.
이는 당시 우리 시스템의 능력을 초과하는 것이었습니다. 사실, 이전의 가져오기/내보내기 시스템은 이미 10,000에서 20,000개의 레코드가 포함된 가져오기 및 내보내기로 어려움을 겪고 있었습니다! 따라서 200,000개 이상의 레코드는 불가능했습니다.
사용자들은 답답한 긴 대기 시간을 경험했고, 경우에 따라 가져오기 또는 내보내기가 완료되지 않는 경우도 있었습니다. 이는 그들이 특정 운영 측면을 관리하기 위해 매일 가져오기 및 내보내기에 의존했기 때문에 그들의 운영에 심각한 영향을 미쳤습니다.
다중 테넌시는 단일 소프트웨어 인스턴스가 여러 고객(테넌트)에 서비스를 제공하는 아키텍처입니다. 효율적이지만, 한 테넌트의 작업이 다른 테넌트에 부정적인 영향을 미치지 않도록 신중한 리소스 관리가 필요합니다.
그리고 이 제한은 특정 고객에게만 영향을 미치는 것이 아니었습니다.
우리의 다중 테넌트 아키텍처로 인해 — 여러 고객이 동일한 인프라를 공유하는 — 단일 리소스 집약적인 가져오기 또는 내보내기가 다른 사용자에게 운영 속도를 늦출 수 있었고, 실제로 종종 발생했습니다.
우리는 항상 구축 대 구매 분석을 수행하여 우리 시스템을 업그레이드하는 데 시간을 투자해야 할지, 아니면 다른 곳에서 시스템을 구매해야 할지를 이해했습니다. 우리는 다양한 가능성을 살펴보았습니다.
눈에 띄는 공급업체는 Flatfile이라는 SaaS 제공업체였습니다. 그들의 시스템과 기능은 우리가 필요로 하는 것과 정확히 일치하는 것처럼 보였습니다.
하지만 그들의 가격을 검토한 후, 우리는 이것이 우리의 규모에 비해 매우 비싼 솔루션이 될 것이라는 결론에 도달했습니다 — 파일당 $2는 정말 빠르게 합산됩니다! — 따라서 내장된 CSV 가져오기/내보내기 엔진을 확장하는 것이 더 나았습니다.
이 도전에 대처하기 위해 우리는 대담한 결정을 내렸습니다: 주로 Javascript 기술 스택에 Rust를 도입하는 것입니다. 성능과 안전성으로 알려진 이 시스템 프로그래밍 언어는 성능이 중요한 CSV 파싱 및 데이터 매핑 요구에 완벽한 도구였습니다.
우리가 해결책에 접근한 방법은 다음과 같습니다.
백그라운드 서비스 도입
우리 솔루션의 기초는 리소스 집약적인 작업을 처리하기 위해 백그라운드 서비스를 도입하는 것이었습니다. 이 접근 방식은 주요 서버에서 무거운 처리를 오프로드하여 전체 시스템 성능을 크게 개선할 수 있게 해주었습니다.
우리의 백그라운드 서비스 아키텍처는 확장성을 염두에 두고 설계되었습니다. 우리 인프라의 모든 구성 요소와 마찬가지로, 이러한 서비스는 수요에 따라 자동으로 확장됩니다.
이는 여러 대형 가져오기 또는 내보내기가 동시에 처리되는 피크 시간 동안 시스템이 자동으로 더 많은 리소스를 할당하여 증가된 부하를 처리할 수 있음을 의미합니다. 반대로, 조용한 기간 동안에는 리소스 사용을 최적화하기 위해 축소됩니다.
이 확장 가능한 백그라운드 서비스 아키텍처는 CSV 가져오기 및 내보내기뿐만 아니라 Blue에도 혜택을 주었습니다. 시간이 지나면서 우리는 주요 서버의 부하를 줄이기 위해 상당수의 기능을 백그라운드 서비스로 이동했습니다:
- 수식 계산: 복잡한 수학적 작업을 오프로드하여 주요 서버 성능에 영향을 주지 않고 파생 필드의 빠른 업데이트를 보장합니다.
- 대시보드/차트: 사용자 인터페이스를 느리게 하지 않고 최신 시각화를 생성하기 위해 대량의 데이터 세트를 백그라운드에서 처리합니다.
- 검색 인덱스: 시스템 성능에 영향을 주지 않으면서 빠르고 정확한 검색 결과를 보장하기 위해 백그라운드에서 검색 인덱스를 지속적으로 업데이트합니다.
- 프로젝트 복사: 대규모 복잡한 프로젝트의 복제를 백그라운드에서 처리하여 사용자가 복사가 생성되는 동안 계속 작업할 수 있도록 합니다.
- 프로젝트 관리 자동화: 다른 작업을 차단하지 않고 적시에 작업을 보장하기 위해 백그라운드에서 사용자 정의 자동화된 워크플로를 실행합니다.
- 반복 레코드: 백그라운드에서 반복 작업이나 이벤트를 생성하여 주요 애플리케이션에 부담을 주지 않고 일정 정확성을 유지합니다.
- 시간 지속 사용자 정의 필드: Blue에서 두 이벤트 간의 시간 차이를 지속적으로 계산하고 업데이트하여 시스템 반응성을 저하시키지 않고 실시간 지속 데이터를 제공합니다.
데이터 파싱을 위한 새로운 Rust 모듈
우리의 CSV 처리 솔루션의 핵심은 사용자 정의 Rust 모듈입니다. 이는 우리의 핵심 기술 스택인 Javascript를 벗어난 첫 번째 시도였지만, Rust를 사용하기로 한 결정은 동시 작업 및 파일 처리 작업에서의 뛰어난 성능에 의해 촉발되었습니다.
Rust의 강점은 CSV 파싱 및 데이터 매핑의 요구와 완벽하게 일치합니다. 제로 비용 추상화는 성능을 희생하지 않고 고급 프로그래밍을 가능하게 하며, 소유권 모델은 가비지 수집 없이 메모리 안전성을 보장합니다. 이러한 기능은 Rust가 대량의 데이터 세트를 효율적이고 안전하게 처리하는 데 특히 적합하게 만듭니다.
CSV 파싱을 위해 우리는 Rust의 csv 크레이트를 활용하여 CSV 데이터를 고성능으로 읽고 쓸 수 있었습니다. 우리는 이를 사용자 정의 데이터 매핑 논리와 결합하여 Blue의 데이터 구조와 원활하게 통합했습니다.
Rust의 학습 곡선은 가파르지만 관리 가능했습니다. 우리 팀은 이 과정에 대해 약 2주간 집중 학습을 했습니다.
개선 사항은 인상적이었습니다:
우리의 새로운 시스템은 이전 시스템이 15분에 처리할 수 있었던 동일한 양의 레코드를 약 30초 만에 처리할 수 있습니다.
웹 서버 및 데이터베이스 상호작용
Rust 구현의 웹 서버 구성 요소로 우리는 Rocket을 프레임워크로 선택했습니다. Rocket은 성능과 개발자 친화적인 기능의 조합으로 두드러졌습니다. 정적 타이핑과 컴파일 타임 검사 기능은 Rust의 안전 원칙과 잘 맞아 개발 과정에서 잠재적인 문제를 조기에 발견하는 데 도움을 줍니다.
데이터베이스 측면에서는 SQLx를 선택했습니다. 이 Rust용 비동기 SQL 라이브러리는 우리의 요구에 이상적인 여러 가지 이점을 제공합니다:
- 타입 안전 SQL: SQLx는 컴파일 타임에 체크된 쿼리로 원시 SQL을 작성할 수 있게 하여 성능을 희생하지 않고 타입 안전성을 보장합니다.
- 비동기 지원: 이는 Rocket 및 효율적이고 비차단적인 데이터베이스 작업의 필요성과 잘 맞습니다.
- 데이터베이스 독립적: 우리는 주로 AWS Aurora를 사용하지만, SQLx의 여러 데이터베이스에 대한 지원은 우리가 변경할 경우 미래에 유연성을 제공합니다.
배치 최적화
최적의 배치 구성을 찾기 위한 여정은 철저한 테스트와 신중한 분석의 과정이었습니다. 우리는 다양한 동시 트랜잭션 및 청크 크기의 조합으로 광범위한 벤치마크를 실행하며, 원시 속도뿐만 아니라 리소스 활용도와 시스템 안정성도 측정했습니다.
이 과정은 다양한 크기와 복잡성의 테스트 데이터 세트를 생성하여 실제 사용 패턴을 시뮬레이션하는 것을 포함했습니다. 그런 다음 이러한 데이터 세트를 시스템에 통과시켜 각 실행에 대해 동시 트랜잭션 수와 청크 크기를 조정했습니다.
결과를 분석한 결과, 500개의 레코드로 청크 크기를 설정한 5개의 동시 트랜잭션을 처리하는 것이 속도와 리소스 활용의 최상의 균형을 제공하는 것으로 나타났습니다. 이 구성은 높은 처리량을 유지하면서 데이터베이스를 압도하거나 과도한 메모리를 소비하지 않도록 합니다.
흥미롭게도, 5개 이상의 트랜잭션으로 동시성을 증가시키는 것은 상당한 성능 향상을 가져오지 않았으며 때때로 데이터베이스 경합을 증가시키기도 했습니다. 마찬가지로, 더 큰 청크 크기는 원시 속도를 개선했지만, 소규모 및 중간 규모의 가져오기/내보내기에서 더 높은 메모리 사용량과 긴 응답 시간을 초래했습니다.
이메일 링크를 통한 CSV 내보내기
우리 솔루션의 마지막 부분은 사용자에게 대형 내보내기 파일을 전달하는 문제를 해결합니다. 웹 앱에서 직접 다운로드를 제공하는 대신, 이는 타임아웃 문제와 서버 부하 증가를 초래할 수 있으므로, 이메일 다운로드 링크 시스템을 구현했습니다.
사용자가 대형 내보내기를 시작하면, 우리 시스템은 백그라운드에서 요청을 처리합니다. 완료되면, 연결을 열어두거나 파일을 웹 서버에 저장하는 대신, 파일을 안전한 임시 저장 위치에 업로드합니다. 그런 다음 고유하고 안전한 다운로드 링크를 생성하여 사용자에게 이메일로 전송합니다.
이 다운로드 링크는 2시간 동안 유효하며, 사용자 편의성과 정보 보안 간의 균형을 맞춥니다. 이 시간 프레임은 사용자가 데이터를 검색할 수 있는 충분한 기회를 제공하면서 민감한 정보가 무기한으로 접근 가능하지 않도록 보장합니다.
이 다운로드 링크의 보안은 우리의 설계에서 최우선 사항이었습니다. 각 링크는:
- 고유하고 무작위로 생성되어 추측하기 사실상 불가능합니다.
- 단 2시간 동안만 유효합니다.
- 전송 중 암호화되어 데이터가 다운로드될 때 안전성을 보장합니다.
이 접근 방식은 여러 가지 이점을 제공합니다:
- 대형 파일 다운로드를 직접 처리할 필요가 없으므로 웹 서버의 부하를 줄입니다.
- 특히 느린 인터넷 연결을 가진 사용자에게 사용자 경험을 개선합니다. 이들은 직접 다운로드에서 브라우저 타임아웃 문제에 직면할 수 있습니다.
- 일반적인 웹 타임아웃 한계를 초과할 수 있는 매우 대형 내보내기에 대해 더 신뢰할 수 있는 솔루션을 제공합니다.
이 기능에 대한 사용자 피드백은 압도적으로 긍정적이며, 많은 사용자들이 대량 데이터 내보내기를 관리하는 데 제공하는 유연성을 높이 평가하고 있습니다.
필터링된 데이터 내보내기
또 다른 명백한 개선 사항은 사용자가 프로젝트 보기에서 이미 필터링된 데이터만 내보낼 수 있도록 하는 것이었습니다. 즉, "우선순위"라는 활성 태그가 있을 경우, 이 태그가 있는 레코드만 CSV 내보내기에 포함됩니다. 이는 Excel에서 중요하지 않은 데이터를 필터링하는 데 소요되는 시간을 줄이고, 처리할 행 수를 줄이는 데도 도움이 됩니다.
앞으로의 계획
우리는 Rust 사용을 확장할 즉각적인 계획은 없지만, 이 프로젝트는 성능이 중요한 작업을 위한 이 기술의 잠재력을 보여주었습니다. 이는 향후 최적화 요구를 위한 도구 키트에 추가된 흥미로운 옵션입니다. 이 CSV 가져오기 및 내보내기 개편은 Blue의 확장성에 대한 약속과 완벽하게 일치합니다.
우리는 고객과 함께 성장하는 플랫폼을 제공하기 위해 헌신하고 있으며, 성능을 저하시키지 않으면서 그들의 확장되는 데이터 요구를 처리할 수 있도록 하고 있습니다.
Rust를 기술 스택에 도입하기로 한 결정은 가볍게 이루어진 것이 아닙니다. 이는 많은 엔지니어링 팀이 직면하는 중요한 질문을 제기했습니다: 언제 핵심 기술 스택을 벗어나는 것이 적절하며, 언제 익숙한 도구를 고수해야 할까요?
모든 상황에 맞는 정답은 없지만, Blue에서는 이러한 중요한 결정을 내리기 위한 프레임워크를 개발했습니다:
- 문제 우선 접근법: 우리는 항상 해결하려는 문제를 명확히 정의하는 것부터 시작합니다. 이 경우, 대량 데이터 세트에 대한 CSV 가져오기 및 내보내기의 성능을 극적으로 개선해야 했습니다.
- 기존 솔루션 소진: 핵심 스택 외부를 살펴보기 전에 기존 기술로 달성할 수 있는 것을 철저히 탐색합니다. 이는 종종 프로파일링, 최적화 및 익숙한 제약 내에서 접근 방식을 재고하는 것을 포함합니다.
- 잠재적 이익 정량화: 새로운 기술을 고려할 경우, 우리는 이점을 명확히 설명하고, 이상적으로는 정량화할 수 있어야 합니다. 우리의 CSV 프로젝트의 경우, 처리 속도에서 수량급 개선을 예측했습니다.
- 비용 평가: 새로운 기술을 도입하는 것은 단지 즉각적인 프로젝트에 관한 것이 아닙니다. 우리는 장기적인 비용을 고려합니다:
- 팀의 학습 곡선
- 지속적인 유지 관리 및 지원
- 배포 및 운영에서의 잠재적 복잡성
- 채용 및 팀 구성에 미치는 영향
- 제한 및 통합: 새로운 기술을 도입할 경우, 우리는 이를 시스템의 특정하고 잘 정의된 부분에 한정하려고 합니다. 또한 기존 스택과 통합하는 방법에 대한 명확한 계획이 있는지 확인합니다.
- 미래 대비: 이 기술 선택이 미래의 기회를 열어주는지, 아니면 우리를 궁지에 몰아넣을 수 있는지를 고려합니다.
새로운 기술을 자주 채택하는 주요 위험 중 하나는 우리가 *"기술 동물원"*에 빠지는 것입니다 - 애플리케이션의 서로 다른 부분이 서로 다른 언어 또는 프레임워크로 작성되어 유지 관리에 다양한 전문 기술이 필요한 단편화된 생태계입니다.
결론
이 프로젝트는 Blue의 엔지니어링 접근 방식을 잘 보여줍니다: 우리는 사용자에게 훨씬 더 나은 경험을 제공하기 위해 편안한 영역을 벗어나 새로운 기술을 채택하는 것을 두려워하지 않습니다.
CSV 가져오기 및 내보내기 프로세스를 재구상함으로써, 우리는 한 기업 고객의 긴급한 요구를 해결했을 뿐만 아니라 대량 데이터 세트를 처리하는 모든 사용자에게 경험을 개선했습니다.
우리가 프로젝트 관리 소프트웨어에서 가능한 것의 경계를 계속 확장함에 따라, 우리는 이러한 도전 과제를 해결하는 데 흥미를 느끼고 있습니다.
Blue를 지원하는 엔지니어링에 대한 더 많은 심층 분석을 기대해 주세요!