Ruby를 Ruby보다 빠르게 만드는 방법: P2 템플릿 엔진 성능 최적화 사례

How I Made Ruby Faster Than Ruby

작성자
HackerNews
발행일
2025년 08월 18일

핵심 요약

  • 1 P2는 Ruby 코드를 효율적인 HTML 생성 코드로 컴파일하여 ERB/ERubi와 동등한 수준의 성능을 달성한 새로운 Ruby HTML 템플릿 라이브러리입니다.
  • 2 초기 P2의 성능 병목 현상은 보간된 문자열 푸시, 불필요한 예외 처리, 문자열 동결 부재, 비효율적인 HTML 이스케이프 방식에서 비롯되었습니다.
  • 3 정적/동적 HTML 분리, 단일 백트레이스 처리, 문자열 동결, ERB::Escape.html_escape 사용 등의 최적화를 통해 P2는 기존 대비 2배 이상 빨라졌습니다.

도입

이 문서는 Ruby 프로그래밍 언어에서 HTML 템플릿 생성 성능을 최적화하는 방법을 다루며, 특히 저자가 개발한 새로운 HTML 템플릿 라이브러리 P2의 성능 개선 과정을 상세히 설명합니다. P2는 ERB 템플릿과 유사하게 HTML 내에 Ruby 코드를 삽입하는 방식이지만, 템플릿 소스 코드를 효율적인 Ruby 코드로 컴파일하여 HTML을 생성하는 독특한 접근 방식을 사용합니다. 이는 기존의 Phlex, Papercraft, Ruby2html과 같은 다른 Ruby Gem들과 차별화되는 지점입니다. 본 글은 P2의 초기 성능 문제를 진단하고, 이를 ERB 및 ERubi와 대등한 수준으로 끌어올리기 위해 적용된 다양한 최적화 기법 및 그 결과를 공유합니다.

P2 템플릿은 Ruby Proc으로 표현되며, #render 메소드 호출 시 자동으로 컴파일되어 HTML을 생성하는 코드를 실행합니다. 이 과정은 다음과 같은 단계로 이루어집니다.

P2 템플릿의 작동 방식

  • 코드 변환 과정: P2는 Sirop Gem을 사용하여 템플릿의 소스 코드를 Prism AST(추상 구문 트리)로 파싱합니다. 이후 TagTranslator 클래스를 통해 CallNode와 같은 AST 노드를 사용자 정의 TagNode로 변환하여 HTML 태그를 나타냅니다. 이 변환된 AST는 다시 Ruby 소스 코드로 역변환됩니다.
  • HTML 생성 방식: HTML 코드는 즉시 생성되지 않고, 보류 중인 HTML 조각들의 배열에 저장됩니다. 정적 문자열은 하나의 버퍼 푸시로 연결되고, 동적 부분은 적절히 이스케이프된 후 별도로 푸시됩니다.

성능 최적화 배경 및 문제점 진단

P2 초기 버전은 ERB나 ERubi에 비해 성능이 만족스럽지 못했습니다. 주요 성능 저하 요인은 다음과 같았습니다. * 보간된 문자열 푸시: 동적 값을 포함하는 보간된 문자열을 버퍼에 한 번에 푸시하는 방식은 각 부분을 개별적으로 푸시하는 것보다 느렸습니다. 이는 임시 문자열 생성 오버헤드 때문입니다. * 불필요한 rescue: 생성된 코드에 포함된 rescue 절은 특히 중첩된 템플릿에서 상당한 오버헤드를 유발했습니다. * 문자열 동결 부재: Proc으로 평가될 때 리터럴 문자열이 기본적으로 동결되지 않아 할당 오버헤드와 GC(가비지 컬렉션) 압력이 증가했습니다. * 비효율적인 HTML 이스케이프: CGI.escape_html 사용이 ERB::Escape.html_escape보다 느렸습니다.

적용된 최적화 기법 및 결과

이러한 문제점을 해결하기 위해 다음과 같은 변경 사항이 적용되었습니다. * 정적 HTML 문자열과 동적 부분의 분리된 푸시. * 생성된 코드에서 rescue 절을 제거하고, Proc#render에서 백트레이스 변환을 한 번만 수행. * 컴파일된 코드 상단에 # frozen_string_literal: true 매직 코멘트를 추가하여 모든 정적 HTML 콘텐츠를 동결된 문자열로 만듦. * CGI.escape_html 대신 ERB::Escape.html_escape 사용.

이러한 최적화 후 P2는 ERB 및 ERubi와 거의 동일한 성능을 보였습니다. 초기 벤치마크에서 ERubi보다 약 3배 느렸던 P2는 이제 ERB와 ERubi와 대등한 수준이 되었으며, 컴파일되지 않은 Papercraft나 Phlex보다 약 10배 빠른 성능을 보여주었습니다. 이는 컴파일 방식이 템플릿 생성 성능에 미치는 긍정적인 영향을 명확히 보여줍니다.

결론

P2의 코드 생성 방식에 적용된 최적화는 초기 버전 대비 2배 이상의 성능 향상을 가져왔으며, 이는 Ruby가 느린 언어가 아니라 효율적으로 코드를 작성하면 매우 빠를 수 있음을 입증합니다. 본문에서 논의된 Ruby-to-Ruby 컴파일 기법은 HTML 템플릿 생성뿐만 아니라 다른 DSL(Domain Specific Language)이나 다양한 용도로 확장될 잠재력을 가지고 있습니다. 이러한 접근 방식은 Ruby 개발의 성능 한계를 극복하고 더 효율적인 애플리케이션 개발을 가능하게 할 중요한 시사점을 제공합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

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