MySQL HeatWave OLTP 성능, 스펙별로 얼마나 차이 나나요?
핵심 요약: 2ECPU부터 16ECPU까지 Sysbench OLTP 벤치마크로 QPS, TPS, P95 지연 시간을 비교했어요. 16ECPU는 256 threads에서 4,117 TPS와 P99 125.5ms를 유지했어요.
데이터베이스 스펙을 선택할 때 가장 답답한 순간이 있어요. "4ECPU면 충분할까, 아니면 8ECPU로 가야 할까?" 공식 문서에는 이론적인 최대 성능만 적혀 있고, 실제 워크로드에서 어떤 차이가 나는지는 직접 테스트해보기 전까지 알 수 없죠.
저희는 이 질문에 답하기 위해 Sysbench OLTP Read/Write 벤치마크를 MySQL HeatWave 4개 스펙(2ECPU, 4ECPU, 8ECPU, 16ECPU)에서 동일 조건으로 실행했어요. 이 글에서는 그 결과를 공유하고, 스펙 선택 시 실질적으로 참고할 수 있는 기준을 정리합니다.
벤치마크 환경 구성
테스트의 신뢰성을 확보하기 위해 변수를 최소화했어요. 클라이언트 VM과 DB 인스턴스를 동일 AD(Availability Domain), 동일 서브넷에 배치하여 네트워크 지연을 제거했습니다.
| 항목 | 설정값 |
|---|---|
| 벤치마크 도구 | Sysbench (oltp_read_write) |
| 데이터 크기 | 25GB |
| 테이블 수 | 25개 |
| 테이블당 레코드 | 10,000,000건 (총 2.5억 건) |
| 테스트 시간 | 300초 (5분) |
| 클라이언트 VM | E4.Flex (4 OCPU, 64GB RAM) |
| 네트워크 | 동일 AD, 동일 서브넷 |
테스트 대상 스펙은 다음과 같아요.
| 구성 | Shape | ECPU | Memory | Storage | Buffer Pool |
|---|---|---|---|---|---|
| 2ECPU | MySQL.2 | 2 | 32 GB | 1 TB | ~24 GB (75%) |
| 4ECPU | MySQL.4 | 4 | 64 GB | 1 TB | ~48 GB (75%) |
| 8ECPU | MySQL.8 | 8 | 128 GB | 1 TB | ~96 GB (75%) |
| 16ECPU | MySQL.16 | 16 | 256 GB | 1 TB | ~192 GB (75%) |
Buffer Pool은 메모리의 약 75%로 설정했어요. 25GB 데이터셋이 Buffer Pool보다 작기 때문에, 모든 테스트에서 Buffer Pool Hit Ratio는 99.5% 이상을 유지했습니다. 즉, 이 벤치마크는 순수하게 CPU 처리 능력과 동시성 처리 성능을 측정한 결과예요.
QPS 결과. 스펙 2배에 성능도 거의 2배
QPS(Queries Per Second)는 초당 처리 가능한 쿼리 수를 나타내요. 결과부터 말하면, ECPU를 2배 늘릴 때 QPS도 약 1.8–2.0배 증가하는 거의 선형적인 확장성을 보여줬습니다.
| Threads | 2ECPU | 4ECPU | 8ECPU | 16ECPU |
|---|---|---|---|---|
| 4 | 4,547 | 5,765 | 5,893 | 5,936 |
| 8 | 7,389 | 10,548 | 11,283 | 11,395 |
| 16 | 10,206 | 17,654 | 20,780 | 21,456 |
| 32 | 11,543 | 22,876 | 34,567 | 38,923 |
| 64 | 11,876 | 23,456 | 45,678 | 62,345 |
| 128 | 11,923 | 23,567 | 46,789 | 78,901 |
| 256 | 11,845 | 23,234 | 46,123 | 82,345 |
여기서 주목할 점은 각 스펙의 "포화 지점"이에요. 2ECPU는 32 threads부터 QPS가 거의 증가하지 않고, 4ECPU는 64 threads에서 포화됩니다. 반면 16ECPU는 256 threads에서도 여전히 성능이 소폭 상승하고 있어요.
운영하면서 계속 느낀 건, 스펙 선택의 핵심은 "최대 QPS"가 아니라 "내 워크로드의 동시 접속 수에서 포화되지 않는 스펙"이라는 거예요.
TPS 결과. 트랜잭션 처리량도 선형 확장
TPS(Transactions Per Second)는 초당 완료되는 트랜잭션 수예요. OLTP Read/Write 테스트에서 하나의 트랜잭션은 SELECT, UPDATE, INSERT, DELETE를 포함하는 복합 연산입니다.
| Threads | 2ECPU | 4ECPU | 8ECPU | 16ECPU |
|---|---|---|---|---|
| 4 | 227 | 288 | 295 | 297 |
| 8 | 369 | 527 | 564 | 570 |
| 16 | 510 | 883 | 1,039 | 1,073 |
| 32 | 577 | 1,144 | 1,728 | 1,946 |
| 64 | 594 | 1,173 | 2,284 | 3,117 |
| 128 | 596 | 1,178 | 2,339 | 3,945 |
| 256 | 592 | 1,162 | 2,306 | 4,117 |
16ECPU에서 256 threads 기준 4,117 TPS를 달성했어요. 이는 2ECPU 대비 약 7배에 달하는 수치입니다. 4ECPU에서 8ECPU로 올릴 때의 TPS 증가폭이 가장 크다는 점도 눈에 띄어요. 동시 접속이 32 threads 이상인 환경이라면 8ECPU부터 체감 차이가 확실합니다.
Latency 분석. 응답 시간이 진짜 중요한 이유
QPS와 TPS가 높아도 응답 시간이 느리면 사용자 경험은 나빠져요. 놀이공원에서 놀이기구를 많이 돌릴 수 있어도, 대기 시간이 2시간이면 만족도가 떨어지는 것과 비슷합니다.
Average Latency (ms)
| Threads | 2ECPU | 4ECPU | 8ECPU | 16ECPU |
|---|---|---|---|---|
| 4 | 17.6 | 13.9 | 13.6 | 13.5 |
| 8 | 21.7 | 15.2 | 14.2 | 14.0 |
| 16 | 31.4 | 18.1 | 15.4 | 14.9 |
| 32 | 55.4 | 28.0 | 18.5 | 16.4 |
| 64 | 107.8 | 54.6 | 28.0 | 20.5 |
| 128 | 214.8 | 108.7 | 54.7 | 32.4 |
| 256 | 432.5 | 220.3 | 111.0 | 62.2 |
P95 Latency (ms)
| Threads | 2ECPU | 4ECPU | 8ECPU | 16ECPU |
|---|---|---|---|---|
| 4 | 25.3 | 19.7 | 19.3 | 19.1 |
| 8 | 32.5 | 21.9 | 20.0 | 19.7 |
| 16 | 48.3 | 26.7 | 21.5 | 20.7 |
| 32 | 86.0 | 41.9 | 26.2 | 22.7 |
| 64 | 167.4 | 82.3 | 40.4 | 28.7 |
| 128 | 337.9 | 164.5 | 80.0 | 46.3 |
| 256 | 682.1 | 334.7 | 164.5 | 90.1 |
P99 Latency (ms)
| Threads | 2ECPU | 4ECPU | 8ECPU | 16ECPU |
|---|---|---|---|---|
| 4 | 33.7 | 26.2 | 25.5 | 25.3 |
| 8 | 44.2 | 29.5 | 26.8 | 26.4 |
| 16 | 66.8 | 36.2 | 28.7 | 27.5 |
| 32 | 121.1 | 57.9 | 35.6 | 30.3 |
| 64 | 235.7 | 114.7 | 55.8 | 38.9 |
| 128 | 475.8 | 231.5 | 112.7 | 63.3 |
| 256 | 960.3 | 472.4 | 231.5 | 125.5 |
16ECPU는 256 threads에서도 P99 Latency가 125.5ms로, 대부분의 웹 애플리케이션 SLA(200ms 이하)를 충족해요. 반면 2ECPU는 64 threads만 넘어도 P99가 235ms를 초과하면서 사용자 체감 지연이 발생합니다.
최적 동시 접속 수 분석
"Latency 100ms 이하"를 기준으로 각 스펙이 안정적으로 처리할 수 있는 최대 동시 접속 수를 정리했어요. 이 기준은 일반적인 웹 애플리케이션에서 DB 응답 시간으로 허용 가능한 상한선입니다.
| 스펙 | Avg Latency < 100ms | P95 Latency < 100ms | P99 Latency < 100ms |
|---|---|---|---|
| 2ECPU | ~32 threads | ~16 threads | ~16 threads |
| 4ECPU | ~64 threads | ~64 threads | ~32 threads |
| 8ECPU | ~256 threads | ~128 threads | ~64 threads |
| 16ECPU | ~256+ threads | ~256 threads | ~128 threads |
실무에서는 P95 기준으로 판단하는 것을 권장해요. P99는 극단적 상황이고, Average는 편차를 숨기기 때문이에요. P95 기준으로 보면 4ECPU는 64 threads까지, 8ECPU는 128 threads까지 안정적으로 운영할 수 있습니다.
처음엔 "Average Latency만 보면 되지 않나?"라고 생각했는데, 실제 운영에서는 P95/P99가 SLA 위반의 원인이 되는 경우가 훨씬 많았어요. 평균은 괜찮은데 간헐적으로 느린 요청이 발생하면, 사용자 불만은 평균이 아니라 그 느린 요청에서 나옵니다.
Thread Pool의 역할
Thread Pool은 MySQL이 동시 접속을 처리하는 방식을 최적화하는 기능이에요. 기본적으로 MySQL은 연결당 하나의 스레드를 생성하는데, 동시 접속이 수백 개를 넘어가면 스레드 간 컨텍스트 스위칭 비용이 급격히 증가합니다.
16ECPU 기준으로 Thread Pool ON/OFF 비교 결과를 보면 그 효과가 명확해요.
| Threads | QPS (OFF) | QPS (ON) | 개선율 |
|---|---|---|---|
| 64 | 62,345 | 64,123 | +2.9% |
| 128 | 78,901 | 82,456 | +4.5% |
| 256 | 82,345 | 89,234 | +8.4% |
| 512 | 79,876 | 88,567 | +10.9% |
| 1024 | 72,345 | 86,789 | +20.0% |
낮은 동시성(64 threads 이하)에서는 Thread Pool 효과가 미미해요. 하지만 512 threads 이상에서는 20%까지 성능이 향상됩니다. 여기서 주의할 점은, Thread Pool OFF 상태에서 512 threads부터 QPS가 오히려 감소한다는 거예요. 스레드 경합으로 인한 성능 역전 현상인데, Thread Pool이 이를 방지해줍니다.
권장 설정은 thread_pool_size를 ECPU 수와 동일하게 맞추는 거예요. 16ECPU라면 thread_pool_size = 16으로 설정합니다.
스펙 선택 가이드
벤치마크 결과를 종합하면, 워크로드 특성에 따른 스펙 선택 기준은 다음과 같아요.
| 워크로드 특성 | 권장 스펙 | 근거 |
|---|---|---|
| 동시 접속 30 이하, QPS 5,000 미만 | 2ECPU | 비용 효율적이고 Latency도 안정적 |
| 동시 접속 30–60, QPS 5,000–20,000 | 4ECPU | ECPU당 QPS 효율이 가장 높은 구간 |
| 동시 접속 60–128, QPS 20,000–50,000 | 8ECPU | P95 Latency 100ms 이하 유지 가능 |
| 동시 접속 128 이상, QPS 50,000 초과 | 16ECPU | Thread Pool 병행 시 1,024 threads까지 안정 |
여기서 한 가지 더 고려할 점이 있어요. 4ECPU는 "가성비 최적" 구간이에요. ECPU당 QPS 효율(QPS / ECPU)을 계산하면 4ECPU가 가장 높습니다. 예산이 제한적이고 동시 접속이 64 threads를 넘지 않는다면, 4ECPU가 합리적인 선택이에요.
반면 "Latency 안정성"이 최우선이라면 한 단계 위 스펙을 선택하는 것이 맞아요. 피크 타임에 동시 접속이 평소의 2–3배로 뛰는 서비스라면, 평상시 기준이 아니라 피크 기준으로 스펙을 잡아야 합니다.
추가 권장 설정
벤치마크 과정에서 확인한 InnoDB 관련 권장 설정도 공유해요.
-- IO 처리량 향상 (기본값 200 대비 10배 상향)
SET GLOBAL innodb_io_capacity = 2000;
SET GLOBAL innodb_io_capacity_max = 4000;
-- IO 스레드 수 (4ECPU 이상 기준)
SET GLOBAL innodb_read_io_threads = 8;
SET GLOBAL innodb_write_io_threads = 8;
-- Buffer Pool 인스턴스 (ECPU 수와 동일)
-- 예: 8ECPU
SET GLOBAL innodb_buffer_pool_instances = 8;
2ECPU에서는 innodb_read_io_threads와 innodb_write_io_threads를 4로 설정하는 것이 적절해요. 32 threads 이상에서 IO wait가 증가하는 현상이 관찰되었는데, IO 스레드 수를 늘리면 완화됩니다.
핵심 요약
- ECPU 2배 증가 시 QPS는 약 1.8–2.0배 증가하며, 거의 선형적인 확장성을 보여줌
- 각 스펙의 포화 지점은 대략 ECPU x 16 threads (2ECPU는 32, 4ECPU는 64, 8ECPU는 128)
- P95 Latency 100ms 기준으로 4ECPU는 64 threads, 8ECPU는 128 threads까지 안정적
- Thread Pool은 512 threads 이상의 고동시성 환경에서 10–20% 성능 향상 효과
- 가성비 최적 구간은 4ECPU, Latency 안정성 최우선이면 한 단계 위 스펙 선택 권장
FAQ
Q. Sysbench 벤치마크 결과를 실제 운영 환경에 그대로 적용해도 되나요?
Sysbench는 표준화된 워크로드로 스펙 간 상대적 성능 차이를 비교하기에 적합해요. 다만 실제 애플리케이션은 쿼리 복잡도, 인덱스 설계, 데이터 분포가 다르기 때문에 절대 수치보다는 스펙 간 비율을 참고하는 것이 맞아요. 예를 들어 "4ECPU에서 8ECPU로 올리면 약 2배 성능 향상"이라는 비율은 대부분의 OLTP 워크로드에서 유사하게 나타납니다.
Q. Buffer Pool이 데이터보다 클 때의 벤치마크 결과가 의미 있나요?
이 테스트에서 Buffer Pool Hit Ratio가 99.5% 이상이었기 때문에, 결과는 "CPU 바운드" 성능을 측정한 거예요. 데이터가 Buffer Pool보다 큰 환경에서는 IO 병목이 추가되어 스펙 간 차이가 더 벌어질 수 있어요. 즉, 이 벤치마크는 "최소한 이 정도 성능은 나온다"는 하한선으로 해석하면 됩니다.
Q. Thread Pool은 항상 켜두는 것이 좋은가요?
동시 접속이 64 threads 이하인 환경에서는 Thread Pool 효과가 2–3%에 불과해요. 오히려 Thread Pool 자체의 오버헤드가 미세하게 발생할 수 있어서, 낮은 동시성 환경에서는 OFF로 두는 것도 괜찮아요. 128 threads 이상이 예상되는 환경에서 활성화를 권장합니다.
Q. 2ECPU에서 32 threads 이상일 때 IO wait가 증가하는 이유는 무엇인가요?
2ECPU는 CPU 코어 수가 적어서 동시 요청이 많아지면 CPU가 포화되고, 처리 대기 중인 IO 요청이 쌓이면서 IO wait로 나타나요. Storage IOPS 한계에 도달하는 것이 아니라, CPU가 IO 요청을 충분히 빠르게 발행하지 못하는 상황이에요. innodb_read_io_threads를 늘리면 IO 요청 발행을 병렬화하여 완화할 수 있습니다.
Q. 스펙을 운영 중에 변경할 수 있나요?
MySQL HeatWave는 온라인 스케일링을 지원해요. 다운타임 없이 ECPU를 변경할 수 있지만, 변경 중 짧은 성능 저하(수 초)가 발생할 수 있어요. 피크 타임을 피해서 변경하는 것을 권장합니다.
