(해당 글은 온전히 학습을 위한 부분이라는 점 참고 부탁드립니다. Pessimistic Lock을 사용하면 성능 상 좋지 않습니다.)
사용자가 컨텐츠 상세페이지에 방문할때마다 조회수가 1씩 증가되도록 로직을 구현하려고 합니다.
그런데 만약 1000명의 사용자가 동일한 상세페이지에 동시에 접근하면 어떻게 될까요?
동시성 고려하기 전 (로직 구현 및 테스트)
1. 조회수 증가 로직
위 코드를 참고하면, contentsRepository를 통해 contentEntity를 조회한 후 hits를 1씩 증가시키고 있습니다.
2. JMeter를 이용한 동시성 테스트
JMeter에 Thread Group을 생성하고 Number of Threads를 1000으로 설정한 후, 실행해보겠습니다.
먼저 DB를 통해 정상적으로 값이 저장되었는지 확인해보겠습니다.
Hits 값이 1000이 아닌 117인 것을 보았을 때 정상적인 결과 값을 얻지 못한 것을 알 수 있습니다.
먼저 InteliJ Console에서 로그를 보게 되면 무언가 문제가 있음을 직감할 수 있습니다.
예시를 들어 조금 더 자세히 설명 드리면,
현재 hits가 10이라고 가정하고 사용자 1, 2, 3이 contents를 조회했다고 생각해보겠습니다.
hits 기댓값
- 사용자 1의 조회 후 hits 값 : 11
- 사용자 2의 조회 후 hits 값 : 12
- 사용자 3의 조회 후 hits 값 : 13
과연 기댓값과 동일한 값이 나올까요?
1. 사용자 1, 2, 3이 동시에 contents 조회 (hits 10)
-> 사용자 1이 hits를 업데이트하기전에 사용자 2, 3 이 contents를 조회하게되면 hits가 10일 때 값을 가져가게 됩니다.
2. 사용자 1, 2, 3은 각각 hits를 1씩 증가시킨다. (hits 11)
3. 사용자 1, 2, 3 모두 조회를 끝냈지만 hits는 11로 저장하게 됩니다.
동시성 고려 후 (로직 구현 및 테스트)
1. 조회수 증가 로직 (Pessimistic Lock 적용)
PESSIMISTIC_WRITE은 해당 리소스에 베타 Lock을 걸고, 다른 트랜잭션에서는 읽기와 쓰기 모두 불가능해집니다.
Hibernate:
select contents_e0_.contents_id as contents1_0_,
contents_e0_.created_date as created_2_0_,
contents_e0_.description as descript3_0_,
contents_e0_.download_file_path as download4_0_,
contents_e0_.hits as hits5_0_,
contents_e0_.image_url as image_ur6_0_,
contents_e0_.title as title7_0_,
contents_e0_.user_id as user_id8_0_
from tb_contents_info contents_e0_
left outer join tb_user_info user_entit1_ on contents_e0_.user_id=user_entit1_.user_id
where user_entit1_.user_id=? and contents_e0_.contents_id=?
for update
위 로그 맨 아래를 보면 for update가 추가되어 있습니다. 해당 리소스를 조회하는 것이 업데이트를 위한 것이라는 뜻입니다.
그래서 for update는 리소스에 update할 때, Lock 이걸려 있는 순서대로 update가 진행되는 점을 확인할 수 있었습니다.
2. JMeter를 이용한 동시성 테스트
동시성을 보장 한 후에는, Average(평균 응답시간)은 더 오래걸리고 Throughput은 줄었습니다.
결국 동시성 보장과 성능은 Trade-Off 관계이기 때문에 비즈니스를 잘 고려하여 상황에 맞게 사용하는 것이 좋겠습니다.
Hits 값이 1000으로 원하는 결과 값이 정상적으로 저장되어 있는 것을 확인할 수 있습니다.
'JPA.' 카테고리의 다른 글
[우아한테크캠프 Pro] JPA Hands-on Part 1 정리 (0) | 2022.11.03 |
---|---|
[Spring] JPA 동작 방식 (0) | 2022.02.02 |