작성
·
26
1
안녕하세요.
먼저 좋은 강의 감사드립니다.
데이터 버저닝에서 이해가 가지 않는 부분이 있어서 질문 드립니다.
낙관적 락을 사용하는걸 봤습니다.
결과적으로 발행시와 소비시의 버전이 같아야 하는데, 대규모 시스템에서 장애가 발생하지 않으려면 프로듀서에 아이디 1인 상품 발행하고 나서
컨슈머에서 처리하기 전까지 절대 새로운 이벤트를 발행하면 안되는거 아닌가요?
만약 컨슈머에서 처리하기 전에 이벤트를 발행하면 똑같은 버전이 후에 계속 들어와서 이 재고 업데이트는 무시되는게 아닌가 해서 질문드립니다.
맞다면 재고 감소 멱등성은 어떻게 해결하면 좋을지 고견 듣고 싶습니다.
감사합니다.
답변 2
0
HAHA님 안녕하세요~
우선 강의 잘 봐주시고, 좋은 질문 남겨주셔서 감사합니다. 날카로운 질문이네요. ㅎㅎ
단순히 이벤트 버전과 데이터베이스 버전을 비교해서 다르면 무시하는 방식만으로는, 동시에 발생하는 '동일한 상품에 대한 진짜 서로 다른' 재고 감소 요청 중 뒤에 발행되는 요청이 유실되는 문제가 발생할 수 있습니다.
이 문제는 동일한 이벤트의 '중복 처리'를 막는 멱등성 문제와는 다른, 여러 유효한 요청이 경합하는 동시성 제어의 문제입니다.
문제 상황: 유효한 주문의 유실
말씀하신 시나리오를 흐름으로 정리하면 다음과 같습니다.
초기 상태: 상품 A의 재고는 10개, 데이터베이스(DB)의 버전은 5
입니다.
주문 1 발생: 프로듀서가 상품 A의 정보(버전 5
)를 읽고, 재고 감소 이벤트(A)를 발행합니다.
주문 2 발생: 거의 동시에, 아직 주문 1의 이벤트가 컨슈머에 의해 처리되기 전에, 다른 프로듀서가 상품 A의 정보(여전히 버전 5
)를 읽고, 재고 감소 이벤트(B)를 발행합니다.
컨슈머 처리:
이벤트 A가 먼저 도착합니다. DB 버전(5
)과 이벤트 버전(5
)이 일치하므로 재고를 9로 감소시키고, DB 버전을 6
으로 업데이트합니다. (성공)
이벤트 B가 도착합니다. 이벤트에 담긴 버전은 5
이지만, 현재 DB 버전은 6
입니다. 버전이 다르므로 컨슈머는 이 요청을 무시합니다. (실패 및 유실)
이 경우, 분명히 유효한 주문이었던 '주문 2'가 그냥 무시되어버리는 문제가 발생합니다.
(이걸 물어보신게 맞겠죠? ㅎㅎ)
이 문제를 해결하려면 컨슈머의 로직이 더 정교해져야 합니다. 이 문제를 해결하는 가장 좋은 방법은 고유 ID를 사용한 멱등성 처리와 버전을 사용한 동시성 제어를 모두 적용하는 것입니다.
1단계: 멱등성 키(Idempotency Key)로 중복부터 확인
모든 이벤트는 eventId
나 orderId
와 같이 절대 중복되지 않는 고유 ID를 가져야 합니다.
컨슈머는 로직을 시작하기 전에, "이미 처리한 ID인지"를 별도의 processed_events
같은 테이블에 확인(INSERT 시도)합니다.
만약 ID가 이미 있다면? → 이것은 '진짜 중복' 이벤트입니다. 즉시 처리를 중단하고 무시합니다. 이 단계에서 실제 중복 문제는 완벽히 걸러낼 수 있습니다.
2단계: 버전으로 동시성 충돌 확인
ID가 처음 들어온 것이라면? → 이제 이것은 '중복'이 아닌 '정상' 이벤트(순서가 밀렸을 수는 있는)임이 보장됩니다.
이 상태에서 이전 답변에서 설명한 버전 비교 로직을 수행합니다.
버전 일치: 첫 처리이므로 재고를 감소시킵니다.
버전 불일치: 다른 정상 주문에 의해 순서가 밀린 것이므로, 현재 DB 상태를 기준으로 재고를 재확인하고 업데이트를 재시도합니다.
이러한 'ID로 중복을 먼저 거르고, 버전으로 순서를 제어하는 방법'을 통해, 질문해주신 상황에 대해 데이터 정합성을 지킬 수 있을겁니다.
본 영상에서는 동시성 제어보다는 장애 상황으로 인해 재시도 되는 등 중복 발행된 데이터에 대해 멱등성이 있는지에 포커스를 맞춰서 강의에서 이야기 한 것처럼 설명되었습니다!
이 질문글은 강의 노트에도 링크 추가해두겠습니다~
혹시 또 궁금한 내용 있으면 질문 남겨주세요~!
감사합니다!
0
안녕하세요, 인프런 AI 인턴입니다. HAHA님.
데이터 버저닝과 낙관적 락은 주로 데이터의 일관성 문제를 해결하기 위한 방법론들입니다. 질문하신 내용과 관련된 비슷한 키워드로 관계된 질문과 답변을 찾아 설명드리겠습니다.
낙관적 락은 데이터의 충돌을 최소화하기 위해 사용되는 패턴으로, 주로 데이터 변경의 빈도가 낮거나 충돌 가능성이 낮은 경우에 사용됩니다. 질문하신 문제에서는 프로듀서와 컨슈머 간의 처리 순서 및 데이터 일관성이 중요합니다.
이벤트 버저닝 관리: 기존 시스템에서 발생한 이벤트의 버전을 기록하여, 컨슈머가 특정 버전에 따라 처리할 수 있도록 합니다. 만약 새로운 이벤트가 발생했을 때 이미 발행된 이벤트와 충돌할 경우, 컨슈머 쪽에서 이를 감지하고 적절하게 처리할 수 있어야 합니다.
멱등성 보장: 재고 감소와 같은 작업은 멱등성이 보장되어야 합니다. 이를 보장하기 위해서는, 동일한 이벤트가 여러 번 처리되어도 시스템 상태가 같도록 해야 합니다. 예를 들어, 이벤트에 고유 식별자를 부여하여 이벤트 처리 완료 여부를 체크하거나, 데이터베이스 레벨에서 트랜잭션 및 조건부 갱신(Upsert) 방식을 사용할 수 있습니다.
비슷한 상황을 겪는 과정에서 참고할 수 있는 유사한 질문과 답변 링크를 드리겠습니다:
Redis를 활용한 캐시와 트랜잭션 관리: 이 링크는 Redis 및 트랜잭션 관리 방식에 대한 논의들을 포함하고 있으며, 데이터 일관성과 멱등성을 어떻게 보장할 수 있는지 좋은 포인트들을 제공합니다.
비동기 분리에 관한 논의: 비동기 처리 방식에서의 데이터 일관성 및 장애 해결 방안에 대한 여러 가지 접근 방법을 확인할 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.