💡문제 상황

첫번째 게시글에서는 좋아요 클릭 시, 반영이 잘 되는데 두번째 게시글부터 게시글 좋아요가 반영이 안되는 현상이 발견됨. 게시글을 조회하고 있는 멤버의 좋아요 여부를 나타내는 isLiked 값이 여러번 연속해서 처리할 때 계속해서 true로만 반환 됨. 트랜잭션이 충돌을 일으킨 것으로 여겨짐.

 

해당 게시글에 조회하는 멤버가 좋아요를 눌렀을 시, 생성되는 postLike 데이터를 조회하는 과정에서 에러가 나는 것으로 확인됨. 해당 멤버와 해당 게시글 아이디로 데이터를 조회하여 postLike가 이미 있으면 false로 반환(좋아요 취소)하고 없으면 true로 반환(좋아요 성공)하는 로직임.

 

 

📒선택지

1. 낙관적 락(Optimistic Lock): version 관리를 통해 application 레벨에서 처리하는 방법으로, JPA가 제공하는 버전 관리 기능(@Version)을 사용함. 대부분의 트랜잭션이 충돌하지 않는 다고 가정하는 방법임. 충돌이 나는 것을 막지 않고, 충돌이 난 것을 감지하면 처리함

 

2. 비관적 락(Pessimistic Lock): 트랜잭션의 충돌이 발생한다고 가정함. 하나의 트랜잭션이 자원에 접근 시 락을 걸고, 다른 트랜잭션이 접근하지 못하게 함. 데이터 수정 즉시 트랜잭션 충돌 여부 확인이 가능함. DB 단에서 Lock을 함.

 

 

🤔 문제 해결

  • 이미 충돌이 발생한 것을 확인 했기 때문에 비관적 락을 사용하기로 결정함. 복합키를 이용하여 좋아요 데이터를 찾아오는 메서드에 비관적 락을 걸어주었음.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Transactional
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="3000")})
Optional<PostLike> findByPostLikedIdAndMemberId(Long postLikedId, Long memberId);
  • 비관적 락에는 두가지 종류가 있음:
    • Exclusive Lock: 데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지되어 해당 Lock이 해제될 때까지 다른 트랜잭션은 해당 데이터에 읽기를 포함하여 접근을 할 수 없음
    • Shared Lock: 다른 사용자가 동시에 데이터를 읽을 수는 있지만 Write는 할 수 없음
  • LockModeType으로 PESSIMISTIC_WIRTE 선택하였는데, PESSIMISTIC_WRITEExclusive Lock을 걸고, 데이터를 읽거나, 업데이트 하거나, 삭제하는 것을 막음
  • Lock이 길어지면 Latency가 길어지기 때문에,  @QueryHints 를 사용하여 Lock에 3초 타임 아웃을 적용함

 

→ 좋아요 여부 값(isLiked) 반환 정상적으로 실행 됨

 

 

 

기타 고려사항

 

  • 단일 DB 환경이기 때문에 비관적 락을 사용해서 문제가 발생하지 않지만 추후에 분산 DB를 사용하는 환경일 경우에는 분산 락(Distributed Lock) 도입도 고려해 볼 수 있음. (위의 이미지는 현재 아키텍쳐; RBS 하나를 사용)
  • 비관적 락은 모든 트랜잭션에 대해 Lock을 사용하기 때문에 트래픽이 많은 경우, O(N^2) 정도로 성능이 저하된다는 문제가 생길 수 있음.

+ Recent posts