Rails 앱이 느리게 동작하나요?
간단한 뷰 하나를 불러오는 데 몇 초씩 걸린다면, 파고들 가치가 있는 문제입니다.
원인은 데이터베이스 호출이 너무 많거나, 실행 속도가 느린 메서드일 수 있습니다. 아니면 누군가 코드에 넣어두고 잊어버린 성능 저하 루프일 가능성도 있죠.
앱의 병목 지점을 찾는 데 도움이 되는 도구는 매우 다양합니다. 몇 주 전에는 rbtrace에 대해 소개했는데요. New Relic의 rpm 젬 역시 앱 속도 개선에 큰 도움이 되었습니다.
하지만 제가 가장 선호하는 성능 문제 탐색 도구는 훨씬 더 강력합니다. 기본 설치만으로 코드가 무엇을 하고 있는지 보여주고, 여기에 플러그인을 추가하면 그 힘이 배가됩니다. 앱의 성능 문제를 눈으로 직접 확인할 수 있게 해주기 때문에, 느려진 앱을 더 빠르게 발견하고 수정할 수 있습니다.
제가 가장 아끼는 Rails 프로파일러
제가 가장 좋아하는 Rails 성능 도구는 바로 rack-mini-profiler입니다. 이 젬을 앱에 추가하면 모든 페이지에 작은 인디케이터가 표시됩니다. 화면에는 다음과 같이 나타납니다:

이 박스를 클릭하면 패널이 확장되면서 다양한 유용한 정보를 확인할 수 있습니다. 어떤 SQL 문이 실행되었는지, 각 부분 템플릿(partial) 렌더링에 얼마나 걸렸는지 등이 그 예입니다:

MiniProfiler는 각 페이지가 로드되는 데 걸리는 시간을 항상 상기시켜 줍니다. 덕분에 앱의 성능에 대한 감각을 자연스럽게 익힐 수 있습니다. 어떤 페이지가 느리고 어떤 페이지가 빠른지 직관적으로 파악하게 되고, 평소보다 비정상적으로 오래 걸리는 페이지도 금방 알아차립니다. 그리고 그 순간, 기억이 생생할 때 바로 수정 작업에 착수할 수 있습니다.
MiniProfiler는 사실 더 많은 일을 할 수 있습니다. 단, 먼저 flamegraph 젬을 설치해야 합니다.
설치를 마치면 앱 성능을 들여다보는 완전히 새로운 방법이 열립니다.
플레임그래프(Flamegraph): 이름처럼 재미있는 도구
플레임그래프는 다음과 같이 생겼습니다:

이름의 유래가 딱 보이시죠?
rack-mini-profiler 젬과 flamegraph 젬을 설치한 후에는 모든 요청에 대해 플레임그래프를 확인할 수 있습니다. HTTP 파라미터로 pp=flamegraph만 추가하면 됩니다:
https://www.example.com/restaurants?pp=flamegraph
플레임그래프가 나타나면 확대·축소하고 스크롤하면서 흥미로운 지점들을 마음껏 탐색할 수 있습니다.
플레임그래프의 각 "층(layer)"은 스택 트레이스(stack trace)의 한 줄에 해당합니다:

그리고 가로축은 시간을 나타냅니다. 즉, 그래프의 맨 왼쪽이 요청이 시작된 시점, 맨 오른쪽이 요청이 종료된 시점입니다.
확실히 멋져 보이긴 하는데, 플레임그래프로 대체 무엇을 할 수 있을까요?
플레임그래프 활용 방법
가로축(X축)이 시간을 나타내기 때문에, 앱이 어느 구간에서 병목 현상을 겪는지 아주 명확하게 파악할 수 있습니다. 폭이 가장 넓은 층일수록 실행 시간이 오래 걸렸다는 의미입니다. 따라서 이 영역이 가장 먼저 살펴봐야 할 대상이며, 이곳을 개선하면 가장 큰 성능 향상 효과를 얻을 수 있습니다.
앱은 뷰 렌더링에 얼마나 많은 시간을 쓰고 있나요? 컨트롤러 액션에서는? 데이터베이스 조회에는? 부분 템플릿 렌더링에는?
이 모든 것을 시각적으로 아주 쉽게 확인할 수 있습니다:

플레임그래프가 보여주는 또 하나의 유용한 신호가 있습니다:
아래 이미지처럼 높이가 거의 비슷한 뾰족한 스파이크(spike)들이 여러 개 보이시나요?

이런 패턴은 대개 N+1 쿼리 문제를 의미합니다. 어딘가에 includes가 빠져 있거나, 같은 API를 반복해서 여러 번 호출하고 있는 것이죠. includes를 추가하면 플레임그래프가 다음과 같이 깔끔하게 바뀝니다:

N+1 SQL 쿼리는 대부분의 성능 분석 도구에서 비교적 쉽게 발견할 수 있습니다. 비슷한 형태의 SQL 호출만 찾으면 되니까요. 하지만 SQL이 아닌 N+1 문제, 예컨대 같은 API를 과도하게 반복 호출하는 경우는 훨씬 잡아내기 어렵습니다. 로깅 환경이 잘 갖춰져 있지 않다면 더욱 그렇죠.
반면 플레임그래프를 사용하면 이런 문제들이 한눈에 들어옵니다.
신경 쓰지 않아도 되는 부분
플레임그래프는 정보량이 방대해서 처음 접하면 압도당하기 쉽습니다. 온갖 정보를 한꺼번에 받아들여야 하는 듯한 느낌이 들죠. 그렇다면 무엇을 무시해도 될까요?
보통은 그래프의 맨 아래층과 맨 위층은 건너뛰어도 괜찮습니다. 저는 그래프 중간, 혹은 위쪽 4분의 1 지점부터 탐색을 시작합니다. 직접 작성한 애플리케이션 코드는 대개 그 부근에 위치하기 때문입니다.
그래프의 최상단은 주로 ActiveRecord나 IO 관련 코드가 차지하고, 최하단은 Rails 프레임워크 코드가 차지하므로, 우리가 작성한 코드가 중간쯤에 있는 것이 자연스럽습니다.
혹시 플레임그래프를 사용해 보셨나요? 최적화해야 할 지점을 찾는 데 정말 훌륭한 도구입니다. 꼭 한번 사용해 보세요! Gemfile에 rack-mini-profiler와 flamegraph 젬을 추가하기만 하면 됩니다. 코드에 대해 얻을 수 있는 통찰의 깊이에 놀라게 될 것입니다.