fos-blog/study
01 / 홈02 / 카테고리
01 / 홈02 / 카테고리

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • langgraph 페이지로 이동
    • agents.md
    • BMAD Method — AI 에이전트로 애자일 개발하는 방법론
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code를 5주 더 쓴 결과 — 스킬·CLAUDE.md를 키워가는 방식
    • Claude Code를 11일 동안 쓴 결과 — 데이터로 본 나의 사용 패턴
    • Claude Code 멀티 에이전트 — Teams
    • AI 에이전트와 디자인의 새 컨벤션 — DESIGN.md, Google Stitch, Claude Design
    • 하네스 엔지니어링 실전 — 4인 에이전트 팀으로 코딩 파이프라인 구축하기
    • 하네스 엔지니어링 — 오래 실행되는 AI 에이전트를 위한 설계
    • 멀티모달 LLM (Multimodal Large Language Model)
    • AI 에이전트와 함께 MVP 만들기 — dooray-cli 사례
  • ai 페이지로 이동
    • agent 페이지로 이동
  • algorithm 페이지로 이동
    • live-coding 페이지로 이동
    • 분산 계산을 위한 알고리즘
  • architecture 페이지로 이동
    • [초안] 시니어 백엔드를 위한 API 설계 실전 스터디 팩 — REST · 멱등성 · 페이지네이션 · 버전 전략
    • [초안] API Versioning과 Backward Compatibility: 시니어 백엔드 관점 정리
    • 캐시 설계 전략 총정리
    • [초안] CJ푸드빌 커머스/F&B 도메인 설계 면접 대비 — 슬롯 경험을 주문·결제·쿠폰·매장 상태 설계로 번역하기
    • [초안] 커머스 Spring 서비스에 Clean/Hexagonal Architecture를 실용적으로 적용하기
    • [초안] 커머스 주문 상태와 데이터 정합성 기본기 — CJ푸드빌 면접 대비
    • [초안] 쿠폰/프로모션 동시성과 정합성 기본기 — 선착순·중복 사용 방지·발급/사용/복구
    • [초안] DDD와 도메인 모델링: 시니어 백엔드 관점의 전술/전략 패턴 실전 가이드
    • [초안] Decorator & Chain of Responsibility — 행동을 체인으로 조립하는 두 가지 방식
    • 디자인 패턴
    • [초안] 분산 아키텍처 완전 정복: Java 백엔드 시니어 인터뷰 대비 실전 가이드
    • [초안] 분산 트랜잭션과 Outbox 패턴 — 왜 2PC를 피하고 어떻게 대신할 것인가
    • 분산 트랜잭션
    • [초안] e-Commerce 주문·결제 도메인 모델링: 상태머신, 멱등성, Outbox/Saga 실전 정리
    • [초안] F&B 쿠폰·프로모션·멤버십·포인트 설계
    • [초안] F&B · e-Commerce 디지털 채널 도메인 한 장 정리 — CJ푸드빌 디지털 채널 백엔드 면접 대비
    • [초안] F&B 주문/매장/픽업 상태머신 설계 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] F&B 이커머스 결제·환불·정산 운영 가이드
    • [초안] Hexagonal / Clean Architecture를 Spring 백엔드에 적용하기
    • [초안] 대규모 커머스 트래픽 처리 패턴 — 1,600만 고객과 올영세일을 버티는 설계
    • [초안] 레거시 JSP/jQuery 화면과 신규 API가 공존하는 백엔드 운영 전략
    • [초안] MSA 서비스 간 통신: Redis [Cache-Aside](../database/redis/cache-aside.md) × Kafka 이벤트 하이브리드 설계
    • [초안] Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • [초안] Outbox / Inbox Pattern 심화 — 분산 메시징의 정합성 문제를 DB 트랜잭션으로 풀어내기
    • [초안] 결제 도메인 멱등성과 트랜잭션 재시도 기본기
    • [초안] 시니어 백엔드를 위한 Resilience 패턴 실전 가이드 — Timeout, Retry, Circuit Breaker, Bulkhead, Backpressure
    • [초안] REST API 버저닝과 모바일 앱 하위 호환성 — CJ푸드빌 디지털 채널 백엔드 관점
    • [초안] Strategy Pattern — 분기문을 없애는 설계, 시니어 백엔드 인터뷰 핵심 패턴
    • [초안] 시니어 백엔드를 위한 시스템 설계 입문 스터디 팩
    • [초안] 템플릿 메서드 패턴 - 백엔드 처리 골격을 강제하는 가장 오래되고 가장 위험한 패턴
    • [초안] 대규모 트래픽 중 무중단 마이그레이션 — Feature Flag + Shadow Mode 실전
  • database 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • redis 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • [초안] JPA N+1과 커머스 조회 모델: 주문/메뉴/쿠폰 도메인에서 살아남기
    • [초안] MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • [초안] MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • observability 페이지로 이동
    • [초안] 커머스/F&B 채널 장애 첫 5분과 관측성 기본기
    • Envoy Proxy
    • [초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리
    • Graceful Shutdown
  • finance 페이지로 이동
    • industry-cycle 페이지로 이동
    • investing 페이지로 이동
    • stock-notes 페이지로 이동
  • http 페이지로 이동
    • HTTP Connection Pool
  • interview 페이지로 이동
    • [초안] AI 서비스 팀 경험 기반 시니어 백엔드 면접 질문 뱅크 — Spring Batch RAG / gRPC graceful shutdown / 전략 패턴 / 12일 AI 웹툰 MVP
    • [초안] CJ푸드빌 디지털 채널 Back-end 개발자 직무 분석
    • [초안] CJ푸드빌 디지털 채널 Back-end 면접 답변집 — 슬롯 도메인 경험을 커머스/F&B 설계로 번역하기
    • [초안] F&B / e-Commerce 운영 모니터링과 장애 대응 인터뷰 정리
    • Observability — 면접 답변 프레임
    • [초안] 시니어 Java 백엔드 면접 마스터 플레이북 — 김병태
    • [초안] NSC 슬롯팀 경험 기반 질문 은행 — 도메인 모델링·동시성·성능·AI 협업
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • [초안] Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • [초안] JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • npm vs pnpm — 어떤 기준으로 선택했나
    • `setImmediate()`
  • kafka 페이지로 이동
    • [초안] Kafka 기본 개념 — 토픽, 파티션, 오프셋, 복제
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • [초안] Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • 메시지 전송 신뢰성
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • network 페이지로 이동
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • rabbitmq 페이지로 이동
    • [초안] RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • [초안] RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • security 페이지로 이동
    • [초안] 시니어 백엔드를 위한 보안 / 인증 스터디 팩 — Spring Security, JWT, OAuth2, OWASP Top 10
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • testing 페이지로 이동
    • [초안] 시니어 Java 백엔드를 위한 테스트 전략 완전 정리 — 피라미드부터 TestContainers, 마이크로벤치, Contract까지
  • travel 페이지로 이동
    • 오사카 3박 4일 일정표: 우메다 쇼핑, USJ, 난바·도톤보리, 오사카성
  • web 페이지로 이동
    • [초안] HTTP / Cookie / Session / Token 인증 기본기 — 레거시 JSP와 모바일 API가 공존하는 백엔드 관점
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/devops/[초안] F&B / e-Commerce 운영…
devops

[초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리

F&B 디지털 채널 백엔드는 일반 커머스보다 운영 변수가 더 많다. 매장 POS, 배달 외부 채널, PG, 멤버십, 쿠폰, 재고, 알림이 한 트랜잭션 안에서 같이 움직이고, 점심·저녁 피크타임이 하루에 두 번 분명하게 찍힌다. 이 시간대에 한 쪽이 어긋나면 주문은 받았는데 매장에 안 떨어졌거나, 결제는 됐는데 쿠폰이 안 빠졌거나, 재고가 0인데 주문이 들어...

2026.05.07·14 min read·17 views

왜 이 주제가 중요한가

F&B 디지털 채널 백엔드는 일반 커머스보다 운영 변수가 더 많다. 매장 POS, 배달 외부 채널, PG, 멤버십, 쿠폰, 재고, 알림이 한 트랜잭션 안에서 같이 움직이고, 점심·저녁 피크타임이 하루에 두 번 분명하게 찍힌다. 이 시간대에 한 쪽이 어긋나면 주문은 받았는데 매장에 안 떨어졌거나, 결제는 됐는데 쿠폰이 안 빠졌거나, 재고가 0인데 주문이 들어가 있는 식의 운영 사고가 즉시 CS로 전환된다. 그래서 F&B 백엔드의 실력은 새 기능을 만드는 능력보다 "장애 났을 때 5분 안에 무엇을 보고, 무엇을 끄고, 무엇을 복구하느냐"에서 더 분명하게 갈린다.

면접 관점에서도 마찬가지다. CJ푸드빌처럼 빕스·뚜레쥬르·계절밥상 같은 다채널 브랜드를 운영하는 조직은 "안정 운영"을 직무 기술서의 앞쪽에 둔다. 코드 스타일이나 알고리즘보다 "피크타임에 503 어떻게 줄였나", "PG 장애 때 어떻게 대응했나", "재고 동기화 깨졌을 때 어떻게 회복했나" 같은 운영형 질문이 시니어 백엔드 평가의 본진이 된다. 이 글은 그 본진을 정면으로 다룬다.

핵심 개념: 운영형 백엔드가 모니터링을 보는 방식

운영 장애를 다룰 때 가장 먼저 정렬해야 할 개념은 "관측은 3층 구조"라는 사실이다.

  1. 메트릭(metric) — 숫자로 집계되는 시계열. RPS, 5xx 비율, p95 latency, JVM heap, DB connection pool 사용률, Redis hit rate, Kafka consumer lag. 알람은 거의 항상 메트릭에서 발화된다.
  2. 로그(log) — 사람이 읽는 텍스트. 한 줄 한 줄이 사건이다. WARN/ERROR, stack trace, 외부 응답 코드. 알람이 울린 뒤 원인을 좁히는 첫 번째 단서.
  3. 트레이스(trace) — 한 요청이 서비스 A → B → C → DB → PG 까지 어떻게 흘렀는지 보여주는 인과 그래프. traceId로 묶인다. "왜 느린지", "어디서 죽었는지"를 가장 빠르게 답해준다.

운영 사고를 잘 다루는 백엔드 엔지니어는 이 3층을 항상 같은 순서로 쓴다. 메트릭으로 "어디가 아픈가"를 잡고, 트레이스로 "어떤 흐름이 아픈가"를 좁히고, 로그로 "왜 아픈가"를 본다. 신입 시절 흔히 하는 실수가 알람 받자마자 로그부터 grep 하는 것인데, 트래픽이 큰 시스템에서는 로그 양이 너무 많아 인과를 잃는다.

여기에 운영 백엔드가 추가로 들고 있어야 할 개념이 두 개 더 있다.

  • SLI / SLO / Error Budget — "주문 API 가용성 99.9%"처럼 사용자 체감 기준으로 정의된 목표. 알람 임계치는 감(感)이 아니라 SLO에서 역산해야 한다.
  • 블래스트 레이디어스(blast radius) — 어떤 컴포넌트가 죽었을 때 영향이 어디까지 번지는가. F&B 도메인에서는 "결제가 죽으면 주문이 같이 죽는가, 주문은 살아 있는가"가 사실상 설계의 분기점이다.

F&B / e-Commerce 운영에서 자주 터지는 9가지 시나리오

1) 피크타임 트래픽 — 점심/저녁 두 번의 산

평일 11:30–13:00, 17:30–20:00이 거의 모든 F&B 디지털 채널의 1차 피크다. 평소 RPS의 3~6배까지 뛴다. 이 시간대에 가장 먼저 깨지는 자원 순서는 대체로 정해져 있다.

  1. WAS 스레드 풀(Tomcat) — 외부 의존성이 느려지면 스레드가 묶여 큐가 쌓인다.
  2. DB connection pool(HikariCP) — 트랜잭션 길어지면 풀이 마른다.
  3. Redis — 캐시 미스 폭주, 또는 hot key.
  4. PG/외부 API — 우리 책임은 아니지만 우리 latency로 환산된다.

피크타임 대비의 핵심은 "용량을 늘리는 것"이 아니라 "느려졌을 때 죽지 않게 하는 것"이다. 즉, 타임아웃, 서킷 브레이커, 백프레셔, 큐잉이 갖춰져야 한다. 단순 스케일 아웃만 해서 피크를 넘기려는 설계는 비용도 비싸고, 외부 의존성이 느려지는 순간 그대로 무너진다.

2) 이벤트 / 쿠폰 오픈 — 인위적으로 만든 스파이크

