티스토리 뷰

성능 시뮬레이션 - ① DB 커넥션 에서 테스팅 하였던 내용을 토대로 버츄얼 쓰레드 테스트를 진행해보았습니다.

 

'성능 시뮬레이션 - ① DB 커넥션 - 2) 서버 스펙보다 과도한 요청 넣기'에서

톰캣 스레드 개수를 변경시켜서 테스트를 해보았고,

200개일때 속도가 제한이 TPS가 많이 제한되었던것을 확인 할 수 있었습니다.

그러면 현재 Java 21에 도입된 버츄얼쓰레드(경량쓰레드) 를 사용해서 측정해보면 어떻게 될까

궁금하게 되어 측정하게 되었습니다.

 

1)  가상 스레드 사용 및 테스트

- CPU: 2 Core

- Ram: 1G

- Connection: 20 - 500

로 설정하였고,

Spring Property에 다음과 같이 설정을 추가했습니다.

spring:
  threads:
    virtual:
      enabled: true

 

다음과 같이 설정하게 되면 VisualVM에서 Thread 측정시 톰캣 스레드가 생성되지 않는 것을 확인 할 수 있었습니다.

좌: 버츄얼 스레드 활성화 전 / 우 : 버츄얼 스레드 활성화 후

 

 

 

종목                         스레드 수 200(pool) 500(pool) Virtual
CPU 사용률 18.3% 26.2% 12.6%
Thread 수 215 515  
Connection 수 200 (Active)
0 (Pending)
500 (Active)
0 (Pending)
300 (Active)
0 (Pending)
TPS 16.3/sec 45.1/sec 45.3/sec

 

500개로는 버츄얼스레드만의 장점이 보이지 않았습니다. (Thread Pool과 비슷한 성능)

 

그럼 2000개로 스레드를 한번 늘려보는것은 어떨까요?

 

종목                         스레드 수 2000(pool) Virtual
CPU 사용률 45.2% 45.6%
Thread 수 2000  
Connection 수 2000 (Active)
0 (Pending)
2000 (Active)
0 (Pending)
TPS 77.8/sec 88.9/sec

 

 


 

생각보다 이에 대해서 드라마틱한 큰 차이는 없었지만, 13프로 이상의 속도차이가 나왔습니다.

가상 스레드는 스레드풀의 최대로 플랫폼 스레드 생성한 것과 성능이 비슷하며,

크기가 커질수록 이 차이는 커졌습니다.

쓰레드 풀의 경우 Max Thread개수를 제한하고 사용하여야하는데 (쓰레드가 차지하는 Heap크기 및 생성비용 때문에)

이에 비한 버츄얼스레드를 이용해서 Tomcat ~ DB I/O 작업을 진행하는 것이 아주 좋다고 생각되었습니다.

실제로 2000개의 스레드를 생성한다고 하였을 때, 

쓰레드 풀을 이용하여 2000개를 생성할때 메트릭데이터가 끊기게 되는 현상을 목격했습니다.

좌 (버츄얼) / 우 (스레드풀)

 

 

 

 

아래에는 가상 스레드 실험하다가 만났던 문제를 정리하고자 합니다.


 

 

2)  가상 스레드 - pinning 문제

 

처음 테스트를 하였을대 아래와 같은 결과가 나왔었습니다.

 

 

결과

 

보자마자 엥? 이런소리가 나왔습니다. 이전보다 더 최악으로 느려졌거든요.

I/O작업동안 다른 쓰레드 요청을 받아들여, 다음 쿼리를 진행시켜 진행속도를 빠르게 하지 않을까 생각했었는데,

결과가 생각과는 다르게 나왔습니다. 

 

그래서 Thread가 어떻게 실제적으로 작동하는지 확인해보도록 하였습니다. (36개 요청)

정확히 16개의 처리 후 다음 16개의 요청이 처리되었습니다.

 

Visual VM - Thread

 

워커 스레드들이 생성됨과 특정 워커는 20초, 그외는 10초 후 끝나는 것을 확인 할 수 있었습니다.

제 예상 시나리오라면 거의 모든 스레드들이 10초 전후로 작업이 처리시킬 수 있을 것 같았는데 말입니다.

(가상 스레드의 경우 ForkJoinPool을 이용해서 버츄얼 스레드를 다룹니다.)

 

포크조인에 마운트되는 Virtual Thread의 동작을 확인하려면 JFR이나 JCMD를 통해서 확인할 수 있습니다.

