여러분은 TDD 좀 치십니까?
저는 잘 못칩니다. 해본 적도 없고, 왜 해야하는지도 모르고..
어차피 기획 없이 내가 기획하면 사실 오늘이건 내일이건 도메인 로직 바뀔거고..
그러다 내게 TDD가 와버렸습니다.
[들어가기 전]
다음 용어가 무엇인지 알고, 설명할 수 있나요?
그런데 나는 동시성
을 몰라요!
어.. 부끄럽지만 나는 동시성 문제를 고려해본적도 해결해본적도 없다. 왜냐하면 이용자가 없으니까!
일단 짜야하니까. 포인트 충전 코드를 아래와 같이 작성해봤다.
public UserPoint chargeUserPoint(long id, long amount) {
// 포인트 테이블은 단순히 HashMap이다.
UserPoint userPoint = userPointTable.selectById(id);
UserPoint chargedPoint = userPoint.chargePoint(amount);
pointHistoryTable.insert(id, chargedPoint.point(), CHARGE, System.currentTimeMillis());
return userPointTable.insertOrUpdate(id, chargedPoint.point());
}
잠시 글을 멈추고 생각해보자.
포인트가 0에서 시작하고, 같은 아이디 유저 1명이 동시에 N번 1만큼 충전하는 요청을 실행시키면 어떻게 될까?
"멀티 쓰레드에서 실행 결과의 순서를 보장할 수 있는 방법은 없다."는 단순한 사실을 기억한다면, 충전의 일관된 결과를 보장할 수 없다.
조금 더 자세히 풀어보자면,
N개의 쓰레드가 거의 동시에 userPointTable에 현재 포인트 값을 조회하고, 해당 조회값 + 충전할 값을 유저 포인트에 업데이트한다.
업데이트 하기 전 값을 조회 성공한다면 전 값을, 업데이트가 완료 된 후 값을 조회 성곤한다면 후 값을 가져온다.
어떤걸 가져올지 우리는 모른다. (쓰레드 스케쥴링 하는 OS는 안다.)
이 과정을 통해 다음을 배웠다.
lost update
가 왜 일어나는지? 동시성 문제가 되면 발생하는 일들이 무엇인지?lock
, Atomic
, Concurrent
, flow
등이 사용된다. 각 개별마다 구현하는 방법은 다르지만, 비관락, 낙관락이랑 비슷한 알고리즘을 가지고 접근한다. (점유중이라면 접근 불가, 이미 변경됐다면 변경 취소)repository
을 넣어 CRUD 할 수 있게 해도 괜찮은가? 에 대한 고민 혹시 [들어가기전]의 답변이 궁금하신가요!?
글을 읽다보니 '아..! 나도 저거 알아야하는데!' 하진 않으신가요?!
여기까지 글을 읽으셨다면, 아마 항해 플러스 과정에 관심있으신 분이라고 생각합니다.
궁금한 점이 있으시다면 저에게 편하게 댓글 남겨주세요!!
혹은 highestbright98@naver.com
으로 메일을 남겨주셔도 굉장히 빨리 답변한답니다!
항해 플러스 백엔드에 관련해서 궁금하신점이 있다면 언제든 편하게 말씀주세요!
그리고 글이 도움됐다면, 등록하실때 제 추천인 코드 [9MPLfu] 입력하면,
20만원 할인의 혜택이 있답니다! (물론 저에게도 혜택이 있습니다! 😉)
MMA 팀장님! 많은 도움이 되고 있습니다!
한주간 고생 많으셨습니다!