쿠폰이나 한정 메뉴 오픈은 시간 0초 기준으로 트래픽이 수직 상승한다. 이 패턴은 일반 피크타임과 달리 "공정성" 요구가 추가된다. 같은 1초 안에 들어온 사용자 중 누구에게 쿠폰을 줄지가 비즈니스 이슈가 된다.

운영에서 자주 터지는 실패 패턴:

  • 쿠폰 카운터를 RDB UPDATE coupon SET remain = remain - 1로 처리해 row lock 경합 폭주.
  • Redis DECR로 옮겼지만 발급 후 영속화 실패 시 보상 트랜잭션이 없어 "발급은 됐는데 DB엔 없음" 상태.
  • 동일 사용자가 동시에 여러 탭에서 누르는 케이스를 idempotency key로 막지 않아 중복 발급.

대응 원칙은 셋이다. Redis로 카운터를 빠르게 깎고, 발급 이력은 idempotency key로 멱등하게 적재하고, 영속화 실패는 비동기 보상 큐로 흘린다.

3) 매장 POS 연동 장애 — "주문은 됐는데 매장이 모름"

F&B 디지털 채널 특유의 사고 유형이다. 사용자 입장에선 결제까지 끝났는데 매장 화면에는 주문이 안 떠 있다. 원인은 보통 다음 셋 중 하나다.

  • 매장 단말 네트워크 끊김 (매장 측 사유).
  • POS 연동 API가 동기 호출로 묶여 있어 타임아웃 발생 후 우리 트랜잭션 롤백, 사용자는 결제 완료 화면을 본 상태.
  • 메시지 큐(Kafka)에는 들어갔으나 매장 consumer가 lag.

