1) 기술적 도전 경험

1-1. 대형 프로모션 트래픽 대응

– Redis 캐싱 설계 + 운영 안정화 주도

문제 상황

페이코 오더에서 대형 프랜차이즈 프로모션을 앞두고, 매장 전체 메뉴 조회 API와 매장 상세 조회 API에서 트래픽 급증이 예상되었습니다. 이전 연도 동일한 프로모션에서는 DB CPU 사용률이 급격히 상승하며 DB가 마비되어 서비스 장애로 이어졌던 이력이 있었기 때문에, 이번 프로모션에서는 동일한 문제가 재발하지 않도록 사전 대응이 필수적인 상황이었습니다. 특히 이벤트 특성상 메뉴 조회 지연은 곧 주문·결제 실패로 이어질 수 있어, 백엔드 구조 전반의 안정성이 요구되었습니다.

관측 및 진단

과거 장애 사례를 기반으로 DB팀과 협업해, 당시 DB CPU를 가장 많이 점유했던 쿼리를 재분석했습니다. 그 결과 CPU 사용량 TOP 1, 2가 모두 매장 전체 메뉴 조회 쿼리와 매장 상세 조회 쿼리였으며, 두 쿼리 모두 레거시 구조로 유지되고 있음을 확인했습니다.

해당 쿼리는 하나의 쿼리에서 메뉴, 옵션, 품절 여부, 매장 이미지, 해시태그 등 모든 데이터를 조회하도록 설계되어 있었고, 다수의 LEFT JOIN과 UNION이 포함된 복잡한 형태였습니다. 이 구조는 트래픽 증가 시 DB 부하를 선형적으로 증폭시키는 근본 원인이라고 판단했습니다.

접근 방법

저는 단순히 캐싱을 적용하기보다, DB 병목의 근본 원인을 먼저 제거하는 것이 우선이라고 판단해 쿼리 구조 자체를 재설계했습니다.

기존 매장 전체 메뉴 조회 쿼리는 하나의 쿼리에서 메뉴, 옵션, 품절 여부, 매장 이미지, 해시태그 등 여러 책임을 동시에 수행하고 있었고, 이로 인해 다수의 LEFT JOINUNION이 포함된 구조였습니다. 저는 이를 기능 단위로 분리해 각 쿼리가 명확한 역할만 수행하도록 정리하고, 조회 조건에 맞는 인덱스를 적용해 불필요한 조인 비용을 제거했습니다. 그 결과 트래픽 증가 시에도 DB 부하가 급격히 증가하지 않는 구조로 개선할 수 있었습니다.

이후 메뉴 조회 구조를 브랜드 공통 메뉴매장별 설정 메뉴로 분리했습니다. 브랜드 공통 메뉴는 변경 빈도가 낮고 조회 빈도가 높아 캐싱 대상으로 선정했고, 매장별 설정 메뉴는 DB 조회를 유지했습니다.

모든 데이터를 무작정 캐시할 경우 Redis 메모리 사용량이 급격히 증가해 또 다른 운영 리스크를 만들 수 있다고 판단해, “무엇을 캐시할 것인가”를 먼저 명확히 정의했습니다.