동시성 문제와 DynamoDB 원자적 업데이트, 조회-수정-덮어쓰기의 함정
들어가며: RDB와 다른 선택지
서버에서 DB에 접근할 때 ‘조회한 뒤 바꾼 값으로 다시 쓰기’를 반복하면 동시성 문제가 난다. RDB에서는 비관적·낙관적 잠금이나 원자적 업데이트로 막을 수 있다. DynamoDB를 쓰는 서비스에서는 원자적 업데이트를 선택한 사례를 소개한다.
전개: 즐겨찾기와 단일 테이블 디자인
사용자별 리소스 즐겨찾기 기능을 단일 테이블 디자인으로 구현할 때, favoritePeople 컬렉션을 앱에서 읽고 수정한 뒤 통째로 덮어쓰면, 비슷한 시각에 들어온 요청들이 같은 ‘빈 리스트’를 읽고 각자 추가한 결과만 남겨 최종적으로 한 명의 변경만 남는 현상이 발생한다.
전환: DynamoDB 원자 연산
DynamoDB는 list_append, ADD mySet, DELETE mySet 같은 연산을 원자적으로 지원한다. 즐겨찾기 등록·해제와 중복 방지를 위해 Set과 ADD/DELETE를 쓰면, 테스트 컨테이너로 100회 비동기 호출 시 비원자 경로는 1건만 남고 원자 경로는 100건 모두 남는 것을 확인할 수 있다.
결말: 서버는 요청을 기다리지 않는다
await으로 한 건씩 끝날 때까지 기다리면 정상 동작하지만, 서버는 여러 요청을 동시에 처리하므로 ‘이전 연산이 끝날 때까지 기다리지 않는다’는 전제로 설계해야 한다. 원자 연산으로 그 갈등을 제거할 수 있다.