설계 원칙은 "주문 확정과 매장 송신을 같은 트랜잭션에 묶지 않는다"이다. 주문 확정 → outbox에 매장 송신 메시지 적재 → 별도 publisher가 Kafka로 송신 → 매장 단말 consumer가 ack. 실패 시 재시도와 사람이 볼 수 있는 운영 대시보드(미송신 주문 카운트)가 필수다.

4) PG 장애 — 가장 자주, 가장 시끄럽게 터진다

PG는 우리가 통제할 수 없고, 1년에 몇 번은 반드시 흔들린다. 백엔드 관점의 방어선은 다음과 같다.

  • PG 호출에 명확한 connect/read timeout (보통 connect 1~2s, read 5~10s).
  • 동일 거래에 대한 재시도는 idempotency key 필수. 그렇지 않으면 이중 결제가 난다.
  • 결제 결과 통보(webhook)와 우리 측 결제 상태 폴링을 둘 다 갖춘다. 한쪽이 막혀도 다른 쪽으로 종결된다.
  • "결제 진행 중" 상태를 명시적으로 둔다. NULL/없음으로 두면 운영 중 추적이 안 된다.

PG 장애 시 가장 빠른 완화는 보통 "결제 수단 일부 차단"이다. 카드사 A만 문제라면 카드사 A 결제만 막고 나머지로 우회시키는 게 전체 서비스 다운보다 낫다. 이게 가능하려면 PG/카드사 단위로 feature flag가 분리돼 있어야 한다.

