웹 소설 서비스 클론코딩 과제 중 상세 조건에 아래와 같은 조건이 걸려있었다.

<aside> 📢 편당 결제, 포인트 충전 등의 화면에서 한번에 동일한 요청이 n 번 발생해도 하나만 성공해야 합니다.

</aside>

당연한 이야기였다. 모든 서비스들이 그렇듯 결제 버튼이 사용자들의 실수로 2번 눌린다던가, 게시글 작성 버튼이 여러번 눌려 같은 게시글이 여러번 데이터베이스에 저장될 수 있다.

난 이제껏 프론트엔드에서 버튼 비활성화와 같은 방식으로 해당 문제를 해결했었고, 서버 단에서는 동시요청에 따른 로직 처리를 따로 하지 않았다. 동시성을 고려하지 않고 개발을 해왔기 때문에 처음 이 주제를 받았을 때.

조금 난감했다.

그냥 프론트에서 버튼 비활성화를 하면 편하겠지만, 파라미터 유효성과 같은 검사도 프론트엔드, 백엔드 둘 다 검사를 하기 때문에, 이렇게 민감한 부분에 있어서는 한 쪽 뿐만이 아닌 양 쪽 다 검사하는 게 좋다고 생각한다.

어떻게 해결해야 하지?


1. ConcurrentHashMap

가장 먼저 생각이 든 것은 여러 요청 중에 동시 요청을 구분하는 것이다. 한번에 서버에 결제요청이 41개가 왔는데, 유저 A가 결제요청 40개를 보내고, 유저 B가 결제요청 1개를 보냈다. 서버에서 이를 구분하려면 요청에 특화되는 키 값이 필요하다.

  1. 토큰 및 세션을 통해 유저ID 값을 가져온다.
  2. ConcurrentHashMap에 key 값으로 넣는다.
  3. 결제에 관한 요청에 대해 매번 ConcurrentHashMap에 유저 ID key값으로 넣어 값이 존재하면 해당 요청을 반려시킨다.
  4. 일정 시간 후 (1초) ConcurrentHashMap에 있는 값을 삭제. ( 일정 시간이 지난 후에는 요청이 가능해야 하므로)