JPA.

JPA 동시성 문제 해결하기 (feat. JMeter)

PI.314 2022. 9. 13. 00:53

(해당 글은 온전히 학습을 위한 부분이라는 점 참고 부탁드립니다. Pessimistic Lock을 사용하면 성능 상 좋지 않습니다.)

 

사용자가 컨텐츠 상세페이지에 방문할때마다 조회수가 1씩 증가되도록 로직을 구현하려고 합니다.

 

그런데 만약 1000명의 사용자가 동일한 상세페이지에 동시에 접근하면 어떻게 될까요?

동시성 고려하기 전 (로직 구현 및 테스트)

1. 조회수 증가 로직

위 코드를 참고하면, contentsRepository를 통해 contentEntity를 조회한 후 hits를 1씩 증가시키고 있습니다.

 

2. JMeter를 이용한 동시성 테스트

JMeter > Thread Group
JMeter > Summary Report

JMeter에 Thread Group을 생성하고 Number of Threads를 1000으로 설정한 후, 실행해보겠습니다.

h2 database

먼저 DB를 통해 정상적으로 값이 저장되었는지 확인해보겠습니다.

Hits 값이 1000이 아닌 117인 것을 보았을 때 정상적인 결과 값을 얻지 못한 것을 알 수 있습니다.

InteliJ > Console

먼저 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를 이용한 동시성 테스트

JMeter > Summary Report

동시성을 보장 한 후에는, Average(평균 응답시간)은 더 오래걸리고 Throughput은 줄었습니다.

결국 동시성 보장과 성능은 Trade-Off 관계이기 때문에 비즈니스를 잘 고려하여 상황에 맞게 사용하는 것이 좋겠습니다.

h2 database

Hits 값이 1000으로 원하는 결과 값이 정상적으로 저장되어 있는 것을 확인할 수 있습니다. 

 

 

'JPA.' 카테고리의 다른 글

[우아한테크캠프 Pro] JPA Hands-on Part 1 정리  (0) 2022.11.03
[Spring] JPA 동작 방식  (0) 2022.02.02