5) 알림 장애 — 사용자가 가장 먼저 체감하는 결함

주문 완료/배달 출발/픽업 준비 완료 같은 알림이 안 가면 CS가 즉시 폭증한다. 알림은 본질적으로 비동기여서 모니터링 사각지대가 되기 쉽다. 운영용 지표로 반드시 갖춰야 할 것:

  • 알림 발송 성공률 (provider 단위로 분리).
  • 알림 발송 큐 lag.
  • 알림 미수신 클레임 CS 건수와의 상관 그래프.

자주 하는 실수는 알림 실패를 단순 WARN 로그만 남기고 retry queue를 안 두는 것이다. 푸시 provider는 5xx가 흔하다. retry/backoff/DLQ가 기본 세트다.

6) 재고 / 품절 동기화 지연 — "주문 받았는데 만들 게 없음"

F&B는 재고 단위가 일반 커머스와 다르다. "원두 떨어짐"이 SKU 단위 품절로 즉시 환산되지 않고 매장 운영자가 수동 토글하는 경우가 많다. 이 토글이 카탈로그 캐시에 늦게 반영되면 "주문은 들어왔지만 매장에서 못 만든다"는 운영 사고가 난다.

대응은 두 갈래다.

  • 카탈로그 캐시 TTL을 짧게(예: 30~60초) 두고, 매장 토글 시점에 명시적 invalidate 이벤트를 발행.
  • 주문 시점에 "최종 가용성 확인" 단계를 둔다. 캐시 기반 노출과 별개로, 주문 확정 직전에 source of truth를 한 번 더 본다.

7) 캐시 불일치 — 가장 추적하기 어려운 운영 사고

캐시는 성능을 위해 도입하지만, 정합성이 깨졌을 때 디버깅이 가장 어렵다. F&B에서 자주 보는 패턴은 다음과 같다.

  • 가격이 바뀌었는데 일부 인스턴스 로컬 캐시가 안 갱신돼 같은 메뉴를 다른 가격으로 보여줌.
  • 매장 휴무 처리 직후 일부 사용자에게 여전히 영업 중으로 보임.
  • 카탈로그 다중 키 갱신 중간에 일관성 깨짐(가격은 새 값, 옵션은 옛 값).

원칙은 세 가지다. TTL을 너무 길게 두지 않는다, 무효화는 단일 이벤트로 묶는다, 마지막 보루로 짧은 주기의 강제 리프레시 잡을 둔다. "캐시 정합성 문제는 절대 안 일어나게 만든다"는 비현실적이고, "일어나도 N분 안에 자동 수렴한다"가 현실적인 목표다.

