-
Shopify가 Redis 재고 예약을 MySQL로 옮긴 이유IT & AI 2026. 5. 30. 12:17
Shopify가 Redis 재고 예약을 MySQL로 옮긴 이유

AI 뉴스 썸네일 Shopify가 결제 중 재고를 잠깐 묶어두는 시스템을 Redis에서 MySQL로 옮겼어요. 단순히 저장소를 바꾼 이야기가 아니에요. 오버셀을 막는 핵심 경로에서 데이터베이스 잠금, 트랜잭션, 커넥션 점유까지 다시 본 사례예요.
핵심 요약
구분 핵심 왜 볼 만한가요 인프라 Redis 기반 예약을 MySQL 8 기반 구조로 바꿨어요 별도 캐시 시스템 없이도 고성능 예약 처리를 만들 수 있다는 사례예요 데이터 모델 수량 칼럼 대신 판매 가능한 단위마다 1개 행을 두는 방식이에요 `SKIP LOCKED`를 제대로 쓰려면 스키마부터 다르게 잡아야 한다는 점을 보여줘요 운영 교훈 병목은 쿼리 자체보다 커넥션 점유 시간에 가까웠어요 성능 문제를 볼 때 DB CPU만 보면 놓치는 지점이 있다는 얘기예요 1. Shopify가 바꾼 건 Redis가 아니라 예약 모델이에요
온라인 쇼핑몰에서 결제 버튼을 누른 뒤 실제 결제가 끝나기 전까지는 재고를 잠깐 묶어둬야 해요. 이 처리가 틀어지면 마지막 1개 상품을 두 명이 사거나, 반대로 살 수 있는 상품을 품절로 보여줄 수 있어요. Shopify는 이 예약 처리를 오랫동안 Redis로 운영했지만, 재고 원장과 예약 상태가 서로 다른 시스템에 나뉘어 있다는 문제가 있었어요. 결제 완료 뒤 MySQL 원장을 바꾸고 Redis 예약을 정리하는 과정을 하나의 원자적 트랜잭션으로 묶기 어려웠다는 점이 핵심이에요. 1
Shopify가 택한 방향은 예약도 MySQL 안으로 넣는 방식이에요. 원장과 예약을 같은 데이터베이스에서 처리하면 reserve와 claim을 ACID 트랜잭션 안에서 다룰 수 있어요. Redis가 느려서 버린 사례라기보다, 정합성 경계를 줄이기 위해 시스템을 단순하게 만든 사례에 가까워요. 원문도 이 점을 Redis 대체 자체보다 데이터 모델과 트랜잭션 경계의 변화로 설명해요. 2
2. `SKIP LOCKED`는 스키마를 바꿔야 힘을 내요
처음 떠올리기 쉬운 모델은 상품별로 `quantity` 칼럼 하나를 두는 방식이에요. 하지만 인기 상품에 주문이 몰리면 같은 행을 여러 트랜잭션이 동시에 건드리게 돼요. Shopify는 이 구조 대신 판매 가능한 단위마다 1개 행을 두는 모델을 썼어요. 재고가 10개면 10개 행이 있고, 3개를 예약할 때는 트랜잭션 안에서 3개 행을 골라 옮기는 식이에요. 2
여기서 MySQL 8의 `SKIP LOCKED`가 의미를 가져요. 다른 트랜잭션이 이미 잠근 행을 기다리지 않고 건너뛰면, 예약 요청들이 같은 행 앞에서 줄을 서지 않아도 돼요. 다만 모든 재고를 행으로 풀어버리면 행 수가 너무 커져요. Shopify는 아이템과 위치 조합별로 가용 행 풀을 최대 1,000개로 제한하고, 별도 보충 프로세스로 풀을 채우는 방식을 택했어요. 이 제한이 없으면 `SKIP LOCKED`도 대규모 재고에서는 느려질 수 있어요.
3. 실제 병목은 예약 쿼리보다 커넥션 점유였어요
흥미로운 대목은 성능 튜닝의 결론이에요. Shopify는 복합 기본 키, `READ COMMITTED` 격리 수준, 일관된 잠금 순서, `UNION ALL` 배치 처리 같은 DB 최적화를 조합했어요. 그런데 최종 병목은 예약 쿼리가 DB CPU를 얼마나 쓰느냐보다 체크아웃 경로 전체에서 커넥션을 얼마나 오래 붙잡고 있느냐에 가까웠어요. 원문은 이 지점을 계측한 뒤 DB 읽기와 트랜잭션 구간을 줄이는 방향으로 개선했다고 설명해요. 2
이건 실무자에게 꽤 익숙한 함정이에요. 느린 쿼리 하나를 찾는 데 집중하다 보면, 실제로는 커넥션 풀이 막히고 요청 전체가 밀리는 상황을 놓칠 수 있어요. Shopify 사례를 보면 데이터베이스 안의 락뿐 아니라 애플리케이션이 커넥션을 붙잡는 시간도 같이 중요해요.
4. 블랙프라이데이 트래픽으로 검증한 설계예요
Shopify는 2025년 블랙프라이데이 피크에 분당 510만 달러 매출을 처리했다고 밝혔어요. 이 기간에도 writer CPU는 50% 미만, reader CPU는 16% 미만으로 유지됐다고 해요. 숫자만 보면 MySQL이 Redis보다 항상 낫다는 결론으로 읽기 쉬워요. 하지만 더 정확한 결론은 달라요. 데이터 모델, 잠금 순서, 격리 수준, 커넥션 사용 방식이 맞물리면 관계형 데이터베이스도 초고빈도 예약 경로를 감당할 수 있다는 쪽이에요. 2
이 사례가 좋은 이유는 성공담만 늘어놓지 않기 때문이에요. 단일 수량 행 모델은 경합 때문에 어렵고, 단위별 행 모델은 행 수 폭증을 관리해야 해요. Redis를 MySQL로 옮기는 결정도 모든 팀에 맞는 답은 아니에요. 그래도 원장과 예약 상태를 한 트랜잭션 안에 두고 싶은 팀이라면, MySQL 8의 `SKIP LOCKED`를 어떻게 써야 하는지 꽤 구체적인 참고가 돼요.
왜 중요한가요
이 글은 “캐시보다 DB가 낫다”라는 단순한 이야기가 아니에요. 대규모 서비스에서 정합성과 처리량을 동시에 맞추려면 저장소 선택보다 경계 설계가 먼저라는 점을 보여줘요. Redis와 MySQL 중 무엇이 빠른지보다, 어떤 데이터가 같은 트랜잭션 안에 있어야 하는지부터 확인해 볼 만해요. 2
백엔드 개발자에게는 `SKIP LOCKED`를 실전에서 쓰는 방식이 참고돼요. 행을 어떻게 나눌지, 풀 크기를 어디서 자를지, 잠금 순서를 어떻게 맞출지까지 같이 확인할 수 있어요. 운영자에게는 병목을 보는 관점이 남아요. 쿼리 시간, DB CPU, 커넥션 점유 시간을 따로 보지 않으면 진짜 원인을 늦게 찾을 수 있어요. 1
참고 자료
- Shopify, 재고 예약 시스템을 Redis에서 MySQL로 교체 — GeekNews
- We replaced Redis with MySQL for inventory reservations and it scaled — Shopify Engineering
'IT & AI' 카테고리의 다른 글
차가 모으는 내 정보, 보험료까지 갈 수 있어요 (0) 2026.05.30 AI가 일자리를 줄이면 경제는 어디서 수요를 얻을까요 (0) 2026.05.30 컨테이너 레지스트리를 API로 이해해야 하는 이유 (0) 2026.05.30 SQLite가 AI 코드를 받지 않겠다고 못 박은 이유 (0) 2026.05.30 오픈소스 리더가 인터넷을 끊은 이유 (0) 2026.05.30