Log in Get started
← 가이드 목록
시작하기

Race Condition이란? 여러 작업이 동시에 실행될 때 결과가 꼬이는 이유 쉽게 이해하기

Race Condition은 여러 작업이 같은 상태를 동시에 다루며 실행 순서에 따라 결과가 달라지는 문제입니다. 재고·검색·Lock·Transaction·멱등성·Lost Update까지 초보 기준으로 정리합니다.

Race Condition이란? 여러 작업이 동시에 실행될 때 결과가 꼬이는 이유 쉽게 이해하기
재고 1개를 두 사용자가 동시에 확인하고 둘 다 구매 성공하는 Race Condition 흐름도
확인 시점과 변경 시점 사이에 다른 작업이 끼어들면, 각자 맞는 판단을 해도 결과가 틀어질 수 있습니다.

마지막 좌석 · Read-Modify-Write

재고 1개에 A·B가 거의 동시에 「1개 있음」을 읽고 둘 다 구매 성공하면 실제보다 많이 팔린 것입니다. 여러 작업이 같은 상태를 다루며 실행 순서에 따라 결과가 달라지는 문제Race Condition(경쟁 상태)입니다. 같은 CPU 순간이 아니어도, 읽기–대기–쓰기 구간이 겹치면 충분합니다. 대표 패턴은 Read-Modify-Write(조회 → 계산 → 저장)와 Check-Then-Act(조건 확인 후 행동)입니다. 혼자 클릭 테스트에선 잘 보이고, 실제에선 「가끔만」 재현되는 버그가 됩니다 — 로그·Request ID·분산 추적이 중요합니다. 동시성을 높일수록 이런 경쟁 구간도 늘어납니다.

읽기 → 계산 → 저장 사이에 다른 요청이 끼어듦
→ Lost Update · 재고 초과 판매 등

프론트: 검색 Race · 버튼만으로는 부족

자동완성에서 「홈 → 홈페 → 홈페이지」 요청이 나가도 응답 순서는 뒤바뀔 수 있습니다. 늦은 「홈」 결과가 최신 화면을 덮으면 그것도 Race입니다. JS가 한 줄씩 실행돼도 비동기 완료 순서는 보장되지 않습니다 — Promise·async/await만으로 자동 해결되지 않습니다. 요청 ID로 최신만 적용하거나 AbortController로 이전 요청을 취소할 수 있습니다. 버튼 비활성은 같은 탭 중복 클릭을 줄이지만, 다른 탭·다른 사용자·직접 API 호출은 막지 못하므로 재고·결제의 최종 안전은 서버·DB가 담당합니다.

서버: Atomic · Lock · Constraint · 멱등

가능하면 UPDATE … SET stock = stock - 1 WHERE stock > 0처럼 원자적(Atomic) 조건부 변경으로 경쟁 구간을 줄입니다. 변경된 row 수로 성공·실패를 판정합니다. Pessimistic Lock은 먼저 잠그고 작업하고, Optimistic Lock은 version 등으로 저장 시 충돌을 감지합니다. Transaction은 여러 변경을 묶지만 Isolation Level·Lock·SQL 없이는 Race가 자동 해결되지 않습니다. 이메일·좌석 등은 UNIQUE 등 DB Constraint가 최종 방어선이 됩니다. 결제 중복에는 멱등성(Idempotency)·Idempotency-Key가 필요합니다 — Race와 개념은 다르지만 함께 자주 등장합니다. 조회수·좋아요의 Lost Update도 views = views + 1 같은 원자 증가로 줄입니다. 로드밸런서 뒤 여러 서버면 프로세스 메모리 Lock만으로는 부족할 수 있고, 공유 DB Lock·분산 Lock을 검토합니다. 수평 확장·Stateless여도 공유 DB 경쟁은 남습니다.

프론트: 최신 요청만 · Abort · 버튼 잠금(UX)
서버/DB: Atomic · Tx · Lock · UNIQUE · Idempotency

찾기 · 테스트 · Deadlock과의 차이

재고·잔액·쿠폰·예약·결제처럼 「같은 데이터를 동시에 바꾸는지」를 먼저 봅니다. HTTP 200이 두 번이어도 데이터가 틀릴 수 있어 서버 오류 모니터링만으로는 부족합니다 — 「재고 < 0 금지」「좌석 예약 1건」 같은 Invariant를 검사합니다. 동시 구매 100건 부하 테스트로 성공 건수가 재고와 맞는지 확인합니다. Race ≠ Deadlock: Race는 잘못된 결과, Deadlock은 서로 Lock을 기다리며 멈춤입니다. Lock으로 Race를 줄이면 Deadlock 위험이 생길 수 있어 순서·범위·유지 시간을 설계합니다. 모든 요청을 직렬화하면 안전하지만 처리량이 떨어지므로, 동시성을 유지하면서 정확성을 지키는 쪽이 현실적입니다.

자주 묻는 질문

Race Condition이란?

여러 작업이 같은 상태·데이터에 겹치며 실행 순서에 따라 결과가 달라지는 동시성 문제입니다.

JavaScript에서도 생기나요?

네. 코드가 한 줄씩이어도 비동기 요청의 완료 순서는 달라질 수 있습니다.

버튼 비활성으로 해결되나요?

중복 클릭 완화에는 도움이 되지만 다른 사용자·탭·API 직접 호출까지 막지는 못합니다.

Transaction이면 끝인가요?

아닙니다. Isolation·Lock·Atomic SQL 등을 함께 봐야 합니다.

Optimistic / Pessimistic Lock?

낙관은 저장 시 충돌 확인, 비관은 작업 전 잠금입니다.

멱등과 같나요?

아닙니다. Race는 순서 경쟁, 멱등은 같은 요청 반복 시 중복 효과를 막는 성질입니다.

정리

Race Condition = 동시에 같은 상태를 다루며 실행 순서에 따라 결과가 달라지는 문제입니다. 재고 1개·두 구매 성공이 대표 예입니다. Atomic Operation·Transaction·Optimistic/Pessimistic Lock·UNIQUE·Idempotency로 막습니다. Race를 막으려 Lock을 걸다 보면, A가 자원 1을 잡고 2를 기다리고 B가 2를 잡고 1을 기다리는 식으로 둘 다 멈출 수 있습니다 — 이것이 Deadlock(교착 상태)입니다.