8) 배치 실패 — 새벽에 조용히 무너지는 영역

정산, 통계, 데이터 동기화, 외부 채널 메뉴 업로드 같은 배치는 새벽에 돈다. 실패하면 다음 날 오전이 돼야 인지된다. 운영에서 필요한 최소 장치:

  • 배치별 마지막 성공 시각 메트릭.
  • 마지막 성공 이후 N시간 넘으면 알람.
  • idempotent 재실행 가능한 구조(이미 처리된 행은 skip).
  • 부분 실패 시 전체 롤백이 아니라 실패 row만 격리해 사람 검수 큐로 보낸다.

9) CS 증가 — 운영 사고의 후행 지표이자 선행 지표

CS 인입량은 보통 사고의 후행 지표지만, 알람보다 빠르게 움직이는 경우도 있다. 알람 임계치가 보수적이거나, 사용자 체감 영역(예: 앱 특정 화면 렌더링 오류)이 서버 메트릭에 안 잡히는 경우다. 그래서 운영팀에서 들어오는 CS 키워드(예: "결제 실패", "쿠폰 안 들어옴")를 시간 단위로 집계해 대시보드에 띄우는 게 의외로 효과적이다.

핵심 지표·알림 기준·대시보드

반드시 잡아야 할 SLI

도메인SLI 예시SLO 예시
주문 API성공률, p95 latency99.9% / 500ms
결제 콜백성공률99.95%
매장 송신30초 내 도달률99.5%
카탈로그 캐시hit rate95% 이상
알림 발송성공률 (provider별)99%
배치마지막 성공 이후 경과 시간< 26h

알림 임계치 설계 원칙

  • "절대값 1개"가 아니라 "기간 + 비율" 조합으로 잡는다. 예: 5분 동안 5xx 비율 1% 초과.
  • 2단계 알람을 둔다. WARN(보고만)과 PAGE(새벽에도 깨움)를 분리한다.
  • 외부 의존성(PG, 알림 provider) 알람은 우리 SLO와 분리해서 본다. 우리가 못 고쳐도 영향은 봐야 한다.

운영 대시보드 기본 구성

  • 상단: 주문 RPS, 주문 성공률, 결제 성공률 (한 화면에서 분명하게 보임).
  • 중단: 외부 의존성별 latency·error율(PG, POS, 알림, 배달채널).
  • 하단: 인프라(WAS thread, DB pool, Redis hit, Kafka lag).
  • 별도 탭: 배치 마지막 성공 시각, 미송신 주문 큐 길이, DLQ 길이.

로그·traceId 설계

운영형 백엔드에서 traceId는 사실상 1순위 시민이다. 원칙:

  • 인입 지점(API Gateway 또는 첫 컨트롤러)에서 traceId 생성 또는 수신.
  • 이후 모든 외부 호출(HTTP, Kafka produce, DB는 선택)에 헤더로 전파.
  • 로그 포맷에 traceId 필드를 고정 위치로 둔다.
  • 비동기 큐로 넘길 때 메시지 헤더에 traceId를 실어 보낸다. 이게 없으면 비동기 구간에서 인과가 끊긴다.

지원자의 traceId 재전송 경험은 정확히 이 지점에 닿는다. "동기 호출에서만 traceId가 살아 있고 Kafka로 넘어가는 순간 끊겼다 → 메시지 헤더로 명시적으로 실어 보내 비동기 구간까지 같은 traceId로 추적 가능하게 만들었다" 같은 식의 서술이 면접에서 강한 운영 신호가 된다.

로그 레벨 운용도 같이 정리해 둔다.

  • ERROR — 사람이 봐야 한다. 알람 후보.
  • WARN — 자동 복구는 됐지만 빈도 늘면 위험.
  • INFO — 비즈니스 이벤트 (주문 확정, 결제 승인 등) 단위로만.
  • DEBUG — 운영 환경에선 끔. 필요 시 특정 traceId만 샘플링.

장애 대응 첫 5분 — 운영 백엔드의 코어 루프