JFR - Thread

이상하지 않나요? 제 생각에는 16개의 처리 도중 Park 상태로 변환되면

즉시 나머지 16개의 쓰레드가 실행될줄 알았습니다만 그렇지 않고, 먼저 들어온 스레드들을 대기하였습니다.

어디선가 스레드들을 언마운트 되지 않도록 하고있는게 분명했습니다.

(사실 이거에 대해서 찾아보다가 거의 반나절을 소비했습니다.)

 

이유는 가상 스레드의 주의 사항중 하나인 'Pinning'입니다.

Pinning이란 OS스레드에 스레드가 고정되는 방식을 이야기하는데요.

자바의 가상 스레드는 Syncronized 블록, 메서드 호출 혹은 네이티브 메서드를 호출하는 경우 언마운트되지 않습니다.

 

그렇다면 왜 가상스레드만 이러한 문제가 일어나는 걸까요??

가상스레드의 포크조인 풀에는 기본적으로 하드웨어의 기본 스레드의 개수만큼 생성되게됩니다.

결론적으로 OS스레드와 연결되는 것은 16개만 되기때문에 가상스레드들이 마운트가 해제되지 않는다면

Pinning에 의해서 나머지 스레드들은 동작할 수 없게되는 것입니다.

 

그렇다면 저는 왜 Pinning이 발생하게 되었냐? 단순 DB호출인데 말이죠.

바로 MySQL의 Connector-J의 문제였습니다.

9.0.0 미만버전에서 해당 라이브러리는 synchronized를 사용하고 있었고 9.0.0 버전부터

Reenterent Lock을 사용하도록 수정되었습니다.

이후 해당 라이브러리 버전을 변경하였고, 위의 성능 테스트 결과를 낼 수 있었습니다.

( MySQL :: MySQL Connector/J 릴리즈 노트 :: MySQL Connector/J 9.0.0 변경 사항 (2024-07-01, General Availability))

 

저처럼 아둔하게 찾아보지 않으려면

-Djdk.tracePinnedThreads=short or full 를 활성화하면 문제가 있는 프레임을 추적할 수 있다고합니다.

한번 활성화해서 본다면 

 

-Djdk.tracePinnedThreads=full

호출스택을 쭉 나열해주어서 어디서 문제가 발생하였는지 알 수 있습니다.

 

 

-Djdk.tracePinnedThreads=short

 

발생한 여부와, 문제가 발생한 부분만 알려주는데 디버깅하기는 쉽지 않습니다.

 

 

혹은 JFR을 통해도 확인할 수 있었습니다. VisualVM의 Browser탭을 확인해보니

Virtual Thread Pinned

 

Pinned 된 목록을 확인 할 수 있었습니다.

 


 

위에 -Djk.tracePinnedThreads 옵션을 적용해보다가 IDE의 Debug모드에서 오류가 발생하여서

정상적으로 Http 요청이 처리되지 않는 문제를 발견하였습니다.

 

해당옵션을 적용하여 Java에이전트를 이용할시에 바이트 코드 변경이 일어나는데,

가상스레드가 고정된 이후 새클래스를 사용할 수 없는다는점 때문에 교착상태가 발생한다고합니다. - JDK 오류

([JDK-8337331] crash: pinned virtual thread will lead to jvm crash when running with the javaagent option - Java Bug System)

제가 자세히 Intellij의 코드를 찾아보지는 않았지만, 디버깅모드를 사용시 에이전트를 사용하는것 아닌지 생각됩니다.

 

 


 

 

사실 단순히 성능테스트만 해보고 넘어가보려했는데,

예상 대로 동작하지 않은 테스트때문에 가상 스레드에게 많이 맞은 기분이었습니다.

 

가상스레드 사용시 주의할점( Virtual Threads  - Oracle 문서)을 꼭 읽어보고

외부 라이브러리 사용시, 기존 동기화 처리시, 그리고 자바 자체의 동기화 라이브러리 사용시 

꼭 주의하면서 사용해야 오히려 성능이 느려지는 현상을 방지할 수 있을 것 같습니다.

 

 

 

 

 

 

'JAVA공부 > JVM' 카테고리의 다른 글

GC 정리  (1) 2024.10.07
String Pool  (1) 2024.10.06
자바 Heap Dump  (0) 2022.11.04
GC 튜닝  (0) 2022.01.14
Garbage Collection 모니터링  (0) 2022.01.12
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함