Contents

1. 용어

2. 스레드 수와 성능

3. I/O bound 시스템의 적절한 스레드 수 설정

4. EatDa에서의 트러블슈팅 경험


1. 용어

버스트(burst):

  • 어떤 작업이 짧은 시간 동안 집중적으로 수행되는 구간

CPU 버스트:

  • 프로세스가 CPU에서 연속적으로 실행되는 시간 371
    • CPU 버스트는 대부분 8ms 이하의 짧은 시간을 가지고 있다.

IO 버스트:

  • 프로세스가 I/O 작업을 요청하고 대기하는 시간

CPU bound:

  • CPU 연산이 병목인 작업
  • CPU 사용률이 높고 I/O 대기 시간은 적다.
  • 동영상 인코딩, 머신러닝 연산

IO bound:

  • I/O 대기가 병목인 작업
  • CPU는 자주 대기 상태가 되고, I/O 대기 시간이 길다.
  • 웹 서버(API 서버), DB 조회, 네트워크 요청

2. 스레드 수와 성능

2.1 CPU bound

CPU를 최대한 활용하는 것이 중요하다.

  • 스레드 수를 늘려도 성능 향상은 제한적이다.
  • CPU bound 환경에서는 스레드가 CPU 자원을 두고 경쟁하게 되므로, 스레드 수가 많아질수록 컨텍스트 스위칭이 증가하여 오버헤드가 발생한다.

적절한 스레드 수:

  • CPU 코어 수
  • 약간의 여유를 두어 CPU 코어 수 + 1 정도로 설정하기도 한다. (Goetz)

2.2 I/O bound

I/O 대기 동안 CPU를 놀리지 않는 것이 중요하다.

  • 스레드 수를 늘리면 성능 향상이 가능하다.

적절한 스레드 수:

  • 스레드 수 ≈ CPU 코어 수 × (1 + I/O 대기 시간 / CPU 사용 시간)

3. I/O bound 시스템의 적절한 스레드 수 설정

IO bound 시스템에서는 정해진 가이드라인이 없으므로, 여러 상황을 고려해 적절한 스레드 개수를 찾아야 한다.

  • 스레드 수가 많을수록 좋은 것은 아니다.
  • 과도한 스레드는 컨텍스트 스위칭 비용과 메모리 사용량을 증가시킨다.

고려 요소:

  • CPU 코어 수
  • I/O 대기 시간
  • 동시 요청 수
  • 요청 처리 시간
  • 외부 시스템 성능(DB, API)

튜닝 과정:

  1. 모니터링

    • CPU 사용률
    • 요청 처리 시간(latency)
    • 처리량(throughput)
    • 대기 시간(queue length)
  2. 병목 판단

    • CPU 사용률이 높고 latency 증가 → CPU bound
    • CPU 사용률이 낮고 latency 높음 → IO bound
  3. 스레드 수 조정

    • 스레드 수를 점진적으로 증가
    • throughput 증가 여부 확인
    • latency 변화 확인
  4. 임계 지점 탐색

    • throughput 증가가 멈추는 지점 확인
    • latency가 급격히 증가하는 지점 확인
    • CPU 사용률이 포화되는 시점 확인
  5. 최적값 결정

    • throughput은 충분히 확보하면서
    • latency가 안정적인 지점 선택

스레드 수를 늘릴수록 처리량은 증가하지만,

특정 시점 이후에는 latency 증가와 context switching 비용으로 인해 전체 성능이 오히려 저하될 수 있다.


4. EatDa에서의 트러블슈팅 경험

리뷰 생성 API 성능 테스트 과정에서 CPU 사용률이 100%를 찍으며 서버가 다운되는 문제가 발생했다.

초기 분석 결과:

  • CPU 코어가 모두 100% 사용되는 상태
  • 요청 처리 중 이미지 처리 작업이 CPU를 집중적으로 사용

CPU 사용률이 100%에 도달했으며, 이미지 처리 과정에서 CPU-intensive 작업이 병목으로 작용하고 있었다.

4.1 스레드 수 증가 시도

처음에는 스레드 수를 늘리면 성능이 개선될 것이라 예상했다. 하지만 효과는 없었고 오히려 응답 시간이 증가했다.

CPU bound 환경에서 스레드 수 증가:

  • CPU 자원 경쟁 발생
  • 컨텍스트 스위칭 빈도 증가
  • 오버헤드 증가

4.2 비동기 처리 도입

이미지 업로드 작업을 비동기로 분리한 결과:

  • CPU 사용률 100% → 10 ~ 20% 수준으로 감소
  • 요청 처리 안정성 확보
  • dropped 요청 제거

분석:

  • HTTP 요청 스레드가 블로킹되지 않도록 개선
  • 작업이 분산되면서 CPU 사용 패턴이 안정화

비동기 처리로 HTTP 요청 스레드의 블로킹이 제거되면서, 요청 처리 구조가 개선되고 CPU 사용 패턴이 안정화 되었다.

4.3 이미지 최적화 로직 제거(webp, 리사이징)

결과:

  • CPU 사용률↓
  • 응답시간 증가(3.76s → 13.53s)

이미지 최적화 작업(디코딩, 리사이징, 인코딩)이 모두 CPU bound 작업이므로 CPU 사용률은 줄었으나,

  • 이미지 크기 증가
  • 이미지 최적화 로직 제거로 데이터 크기가 증가하면서 네트워크 전송 시간디스크 I/O가 증가

CPU와 I/O는 trade-off 관계이며, 한쪽의 부담을 줄이면 다른 쪽이 병목으로 드러날 수 있다.

4.4 결론

CPU 부담을 줄인다고 성능이 항상 좋아지는 것은 아니다.

병목은 제거되는 것이 아니라, 시스템 내 다른 자원으로 전이된다.