알람이 울렸을 때 행동 순서를 머리에 박혀 있게 만든다.

  1. 0~30초: 영향 범위 파악. 어느 SLI가 깨졌는가. 사용자 영향이 있는가, 내부 시스템만의 문제인가.
  2. 30초~1분: 최근 변경 확인. 최근 30분~1시간 안에 배포·feature flag 토글·트래픽 이벤트가 있었는가. 운영 사고의 큰 비율은 직전 변경에서 온다.
  3. 1~2분: 외부 의존성 상태 확인. PG, 알림 provider, 배달채널, 클라우드 상태 페이지. 우리 문제가 아닐 가능성을 먼저 끊는다.
  4. 2~3분: 완화(mitigation) 결정. 원인 분석보다 사용자 영향 차단이 먼저다. 롤백, feature flag off, 결제수단 차단, 트래픽 제한.
  5. 3~5분: 커뮤니케이션. CS·운영·사업 채널에 1차 공지. "조사 중"이라도 보낸다. 침묵이 가장 나쁘다.
  6. 5분 이후: 원인 분석. 트레이스/로그로 깊이 들어간다.

지원자가 이미 갖고 있는 "graceful shutdown 503 대응" 경험은 이 루프의 1~2번에 닿는다. 배포 중 503 비율이 튀었을 때 "직전 변경이 원인" → "graceful shutdown으로 in-flight 요청 종료 후 종료" → "503 비율 회복" 흐름은 첫 5분 루프를 정확히 따른 좋은 케이스다.

잘못된 패턴 vs 개선된 패턴

결제 호출

java
// bad
@Transactional
public Order placeOrder(OrderCommand cmd) {
    Order o = orderRepo.save(cmd.toEntity());
    pgClient.charge(o.getId(), cmd.getAmount()); // 외부 호출이 트랜잭션 안
    sendKakaoAlert(o);                            // 외부 호출이 트랜잭션 안
    posClient.dispatch(o);                        // 외부 호출이 트랜잭션 안
    return o;
}

문제는 셋이다. 외부 호출이 길어지면 DB 커넥션이 점유돼 풀이 마른다. 외부 실패 시 DB만 롤백되고 외부 부작용은 남는다. 이중 결제 위험이 높다.

java
// improved
@Transactional
public Order placeOrder(OrderCommand cmd) {
    Order o = orderRepo.save(cmd.toEntity());
    outboxRepo.save(OutboxEvent.posDispatch(o));
    outboxRepo.save(OutboxEvent.alertOrderPlaced(o));
    return o; // 짧고 결정적
}
 
// 결제는 별도 단계 / idempotency key 필수
public PaymentResult pay(OrderId id, IdempotencyKey key, Amount amount) {
    return pgClient.charge(id, key, amount, timeout(5_000));
}

핵심은 외부 호출을 트랜잭션 밖으로 빼고, outbox로 묶고, 결제는 멱등 키로 보호한다는 점이다.

알림 발송

java
// bad
try {
    push.send(token, message);
} catch (Exception e) {
    log.warn("push failed", e); // 흔적만 남고 사라짐
}
java
// improved
notificationQueue.enqueue(NotificationJob.of(token, message)); // DLQ + retry 보유

캐시 갱신

java
// bad: 가격만 갱신, 옵션 캐시는 그대로
cache.put(menuPriceKey(id), price);
java
// improved: 무효화 이벤트 한 번으로 묶음
events.publish(new MenuChanged(id));
// listener: cache.invalidate(menuPriceKey(id)); cache.invalidate(menuOptionKey(id));

로컬 실습 환경

운영 시뮬레이션은 한 노트북에서 충분히 만들 수 있다. docker compose로 다음 스택을 띄운다.

yaml
services:
  app:
    image: openjdk:17
    # spring boot fat jar 마운트
  mysql:
    image: mysql:8.0
    environment: [MYSQL_ROOT_PASSWORD=root]
  redis:
    image: redis:7
  kafka:
    image: bitnami/kafka:3.6
  prometheus:
    image: prom/prometheus
    volumes: ["./prometheus.yml:/etc/prometheus/prometheus.yml"]
  grafana:
    image: grafana/grafana
  loki:
    image: grafana/loki
  tempo:
    image: grafana/tempo

Spring Boot 쪽에는 micrometer-registry-prometheus, spring-cloud-sleuth(또는 micrometer tracing), logback-json 설정만 들어가 있으면 메트릭/트레이스/로그 3층이 다 잡힌다.

직접 돌려볼 만한 시나리오

1) 피크 트래픽 회복력 측정

bash
k6 run --vus 200 --duration 3m order_script.js
  • 동시접속 200 유지 상태에서 결제 호출 타임아웃을 5s에서 1s로 줄여보고 5xx 추이 비교.
  • HikariCP maximum-pool-size를 10 → 30으로 올렸을 때 DB CPU와 latency 변화 관찰.

2) PG 장애 시뮬레이션

PG mock 서버에 50% 확률 5s 지연을 넣고, 서킷 브레이커 on/off 비교.

yaml
resilience4j:
  circuitbreaker:
    instances:
      pg:
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        slidingWindowSize: 20

