2024. 3. 25. 10:37ㆍ개발
2024.03.22 - [개발] - 제이미터(JMeter)로 테스트 환경 구성 및 테스트하기_1
이전글에서 이어집니다..
실질적인 테스트 조건들을 정리한 뒤 2차 테스트를 수행했고 그 내용에 대해서 정리하기 시작했다.
톰캣설정으로 인한 성능차이가 발생 할 수 있는지를 확인 하기위해 아래 조건들을 대상으로 잡았다.
- 메모리가 높으면 더 빠른 속도가 나오는지 테스트 (1G) (2G)
- 기본조건
- 스레드100개
- 커넥션 15
- keepAliveTimeout 3
- maxKeepAliveRequests 50
- MetaspaceSize 256M
- 변경조건
- 메모리 1G ,메모리 2G 각 3회 테스트
- 기본조건
- 위에서 나온 결과를 확인하고 MetaspaceSize 여부가 속도에 영향을 주는부분이 있을지 테스트.
- 기본조건
- 메모리 1G
- 스레드100개
- 커넥션 15
- keepAliveTimeout 3
- maxKeepAliveRequests 50
- 변경조건
- MetaspaceSize지정 3회, MetaspaceSize 미지정 3회
- 기본조건
- 위에서 나온 결과를 확인하고 keepAliveTimeout과 maxKeepAliveRequests 여부가 속도에 미치는 영향이 있는지 테스트한다.
- 기본조건
- 스레드100개
- 메모리 1G
- 커넥션 15
- MetaspaceSize 미지정
- 변경조건
- keepAliveTimeout
- maxKeepAliveRequests
- 기본조건
- 위에서 나온 결과를 확인하고 스레드 갯수에 따른 속도 차이를 확인한다. (최소 각 3회)
- 기본조건
- 스레드100개
- 메모리 1G
- 커넥션 15
- MetaspaceSize 미지정
- keepAliveTimeout 제거
- maxKeepAliveRequests 제거
- 변경조건
- 스레드 30개
- 스레드 50개
- 스레드 100개
- 스레드 200개(default)
- 기본조건
- 위에서 나온 결과를 확인하고 db커넥션에 따른 속도차이를 확인한다.(최소 각 3회)
- 기본조건
- 스레드 100개
- 메모리 1G
- MetaspaceSize 미지정
- keepAliveTimeout 제거
- maxKeepAliveRequests 제거
- 변경조건
- 커넥션 15개
- 커넥션 20개
- 커넥션 30개
- 기본조건
간략하게 정리하면 다음과 같다.
1번
톰캣 메모리 설정에 따른 성능차이.
2번
MetaspaceSize 값을 지정해주는것에 따른 성능차이가 혹시 있는지..
(MetaspaceSize의 경우에는 JDK 8 기준이라 자동으로 늘어나는 형태라 성능상에 문제는 없다고 한다. 자세한건 다른 블로그들에서 잘 설명되어있으니…참고를 하시면 될 것 같다.)
3번
keepAliveTimeout 와 maxKeepAliveRequests 설정 여부에 따른 성능차이.
(해당 옵션값을 지정하여 사용중이였기 때문에 이 부분에서 문제가 있는지 확인이 필요했다.)
4번
max 스레드 갯수를 지정해줌에 따른 속도차이 확인.
5번
DB 커넥션 갯수를 조절함에 따른 속도 차이.
2차 테스트
1번 테스트
- 메모리
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
1G | 2024-03-05 | 2241 | 4623 | 5736 | 8960 | 0.00 | 36.1 |
1G | 2024-03-05 | 1845 | 3788 | 4926 | 7752 | 0.00 | 36.5 |
1G | 2024-03-05 | 1904 | 3938 | 5103 | 8194 | 0.00 | 36.6 |
2G | 2024-03-05 | 1663 | 3420 | 4522 | 7461 | 0.00 | 36.8 |
2G | 2024-03-05 | 2247 | 4646 | 6021 | 8839 | 0.04 | 36.1 |
2G | 2024-03-05 | 2146 | 4533 | 5508 | 8772 | 0.04 | 36.1 |
결론
메모리를 다 차지하는것도 아니였고 메모리를 늘려준다고 더 빨라지는건 아닌것 같다. (실질적으로 Visualvm을 사용하여 확인하거나 했을때도 메모리 영역을 더 사용하거나 하는것도 아닌듯 보였다.)
2번 테스트
- MetaspaceSize
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
MetaspaceSize지정 | 2024-03-05 | 2241 | 4623 | 5736 | 8960 | 0.00 | 36.1 |
MetaspaceSize지정 | 2024-03-05 | 1845 | 3788 | 4926 | 7752 | 0.00 | 36.5 |
MetaspaceSize지정 | 2024-03-05 | 1904 | 3938 | 5103 | 8194 | 0.00 | 36.6 |
MetaspaceSize미지정 | 2024-03-05 | 1895 | 3854 | 5094 | 8418 | 0.00 | 36.5 |
MetaspaceSize미지정 | 2024-03-05 | 2125 | 4505 | 5613 | 8106 | 0.00 | 36.3 |
MetaspaceSize미지정 | 2024-03-05 | 1971 | 4222 | 5285 | 8149 | 0.00 | 36.2 |
결론
MetaspaceSize가 속도에 영향은 주지 않지만 특정 영역만큼만 지정해주는게 좋다고 한다.
(만약 잘못짜여진 프로그램이라고 가정하면 지정하지 않는경우 동적으로 얼마든지 늘어나기 때문에 운영체제의 메모리를 모두 차지하는걸 방지하는데 사용된다고 한다.)
3번 테스트
- keepAliveTimeout
- maxKeepAliveRequests
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
maxKeepAliveRequests keepAliveTimeout |
2024-03-05 | 1895 | 3854 | 5094 | 8418 | 0.00 | 36.5 |
maxKeepAliveRequests keepAliveTimeout |
2024-03-05 | 2125 | 4505 | 5613 | 8106 | 0.00 | 36.3 |
maxKeepAliveRequests keepAliveTimeout |
2024-03-05 | 1971 | 4222 | 5285 | 8149 | 0.00 | 36.2 |
없음 | 2024-03-05 | 2194 | 4475 | 5925 | 9034 | 0.00 | 36.2 |
없음 | 2024-03-05 | 2107 | 4347 | 5483 | 8648 | 0.00 | 36.2 |
없음 | 2024-03-05 | 1951 | 4164 | 5272 | 7592 | 0.00 | 36.3 |
결론
속도차이는 없어보인다.
4번 테스트
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
30개 | 2024-03-05 | 2212 | 3659 | 3900 | 4423 | 0.00 | 28.8 |
30개 | 2024-03-05 | 2324 | 4004 | 4281 | 4809 | 0.00 | 35.9 |
30개 | 2024-03-05 | 1770 | 2879 | 3108 | 3634 | 0.00 | 36.7 |
50개 | 2024-03-05 | 2515 | 4408 | 4966 | 6246 | 0.00 | 35.8 |
50개 | 2024-03-05 | 1860 | 3505 | 4047 | 4893 | 0.00 | 36.3 |
50개 | 2024-03-05 | 2092 | 3748 | 4374 | 5650 | 0.00 | 36.2 |
100개 | 2024-03-05 | 2194 | 4475 | 5925 | 9034 | 0.00 | 36.2 |
100개 | 2024-03-05 | 2107 | 4347 | 5483 | 8648 | 0.00 | 36.2 |
100개 | 2024-03-05 | 1951 | 4164 | 5272 | 7592 | 0.00 | 36.3 |
200개(default) | 2024-03-05 | 1739 | 3696 | 4802 | 7489 | 0.00 | 36.6 |
200개(default) | 2024-03-05 | 1765 | 3689 | 4848 | 7698 | 0.00 | 36.5 |
200개(default) | 2024-03-05 | 2280 | 4983 | 6680 | 10585 | 0.00 | 36.0 |
결론
속도상으로는 30개가 더 준수하고 스레드 사용율 또한 좋다. 그러나 해당 스레드 들이 모두 일하는 중이라면 뒤에 대기중인 요청이 일정 수 이상 넘어 갈 수 있고, 그에 따른 요청 거부가 발생할수 있음.
코어수 늘리고 스레드 기준 50 or 100정도로 올린다면 준수한 속도를 보여줄것 같음. (보통은 서버 코어의 배수로 올리는게 좋다고함 4코어면 4의 배수)
참고 문헌
어느 순간에 사용가능한 Thread의 수보다 connection가 더 많으면 어떤 일이 발생하나요? Thread에 의해 실행되지 않는 connection은 어떻게 되나요?
Thread에 의해 실행되지 않는 connection은 worker thread가 사용가능해질 때까지 기다립니다.
Tomcat은 연결을 받아들인 후 "accept queue"를 통해 worker thread로 보냅니다. 이것을 조절하는 Tomcat config 파라미터는 다음과 같습니다.
acceptCount: 모든 요청을 처리하는 Thread가 사용중일 때, 들어오는 connection request를 저장한 queue의 최대 크기. 이 queue가 꽉 찼을 때 발생하는 모든 request는 거절됩니다. 기본 값은 100입니다.
(출처 https://tomcat.apache.org/tomcat-8.0-doc/config/http.html)
5번 테스트
스레드 100개
메모리 1G
기타설정 모두 제외처리.
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
커넥션15 | 2024-03-05 | 2194 | 4475 | 5925 | 9034 | 0.00 | 36.2 |
커넥션15 | 2024-03-05 | 2107 | 4347 | 5483 | 8648 | 0.00 | 36.2 |
커넥션15 | 2024-03-05 | 1951 | 4164 | 5272 | 7592 | 0.00 | 36.3 |
커넥션20 | 2024-03-05 | 3632 | 6979 | 8036 | 11044 | 0.00 | 34.5 |
커넥션20 | 2024-03-05 | 4137 | 7715 | 9009 | 12191 | 0.00 | 34.1 |
커넥션20 | 2024-03-05 | 3637 | 7093 | 8294 | 11434 | 0.00 | 34.4 |
커넥션30 | 2024-03-05 | 5260 | 9419 | 10573 | 12599 | 0.00 | 33.1 |
커넥션30 | 2024-03-05 | 5026 | 9256 | 10189 | 12324 | 0.00 | 33.4 |
커넥션30 | 2024-03-05 | 4454 | 8161 | 9157 | 12377 | 0.00 | 33.8 |
생각의 방향 전환 시작.
WAS문제로 접근하고 설정들을 바꿔봐도 변화가 없어서 다른 방향으로 접근해보기 시작했다.
그럼 API 요청이 들어올때마다 요청정보와 기타 응답에 대한 값을 보기위해 남기는 로그 때문에 속도가 느려진건가 싶었다...? (요청건수가 많다면 그 수만큼 로그가 쌓일것이기 때문에…)
API 서비스 LOG 여부에 따른 속도차이 계산해보기로 했다. 로그 insert하는 부분만제거 한 다음 확인했다.
속도자체는 조금 줄어들었다. 그러나 명확하게 그 부분 때문에 느려진다거나 획기적으로 차이가 나진 않는다고 판단되었다.
수행조건 | 수행날짜 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
로그 O | 2024-03-12 | 1845 | 3899 | 4906 | 7832 | 0.00 | 36.6 |
로그 O | 2024-03-12 | 1685 | 3527 | 4648 | 7673 | 0.00 | 36.7 |
로그 O | 2024-03-12 | 1693 | 3601 | 4709 | 7247 | 0.00 | 36.7 |
로그 X | 2024-03-12 | 1572 | 3166 | 3951 | 6153 | 0.00 | 37.0 |
로그 X | 2024-03-12 | 1431 | 3118 | 4013 | 6210 | 0.00 | 37.0 |
로그 X | 2024-03-12 | 1415 | 2920 | 3796 | 6243 | 0.00 | 37.0 |
개발DB쪽의 cpu가 너무 높게 사용되는듯 보여서 DB를 스펙up 해 보았다.
실제 운영시에 동작하는 DB 1대와 동일하게 4core 8G를 맞춰준다음 체크를 시작한다.
(메모리는 딸리지만 innodb buffer pool에 사용하는 부분이 작을뿐이지 테스트의 경우 한개의 API요청을 계속 동작하게 하는거라 크게 차이는 없을것으로 판단했다.
2300건의 경우 너무 스무스하게 처리됨.
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
1G | 100 | 119 | 126 | 140 | 0.00 | 38.4 |
1G | 99 | 117 | 124 | 137 | 0.00 | 38.4 |
기존에 2300건에서 밀려서 딜레이가 발생하던게 사라졌다.
그럼 운영과 동일한 스펙의 DB라고 가정하고 문제가 되었던 상황인 1분당 평균 3000건에 대해서 어떻게 처리가 되는지 확인하기로 했다.
불필요한 테스트는 제거하고 필요한 옵션들에 대해서 was설정에 따라 속도가 얼마나 변경가능한지 확인을 해보고 싶었다.(WAS쪽 튜닝을 위해)
1번 테스트
- 메모리
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
1G | 1304 | 2793 | 3908 | 6302 | 0.00 | 48.0 |
1G | 1462 | 3200 | 4323 | 7097 | 0.00 | 47.9 |
1G | 1615 | 3335 | 4583 | 6921 | 0.00 | 47.9 |
2G | 1978 | 4106 | 5376 | 8739 | 0.00 | 47.5 |
2G | 1582 | 3617 | 4493 | 6802 | 0.00 | 47.9 |
2G | 1581 | 3515 | 4503 | 6911 | 0.00 | 47.7 |
3번 테스트
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
30개 | 2722 | 4368 | 4620 | 5058 | 0.00 | 46.4 |
30개 | 1562 | 2911 | 3101 | 3549 | 0.00 | 47.6 |
30개 | 1537 | 2826 | 3016 | 3394 | 0.00 | 47.6 |
50개 | 1950 | 3142 | 3545 | 4799 | 0.00 | 47.7 |
50개 | 971 | 1908 | 2289 | 3456 | 0.00 | 48.5 |
50개 | 1319 | 2660 | 3034 | 3884 | 0.00 | 47.9 |
50개 | 1729 | 2963 | 3407 | 4338 | 0.00 | 48.0 |
50개 | 1512 | 2625 | 3076 | 4078 | 0.00 | 48.0 |
100개 | 836 | 1995 | 2672 | 4262 | 0.00 | 48.6 |
100개 | 1376 | 2875 | 3856 | 5793 | 0.00 | 48.1 |
100개 | 1376 | 3049 | 4039 | 6061 | 0.00 | 47.8 |
100개 | 1402 | 3231 | 4285 | 6214 | 0.00 | 47.7 |
200개(default) | 1304 | 2793 | 3908 | 6302 | 0.00 | 48.0 |
200개(default) | 1462 | 3200 | 4323 | 7097 | 0.00 | 47.9 |
200개(default) | 1615 | 3335 | 4583 | 6921 | 0.00 | 47.9 |
4번 테스트
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 에러(%) | 처리속도(/sec) |
커넥션15 | 1376 | 2875 | 3856 | 5793 | 0.00 | 48.1 |
커넥션15 | 1376 | 3049 | 4039 | 6061 | 0.00 | 47.8 |
커넥션15 | 1402 | 3231 | 4285 | 6214 | 0.00 | 47.7 |
커넥션20 | 2242 | 4342 | 5355 | 7520 | 0.00 | 47.1 |
커넥션20 | 2416 | 4687 | 5781 | 8438 | 0.00 | 46.6 |
커넥션20 | 2303 | 4487 | 5543 | 7823 | 0.00 | 46.8 |
커넥션30 | 2217 | 4418 | 5318 | 7242 | 0.00 | 47.4 |
커넥션30 | 1897 | 4241 | 5222 | 6962 | 0.00 | 46.8 |
커넥션30 | 2311 | 4798 | 5691 | 8115 | 0.00 | 46.4 |
여러가지 옵션값을 변경해보아도 피크타임때 견뎌야하는 3000건을 빠르게 소화하지못하고 밀리는 모습을 보이며, DB서버의 CPU사용량을 체크 해 보았을때 80~90% 가까이 찍히는 모습을 보였다…!
DB서버가 2core에서 4core로 올라왔을뿐인데 피크타임에 들어오는 조회에 대한 처리량이 차이가 난다.
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 처리속도(/sec) |
2600건 | 104 | 126 | 135 | 152 | 43.4 |
2800건 | 151 | 246 | 274 | 337 | 47.5 |
2850건 | 176 | 320 | 358 | 431 | 47.6 |
2900건 | 166 | 304 | 354 | 443 | 47.6 |
3000건 | 982 | 1965 | 2601 | 4137 | 49.8 |
3000건 | 1439 | 3118 | 3962 | 6346 | 47.8 |
그렇다면 문제가 발생했던 상황을 무난하게 넘기는 속도가 나오려면 현재 운영DB의 스펙인 4core보다 순간적인 처리를 더 할 수있도록 8core로 가야하는건가..?
(동일하게 1분에 3000건이 넘어가는 경우 cpu사용량이 80~90% 까지 오르기 시작했다.)
테스트를 해 보기로 했다.
DB서버의 스펙을 변경을 해 보았다.
실질적으로 4core때 보다 8core일때 동일한 요청에 대해서 처리 할 수 있는 순간적인 처리량인 TPS가 늘어났다….!
수행조건 | 평균(ms) | 90%(ms) | 95%(ms) | 99%(ms) | 처리속도(/sec) |
3000건 | 84 | 96 | 100 | 110 | 49.9 |
3600건 | 84 | 94 | 98 | 110 | 58.7 |
5000건 | 88 | 99 | 105 | 164 | 83.2 |
5500건 | 785 | 1621 | 2083 | 3237 | 88.9 |
6000건 | 2381 | 4952 | 5518 | 6719 | 91.5 |
최종…? 결론..?
일단 운영환경의 경우 MaxScale을 사용하여 select + insert의 경우 master로 select만 수행하는경우 slave로 분산처리가 되고 있기 때문에 단순하게 DB서버 1대의 스펙인 4core 32G로 바라볼순 없다.
그러나 테스트를 수행해본 4core 8G의 DB스펙 기준으로 테스트를 해본결과.
수치상으로만 봤을때는 분당 3000건에 대해서 평균적으로 발생한 요청을 처리 할 때 DB처리량이 밀리기 시작하는게 맞는듯 보이고… 분산처리가 되어있었기 때문에 그나마 밀리더라도 처리가 된게 아닐까 싶다…
동일한 상황이 발생하더라도 해당 요청들이 빠르게 처리가 되면서 다른 서비스들에 무리가 안 생기려면 8core로 스케일업을 수행한 다음 그 이후 발생하는 문제들에 대해서 추가적인 튜닝이 들어가야 하지 않을까…?(순간적으로 몰릴때는 최대 4300건까지 처리가 되야하기 때문이다.)
어느곳에서 병목지점이 생기는지 모니터링 시스템이 잘 되어 있었다면 좀 더 빨리 접근 할 수 있었을것 같은데 ㅠㅠ 해당 결과를 도출해서 도착하는데 시간이 너무 오래 걸린것 같다.
1차적으로 APM Tool인 Pinpoint를 개발서버에 적용해보고 그 이후 실질적인 개발라인으로 보고 후 운영서버에도 적용해봐야겠다. (어디서 병목지점이 발생하는지 UI상으로 쉽게 확인이 가능해보였다.)
'개발' 카테고리의 다른 글
Connection reset by peer 에러 발생 및 관련 처리_1 (1) | 2024.06.18 |
---|---|
PINPOINT (APM) 2.5.3 버전 설치 및 테스트. (0) | 2024.03.28 |
제이미터(JMeter)로 테스트 환경 구성 및 테스트하기_1 (0) | 2024.03.22 |
제이미터(JMeter)로 테스트 세팅 및 사용법 정리. (1) | 2024.03.22 |
이미지 리사이징 및 기타 가공처리.(Java) (0) | 2024.03.20 |