
대용량 트래픽 처리를 위한 쇼핑몰 DB 설계 전략
대용량 트래픽을 견디는 쇼핑몰 DB 설계 전략 3가지를 소개합니다. 읽기/쓰기 분리, 저장소 분리, 반정규화 전략을 통해 안정적인 서비스를 구축하는 방법을 알아보세요.
송찬영
CTO

안녕하세요. 풀링포레스트 CTO 송찬영입니다.
CTO로서 가장 등골이 서늘해지는 순간이 언제일까요? 서비스 장애 알림이 울릴 때도 무섭지만, 진짜 두려움은 '예상치 못한 성공'이 찾아왔을 때 느낍니다. 마케팅 팀이 야심 차게 준비한 타임 세일 이벤트가 대박이 났는데, 정작 시스템은 그 부하를 견디지 못해 뻗어버리는 상황 말입니다. 특히 쇼핑몰 제작 초기 단계에서 데이터베이스(DB) 설계를 안일하게 했다가, 트래픽이 몰리는 결정적인 순간에 발목을 잡히는 경우를 너무나 많이 봐왔습니다. 오늘은 쇼핑몰 제작 시 반드시 고려해야 할 대용량 트래픽 처리를 위한 DB 설계 전략에 대해, 제가 겪었던 시행착오를 바탕으로 이야기해 보려 합니다.

저 역시 과거에 이커머스 프로젝트를 리딩하면서 쓰라린 실패를 경험한 적이 있습니다. 당시 우리는 "일단 빠르게 런칭하자"는 목표 아래, 모든 기능을 하나의 거대한 모놀리식 DB에 때려 넣었습니다. 회원, 상품, 주문, 결제, 정산까지 모든 테이블이 서로 복잡하게 조인(Join)되어 있었죠. 초기에는 아무 문제가 없었습니다. 개발 속도도 빨랐고, 데이터 정합성을 맞추기도 쉬웠으니까요.
하지만 첫 대형 프로모션 날, 재앙이 시작되었습니다. 동시 접속자가 평소의 10배 이상 몰리자 DB CPU 사용률이 100%를 찍고 내려올 생각을 하지 않았습니다. 주문 버튼을 누르면 10초 뒤에야 응답이 오거나, 심지어 타임아웃 오류가 발생했습니다. 원인은 명확했습니다. 주문 트랜잭션이 발생하는 동안 상품 재고를 확인하는 락(Lock)이 걸리고, 그 와중에 정산 쿼리가 같은 테이블을 조회하면서 데드락(Deadlock)까지 발생한 것입니다. 단순히 서버 스펙을 올리는 스케일업(Scale-up)으로는 해결되지 않는, 구조적인 문제였습니다.
그날 밤새 팀원들과 장애 대응을 하며 뼈저리게 느꼈습니다. 쇼핑몰 제작은 단순히 기능을 구현하는 것이 아니라, 데이터의 흐름과 부하를 설계하는 과정이라는 것을요. 그때의 경험을 통해 얻은 핵심적인 설계 전략은 크게 세 가지입니다.
첫째, 읽기(Read)와 쓰기(Write)의 분리입니다. 대부분의 쇼핑몰 트래픽은 쓰기보다 읽기가 압도적으로 많습니다. 상품을 조회하고 상세 페이지를 보는 횟수가 실제로 주문을 넣는 횟수보다 훨씬 많으니까요. 따라서 우리는 CQRS(Command Query Responsibility Segregation) 패턴을 도입해야 합니다. 메인 DB(Master)는 주문, 결제, 회원 가입 같은 쓰기 작업만 전담하게 하고, 여러 개의 복제 DB(Slave/Replica)를 두어 조회 트래픽을 분산시켜야 합니다. 이렇게 하면 이벤트 상황에서 수만 명의 사용자가 동시에 상품을 조회해도, 주문을 처리하는 메인 DB에는 부하가 가지 않습니다.
둘째, 데이터의 성격에 따른 저장소 분리입니다. 모든 데이터를 RDBMS(관계형 데이터베이스)에 넣을 필요는 없습니다. 예를 들어, '장바구니'나 '최근 본 상품' 같은 데이터는 휘발성이 강하고 입출력이 매우 빈번합니다. 이런 데이터까지 메인 DB에 저장하면 불필요한 IO 부하를 일으킵니다. 저희는 Redis 같은 인메모리 DB를 활용해 장바구니 데이터를 처리함으로써 응답 속도를 획기적으로 개선했습니다. 또한, 상품 검색을 위해 복잡한 LIKE 쿼리를 RDBMS에 날리는 대신, ElasticSearch 같은 검색 전용 엔진을 도입하여 검색 성능과 DB 부하를 동시에 해결했습니다.

셋째, 정규화에 대한 집착 버리기(반정규화)입니다. 교과서적인 DB 설계에서는 중복을 피하기 위해 정규화를 강조합니다. 하지만 대용량 트래픽 환경에서는 조인 연산 하나가 치명적일 수 있습니다. 예를 들어, 주문 내역 조회 시 매번 회원 테이블과 상품 테이블을 조인해서 가져오는 것은 비효율적입니다. 차라리 주문 테이블 안에 '주문 당시의 상품명', '주문 당시의 회원 등급' 등을 중복해서 저장해두는 반정규화 전략이 조회 성능을 높이는 데 훨씬 유리합니다. 데이터의 무결성보다는 '성능'과 '가용성'이 생존에 직결되는 순간이 오기 때문입니다.
물론 이 모든 전략을 처음부터 완벽하게 적용할 필요는 없습니다. 스타트업 초기에는 빠른 개발 속도가 더 중요할 수 있으니까요. 하지만 쇼핑몰제작 단계에서부터 데이터가 커졌을 때 어떻게 쪼갤 것인지(Sharding), 어떤 데이터를 캐싱할 것인지에 대한 청사진은 가지고 있어야 합니다. 나중에 뜯어고치려면 10배 이상의 비용이 들기 때문입니다.
풀링포레스트에서도 우리는 늘 이 균형점을 고민합니다. 과도한 오버 엔지니어링은 경계하되, 확장이 필요한 시점에는 지체 없이 구조를 변경할 수 있도록 유연한 설계를 지향합니다.
오늘 이야기가 막연하게 "DB는 성능이 좋아야 한다"라고만 생각했던 분들에게 구체적인 가이드가 되었으면 합니다. 기술적인 화려함보다 중요한 것은, 비즈니스의 성장을 기술이 막지 않도록 미리 길을 터주는 것입니다. 그것이 바로 우리 엔지니어들의 역할이자 존재 이유가 아닐까요? 여러분의 서비스가 트래픽 폭주로 즐거운 비명을 지르는 그날, 단단한 DB 설계가 든든한 버팀목이 되어주길 바랍니다.