3) 캐시 정합성 깨뜨려보기

가격 변경 이벤트를 일부러 일부 인스턴스에만 전달하고 30초 안에 자동 수렴하는지 확인. TTL 30초/60초/300초로 바꿔보면서 사용자 영향 시간 측정.

4) traceId 비동기 전파

주문 컨트롤러 → Kafka produce → consumer → DB 까지 같은 traceId가 찍히는지 Tempo에서 확인. 헤더 전파 빠뜨렸을 때 어디서 끊기는지 직접 본다.

포스트모템 작성 표준

장애 후 24~72시간 안에 다음 형식으로 정리한다. 형식 자체가 재발 방지에 큰 영향을 준다.

  • 요약 (3줄 이내)
  • 사용자 영향 (시간대, 영향 범위, 추정 CS 건수)
  • 타임라인 (분 단위)
  • 직접 원인 (technical root cause)
  • 기여 요인 (왜 더 일찍 막지 못했나)
  • 조치한 완화책
  • 재발 방지 액션 아이템 (오너·기한 필수)
  • 검출 시간(TTD), 완화 시간(TTM), 복구 시간(TTR)

좋은 포스트모템의 가장 큰 특징은 "사람을 탓하지 않는다"는 점이다. "A가 실수했다"가 아니라 "그 실수가 운영 단계까지 도달할 수 있는 구조였다"로 쓴다. 면접에서도 같은 톤이 시니어 신호로 읽힌다.

재발 방지의 4가지 레버

  1. 검출 개선 — 알람 임계치 조정, 부족했던 메트릭 추가.
  2. 완화 자동화 — feature flag, 자동 롤백, 트래픽 차단 스위치.
  3. 구조 변경 — outbox 도입, 동기→비동기 분리, 의존성 격리.
  4. 운영 룰 — 배포 시간대 제한(피크타임 배포 금지), canary 비율 조정.

한 사고에서 1~2개 레버까지만 손대는 게 현실적이다. 4개를 한 번에 하려고 하면 어느 것도 안 끝난다.

면접 답변 프레임

운영 장애 관련 질문에는 STAR + 숫자 + 트레이드오프로 답한다.

  • Situation: "점심 피크타임에 5xx 비율이 평소 0.1%에서 2%까지 튀었습니다."
  • Task: "사용자 영향이 직접 보이는 상황이라 원인 파악보다 완화가 우선이었습니다."
  • Action: "직전 배포가 의심돼 graceful shutdown 흐름을 점검했고, in-flight 요청이 강제 종료되며 503으로 떨어지는 패턴을 확인했습니다. 종료 hook에서 헬스체크를 먼저 unready로 바꾸고 in-flight 요청이 종료된 후에 컨테이너를 내리도록 수정했습니다."
  • Result: "이후 배포 시 503 비율이 평시 수준으로 돌아왔고, 같은 패턴의 재발을 막기 위해 배포 파이프라인에 graceful shutdown 점검 단계를 추가했습니다."
  • Trade-off: "graceful shutdown 시간이 길어지면 배포 속도가 느려져서, 최대 대기 시간을 60초로 캡을 걸어 둔 점도 같이 설명할 수 있습니다."

운영 깊이를 묻는 질문 — "캐시 정합성 어떻게 다뤘나", "traceId 비동기 구간 어떻게 살렸나", "PG 장애 때 어떻게 대응했나" — 에는 같은 프레임을 그대로 쓰면 된다.

자주 나오는 면접 질문과 답변 포인트

Q. 피크타임에 가장 먼저 무너지는 자원이 뭐라고 보나요? A. 보통 WAS 스레드 풀과 DB 커넥션 풀이다. 외부 의존성이 느려질수록 우리 스레드가 묶이기 때문이다. 그래서 외부 호출에 timeout과 서킷 브레이커를 두는 게 단순 스케일 아웃보다 먼저다.

Q. PG 장애 시 어떻게 대응하나요? A. 먼저 영향 범위가 전체 PG인지 특정 카드사인지 확인한다. 부분 장애면 해당 결제수단만 feature flag로 차단해 블래스트 레이디어스를 줄인다. 이중 결제 방지를 위해 idempotency key 기반 재시도와 결과 폴링/webhook 이중 채널을 둔다.

Q. 캐시 정합성은 어떻게 보장하나요? A. "절대 안 깨지게"는 비현실적이고, "깨져도 N분 안에 수렴한다"를 목표로 한다. TTL을 짧게 잡고, 변경 이벤트로 명시적 invalidate, 최후 보루로 강제 리프레시 잡을 둔다. 본인이 다룬 정합성 이슈 사례와 어떤 레버로 수렴 시간을 줄였는지 같이 말한다.

