Rails 성능 저하의 진짜 원인: 데이터베이스 연결 풀 스레드 고갈 해결 사례

Most Rails Performance Advice Is Outdated - Here's What Actually Fixed Ours | Write A Catalyst

작성자
알 수 없음
발행일
2026년 01월 16일

핵심 요약

  • 1 초기에는 Rails 프레임워크 문제로 오인되었던 성능 저하의 실제 원인은 ActiveRecord 데이터베이스 연결 풀의 스레드 고갈이었습니다.
  • 2 Puma의 최대 스레드 수(16)와 ActiveRecord 연결 풀 크기(기본 5)의 불일치가 병목 현상을 초래했으며, 이는 `config/database.yml`의 `pool` 설정을 조정하여 해결되었습니다.
  • 3 연결 풀 크기를 Puma의 최대 스레드 수에 맞춰 16으로 증가시킨 후, 평균 응답 시간이 650ms에서 220ms로 급감하며 애플리케이션 성능이 즉시 개선되었습니다.

도입

Rails 애플리케이션에서 발생하는 성능 저하는 종종 프레임워크 자체의 한계로 오인되기 쉽습니다. 본 사례 연구는 CPU 및 메모리 사용량은 정상임에도 불구하고 애플리케이션 응답 시간이 급격히 증가하는 미스터리한 지연 현상을 겪었던 경험을 공유합니다. 초기에는 YJIT, GC 튜닝, Redis 캐싱 등 일반적인 성능 개선 조치들을 시도했으나, 근본적인 문제 해결에는 실패했습니다. 이는 성능 문제의 원인을 잘못 진단했을 때 발생할 수 있는 시행착오를 보여줍니다.

성능 저하의 미스터리 및 오진

애플리케이션은 부하가 없음에도 불구하고 응답 시간이 지속적으로 증가하는 현상을 겪었습니다. 서버의 CPU와 메모리 사용률은 낮았지만, 레이턴시 그래프는 급격히 상승했습니다. 초기 진단에서는 다음과 같은 일반적인 성능 개선 방안을 시도했습니다.

  • YJIT 활성화: 부분적인 개선은 있었으나 근본적인 해결책은 아니었습니다.

  • GC 튜닝: 미미한 성능 향상에 그쳤습니다.

  • Redis 캐싱: 정상적으로 작동하고 있었으며, 문제의 원인이 아니었습니다.

  • 인프라 증설: 이미 충분히 오버프로비저닝된 상태였습니다.

이러한 노력에도 불구하고 레이턴시 스파이크, 타임아웃, 사용자 불만은 지속되었습니다.

문제의 핵심: 스레드 고갈

Datadog APM 추적 중 ActiveRecord::ConnectionTimeoutError 발생 횟수가 증가하는 것을 발견했습니다. 이는 데이터베이스 연결 풀 내 스레드 고갈을 시사하는 결정적인 단서였습니다.

  • Rails 기본 설정: ActiveRecord의 기본 연결 풀 크기는 5였습니다.

  • Puma 설정: Puma는 최대 16개의 스레드를 사용하도록 구성되어 있었습니다.

즉, 최대 16개의 스레드가 단 5개의 사용 가능한 데이터베이스 연결을 기다리는 상황이 발생했으며, 대부분의 스레드는 유휴 상태로 대기하고 있었습니다. 이러한 상황에서는 아무리 캐싱이나 GC 최적화를 해도 성능 병목 현상을 해결할 수 없었습니다.

해결책 및 결과

문제 해결을 위해 config/database.yml 파일에서 pool 설정을 Puma의 최대 스레드 수와 일치하도록 조정했습니다. yaml # config/database.yml production: adapter: postgresql pool: 16 timeout: 5000 이후 Puma를 동일한 스레드 설정으로 재시작했습니다 (puma -t 4:16).

단 하나의 설정 변경으로 인해 백로그가 거의 즉시 해소되었습니다.

  • 평균 레이턴시: 650ms에서 220ms로 급감했습니다.

  • CPU 활용률: 정상적으로 상승하며 애플리케이션이 활성화되었습니다.

추가 프로파일링 결과, 연결 타임아웃은 더 이상 발생하지 않았고 APM 추적에서도 스레드가 유휴 상태로 대기하는 대신 활성화된 상태를 유지하는 것이 확인되었습니다. 이는 복잡한 코드 변경이나 프레임워크 교체 없이, 기본적인 관찰과 정확한 진단을 통해 얻어진 효과적인 해결책이었습니다.

결론

본 사례는 "Rails가 느리다"는 일반적인 인식이나 프레임워크의 한계를 탓하기 전에, 시스템 구성 요소 간의 정렬(concurrency alignment)이 얼마나 중요한지 강조합니다. 많은 성능 문제는 화려하지 않은 연결 풀 스레드 고갈과 같은 기본적인 구성 오류에서 비롯될 수 있습니다. 성능 디버깅은 단순히 구문을 조정하는 것이 아니라, 실제 부하에서 시스템이 어떻게 동작하는지 면밀히 관찰하고, 직감보다는 측정 지표를 신뢰하는 데서 시작됩니다. 궁극적으로 프레임워크는 설정이 잘못된 부분을 자동으로 수정할 수 없으며, 정확한 측정과 진단이 성능 확장성의 핵심임을 시사합니다.

댓글 0

로그인이 필요합니다

댓글을 작성하거나 대화에 참여하려면 로그인이 필요합니다.

로그인 하러 가기

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!