Q. 운영 중 traceId가 끊기면 어떻게 하나요? A. 끊긴 구간을 먼저 찾는다. 대개 비동기 구간(Kafka, 스레드 풀, 배치) 진입 시점이다. 메시지 헤더 또는 컨텍스트 전파로 traceId를 명시적으로 실어 보내는 처리로 복구한다. 본인이 직접 수정해본 경험을 그대로 풀어 답하면 강하다.

Q. graceful shutdown은 왜 중요하고 어떻게 구현하나요? A. 배포·스케일 다운 시 in-flight 요청이 강제 종료되면 5xx로 사용자에게 노출된다. 종료 hook에서 헬스체크를 unready로 먼저 바꿔 신규 트래픽을 차단하고, in-flight 요청이 끝날 때까지 일정 시간 대기 후 종료한다. Spring Boot의 server.shutdown=graceful과 spring.lifecycle.timeout-per-shutdown-phase로 기본은 구성되지만, LB unregister 타이밍과 맞물려야 실제 503이 사라진다.

Q. 새벽 배치가 실패하면 어떻게 알아내나요? A. 배치별 "마지막 성공 시각" 메트릭을 두고, 이 값이 예상 주기보다 길어지면 알람을 띄운다. 잡 안에서 try/catch로 묻히는 패턴이 가장 위험해서, 실패 시 명시적으로 메트릭에 카운트를 올리는 식으로 보조한다.

운영 체크리스트

  • 핵심 API마다 SLI/SLO가 문서로 정의돼 있는가
  • 알람은 "기간 + 비율" 조합인가
  • WARN과 PAGE 알람이 분리돼 있는가
  • 외부 의존성마다 timeout, retry, 서킷 브레이커가 있는가
  • 결제·쿠폰 발급 같은 멱등 필요 지점에 idempotency key가 있는가
  • 외부 호출이 트랜잭션 안에서 일어나지 않는가
  • outbox 또는 동등한 패턴으로 부작용이 보호되는가
  • 알림 발송에 retry/DLQ가 있는가
  • 캐시 무효화가 단일 이벤트로 묶여 있는가
  • traceId가 동기·비동기 구간을 모두 횡단하는가
  • 배치마다 마지막 성공 시각 메트릭과 알람이 있는가
  • PG/카드사/결제수단을 feature flag로 분리해 차단할 수 있는가
  • 장애 첫 5분 행동 순서를 팀원 모두가 알고 있는가
  • 포스트모템 양식이 사람 탓을 하지 않는 구조인가
  • 재발 방지 액션 아이템에 오너와 기한이 있는가
on this page
  • 01왜 이 주제가 중요한가
  • 02핵심 개념: 운영형 백엔드가 모니터링을 보는 방식
  • 03F&B / e-Commerce 운영에서 자주 터지는 9가지 시나리오
  • 1) 피크타임 트래픽 — 점심/저녁 두 번의 산
  • 2) 이벤트 / 쿠폰 오픈 — 인위적으로 만든 스파이크
  • 3) 매장 POS 연동 장애 — "주문은 됐는데 매장이 모름"
  • 4) PG 장애 — 가장 자주, 가장 시끄럽게 터진다
  • 5) 알림 장애 — 사용자가 가장 먼저 체감하는 결함
  • 6) 재고 / 품절 동기화 지연 — "주문 받았는데 만들 게 없음"
  • 7) 캐시 불일치 — 가장 추적하기 어려운 운영 사고
  • 8) 배치 실패 — 새벽에 조용히 무너지는 영역
  • 9) CS 증가 — 운영 사고의 후행 지표이자 선행 지표
  • 04핵심 지표·알림 기준·대시보드
  • 반드시 잡아야 할 SLI
  • 알림 임계치 설계 원칙
  • 운영 대시보드 기본 구성
  • 05로그·traceId 설계
  • 06장애 대응 첫 5분 — 운영 백엔드의 코어 루프
  • 07잘못된 패턴 vs 개선된 패턴
  • 결제 호출
  • 알림 발송
  • 캐시 갱신
  • 08로컬 실습 환경
  • 09직접 돌려볼 만한 시나리오
  • 1) 피크 트래픽 회복력 측정
  • 2) PG 장애 시뮬레이션
  • 3) 캐시 정합성 깨뜨려보기
  • 4) traceId 비동기 전파
  • 10포스트모템 작성 표준
  • 11재발 방지의 4가지 레버
  • 12면접 답변 프레임
  • 13자주 나오는 면접 질문과 답변 포인트
  • 14운영 체크리스트

댓글 (0)