테스트는 유지 관리가 악몽이 아니며 새로운 기능이 지속적으로 추가되거나 기존 기능이 개선되는 대부분의 잘 작동하는 Rails 애플리케이션의 필수적인 부분입니다. 불행히도 많은 애플리케이션의 경우 프로덕션 환경은 처음으로 과중한 워크로드 또는 상당한 트래픽을 받는 곳입니다. 이러한 테스트는 비용이 많이 들기 때문에 이해할 수 있습니다.
고맙게도 Rails는 단위, 종단 간 및 통합 테스트뿐만 아니라 성능 및 로딩과 관련된 테스트도 잘 지원합니다. 이 기사에서 모든 것을 다루고 애플리케이션의 성능 수준을 테스트하는 도구를 효율적으로 사용하는 방법을 이해하는 데 도움이 되는 몇 가지 실용적인 예를 보여 드리겠습니다.
이 기사는 두 섹션으로 나뉩니다.
-
이론적 — 테스트가 필요한 이유, 우리가 수행할 수 있는 테스트의 종류, 애플리케이션에서 테스트를 수행할 때 필수적인 메트릭을 보여 드리겠습니다.
-
실용적 — 우리는 손을 더럽히고 실제 애플리케이션에 대한 테스트를 작성하여 출력을 얻습니다.
두 섹션을 읽고 나면 다양한 유형의 테스트와 Rails 애플리케이션에서 테스트를 수행하는 방법에 대해 더 깊이 이해할 수 있을 것입니다. 흥미롭게 들립니까? 그런 다음 테스트에 대한 약간의 이론으로 시작하겠습니다.
이론 테스트
테스트는 항상 모든 유형의 애플리케이션 개발에 내재된 부분이어야 합니다. 아직 확신이 서지 않거나 테스트를 아직 작성하지 않았다면 다음과 같은 몇 가지 테스트 주장이 도움이 될 것입니다.
- 깨질 염려 없이 변경 사항 도입 — 이것이 테스트가 필요한 주요 이유입니다. 작은 변경 사항을 적용할 때마다 오류가 없는지 확인하기 위해 전체 앱을 클릭해야 하는 거대한 앱에서 작업한다고 상상해 보십시오. 테스트를 통해 하나의 명령만 실행하면 검증 프로세스가 자동으로 빠르게 진행됩니다.
- 손쉬운 리팩토링 프로세스 — 위에서 테스트는 새로운 기능을 추가하거나 변경할 때 필수적이라고 언급했습니다. 테스트를 진행하면 기존 코드를 더욱 편안하게 개선할 수 있습니다.
- 테스트는 문서 형식 — 잘 작성된 테스트는 애플리케이션의 다양한 기능 세트에 대한 문서 형식이 될 수 있습니다. 기능이 무엇인지 설명할 뿐만 아니라 어떻게 작동해야 하는지도 설명합니다.
- 구현을 재고할 기회 — 테스트를 작성할 때 코드를 구현하려는 방식이 올바르고 합리적인지 다시 생각할 기회가 있습니다. 또한 코드가 예상대로 작동하는지 확인하기만 하면 됩니다.
위의 주장이 모든 앱을 개발하는 동안 테스트를 사용하도록 확신을 주기를 바랍니다. 코드를 테스트해야 하는 이유를 아는 것도 중요하지만 다양한 테스트 유형에 대해 배우는 것도 중요합니다.
다양한 유형의 테스트
Rails 애플리케이션의 성능이 정확하고 인프라가 과부하 상태에서 제대로 작동하는지 확인하기 위해 작성할 수 있는 세 가지 기본 테스트 유형이 있습니다. 이러한 유형은 다음과 같습니다.
- 부하 테스트 — 이 유형의 테스트는 다음 질문에 답합니다. 주어진 기간 동안 시스템이 처리할 수 있는 동시 사용자 수. 웹사이트에서 최고 등급의 제품을 출시하고 수천 명의 사용자가 동시에 주문하기를 원한다고 상상해 보십시오. 적절한 로딩 테스트가 없으면 가장 중요한 시기에 충돌할 위험이 있습니다.
- 스트레스 테스트 — 이 유형의 테스트에서는 시스템이 동시에 처리할 수 있는 사용자 수를 확인하는 데 중점을 두지 않고 사용자 제한에 도달했을 때 시스템이 어떻게 작동하는지 확인합니다.
- 성능 테스트 — 이 유형의 테스트는 스트레스 및 부하 테스트의 부모라고 말하고 싶습니다. 이러한 테스트의 주요 목적은 애플리케이션의 코드를 개선하기 위해 어떤 조치를 취할 수 있는 기반이 되는 특정 메트릭 세트를 얻는 것입니다. 잠시 후 이러한 측정항목에 대해 이야기하겠습니다.
즉, 이제 이론 부분의 마지막 단계로 이동할 준비가 되었습니다. Rails 애플리케이션에서 성능 테스트를 수행할 때 어떤 메트릭이 필수적인지 배우는 것입니다. 그 지식이 없으면 테스트 출력을 올바르게 해석하지 못하고 코드를 변경해야 하는지 여부를 결정할 수 없습니다.
중요 지표
받을 수 있는 측정항목 유형은 테스트에 사용하는 도구에 따라 다를 수 있지만 일반적으로 매우 일반적인 측정항목 집합으로 그룹화할 수 있습니다.
- 응답 시간 — 요청이 만들어지고 브라우저에서 응답이 렌더링되는 사이의 시간입니다. 이 측정항목은 사용자가 요청한 정보를 수신하기 전에 얼마나 기다려야 하는지를 보여줍니다. 처리 시간이라고도 합니다.
- 메모리 사용량 — 주어진 요청에 대해 소비된 메모리의 양. 이것은 시스템이 더 빠르게 응답하고 더 적은 리소스를 사용할 수 있도록 코드를 개선할 수 있는 부분을 알려주는 필수 정보입니다.
- 객체 할당 — 높은 메모리 할당은 높은 메모리 사용량과 긴 응답 시간을 유발합니다. 이 측정항목을 통해 코드에서 많은 개체가 할당된 정확한 위치를 확인할 수 있으므로 즉시 검사할 수 있습니다.
테스트할 때 더 많은 메트릭을 가질 수 있지만 이 세 가지가 가장 중요하며 테스트하는 모든 애플리케이션에 유효합니다. 이제 손을 더럽히고 실제 테스트를 작성할 수 있습니다.
연습
테스트할 것이 없으면 테스트를 작성할 수 없습니다. 그렇기 때문에 실습 부분의 첫 번째 단계는 테스트를 작성할 수 있는 간단한 Rails 애플리케이션을 작성하는 것입니다.
샘플 Rails 애플리케이션
나는 Ruby 3.0.1과 Rails 6.1.3.1을 사용할 것이지만 당신이 편안하게 느끼는 어떤 버전을 사용해도 무방하다. Ruby와 Rails가 설치되어 있다면 다음 단계는 애플리케이션의 골격을 만드는 것입니다.
rails new simpleapp -d=postgresql
이 기사의 목적을 위해 사용자 목록이 애완 동물의 이름과 함께 표시되는 앱을 만들 것입니다. 이러한 구조를 통해 성능 테스트를 수행하고 속도 및 변경 사항이 가져올 기타 측정항목에 대한 영향을 확인할 때 더 재미있는 N+1 쿼리를 쉽게 생성할 수 있습니다.
모델을 생성하기 전에 먼저 데이터베이스를 생성하겠습니다.
cd simpleapp/
bin/rails db:create
이제 모델을 생성할 수 있습니다.
rails g model User name:string
rails g model Animal name:string user:references
bin/rails db:migrate
User
에 대한 작은 업데이트 Animal
과의 관계를 반영하는 모델 모델:
class User < ApplicationRecord
has_many :animals
end
이제 db/seeds.rb
에 일부 시드를 추가할 수 있습니다. 파일:
people = {
'Tim' => ['Pinky', 'Rick'],
'Martha' => ['Rudolph'],
'Mark' => ['Niki', 'Miki', 'Bella'],
'Tina' => ['Tom', 'Luna']
}
people.each_pair do |name, pets|
user = User.create(name: name)
pets.each do |pet_name|
user.animals.create(name: pet_name)
end
end
데이터를 데이터베이스에 로드:
bin/rails db:seed
사용자 할당으로 하나의 컨트롤러를 만든 다음 보기에 모든 사용자를 애완 동물의 이름과 함께 나열합니다. 나중에 개선 사항을 측정할 수 있도록 성능 문제를 일으키는 코드를 의도적으로 사용하고 있습니다.
touch app/controllers/home_controller.rb
mkdir app/views/home
touch app/views/home/index.html.erb
컨트롤러는 간단합니다.
class HomeController < ApplicationController
def index
@users = User.all
end
end
또한 보기:
<h1>List</h1>
<ul>
<% @users.each do |user| %>
<li><%= user.name %> (<%= user.animals.count %>)
<ul>
<% user.animals.each do |animal| %>
<li><%= animal.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
마지막 단계는 config/routes.rb
를 업데이트하는 것입니다. 기본 URL을 방문할 때 보고 싶은 내용을 Rails에 알리는 파일:
Rails.application.routes.draw do
root to: 'home#index'
end
JMeter를 사용한 부하 테스트
JMeter는 Apache 소프트웨어 재단에서 만든 오픈 소스 소프트웨어로, 기능 동작을 로드하도록 설계되었습니다. Java로 만든 프로그램이기 때문에 모든 운영 체제에 설치할 수 있습니다. https://jmeter.apache.org/download_jmeter.cgi
에서 파일을 다운로드할 수 있습니다.macOS 시스템에서 작업하는 경우 Homebrew로 JMeter를 쉽게 설치할 수 있습니다.
brew install jmeter
설치 후 다음 명령으로 프로그램을 실행할 수 있습니다.
jmeter
테스트 구성
구성 프로세스는 다음 단계로 구성됩니다.
- 스레드 그룹 추가 - 사용자 수와 각 사용자가 웹사이트를 방문하는 시간 지정
- HTTP 요청 구성 - JMeter가 도달해야 하는 엔드포인트 지정
- 관심 있는 측정항목 설정
이전에 만든 간단한 앱의 기본 페이지에 대한 단일 사용자 요청을 시뮬레이션하는 간단한 테스트 구성을 단계별로 살펴보겠습니다.
스레드 그룹 추가
"테스트 계획"을 마우스 오른쪽 버튼으로 클릭한 후 확장되는 메뉴에서 추가 -> 스레드(사용자) -> 스레드 그룹을 선택합니다.
사용자 수 및 추가 속성 지정:
HTTP 요청 구성
이전 단계에서 생성한 스레드를 마우스 오른쪽 버튼으로 클릭하고 추가 -> 샘플러 -> HTTP 요청:
을 선택합니다.프로토콜, 서버 이름, 포트 및 요청 경로를 구성합니다.
결과 보기 지정
HTTP 요청을 마우스 오른쪽 버튼으로 클릭하고 추가 -> 리스너 -> 결과 트리 보기:
를 선택합니다.테스트 실행
이제 테스트가 구성되었으며 트리거할 수 있습니다. 이렇게 하려면 녹색 재생 버튼을 클릭하기만 하면 됩니다.
보시다시피 애플리케이션은 테스트를 통과했지만 단일 요청에 불과했기 때문에 결과는 뻔했습니다. 이제 사용자 수와 기타 구성 옵션을 실험하여 애플리케이션이 어떻게 작동하는지 확인할 수 있습니다. 내 테스트에서 약 200명의 사용자가 동시에 액세스하기 시작했을 때 간단한 앱이 충돌하기 시작했습니다.
다음 단계
부하 테스트를 수행한 후 애플리케이션의 문제점을 알게 됩니다. 사용자 제한을 이해하면 이제 스트레스 테스트를 수행하여 애플리케이션이 어떻게 작동하는지 확인할 수 있습니다.
Ruby-prof를 사용한 성능 테스트
성능 테스트 기능은 버전 3까지 Rails에 내장되어 있었고 이후 별도의 gem https://github.com/rails/rails-perftest로 추출되었습니다. 최신 버전의 Rails와 함께 사용하는 데 약간의 문제가 있었기 때문에 이 기사에 포함하지 않기로 결정했습니다. 대신 잘 작동하는 ruby-prof 라이브러리를 사용하겠습니다.
평소와 같이 첫 번째 단계는 애플리케이션에 gem을 추가하는 것입니다.
bundle add ruby-prof
구성 프로세스의 두 번째이자 마지막 단계는 config/application.rb
를 업데이트하는 것입니다. 그리고 gem에 미들웨어를 사용하여 라이브러리가 자동으로 요청을 검사하고 이를 기반으로 보고서를 생성할 수 있도록 합니다.
module Simpleapp
class Application < Rails::Application
config.middleware.use Rack::RubyProf, :path => './tmp/profile'
end
end
이제 앱에 액세스할 수 있으며 요청을 수행할 때마다 gem이 새 보고서를 생성합니다. 다음과 같습니다.
구성된 경로(tmp/profile
)에서 찾을 수 있습니다. 우리의 경우. 두 번째 보고서도 생성되며 호출 스택을 보여줍니다. 이는 Rails 애플리케이션에서 성능 문제를 디버깅할 때 매우 유용한 지표이기도 합니다.
cache_classes
및 cache_template_loading
true
로 설정 Rails가 필요한 파일을 로드하려고 할 때 애플리케이션 속도가 느려지고 애플리케이션 메트릭이 압도됩니다.
요약
테스트는 모든 개발 프로세스의 필수적인 부분입니다. 코드가 원하는 대로 작동하는지 확인하는 것은 솔루션의 성능이 좋은지 확인하는 것만큼 중요합니다. 테스트를 건너뛰면 앱의 성능과 사용자의 신뢰에 영향을 미치는 심각한 문제가 발생합니다. 테스트가 그렇게 어렵지 않기를 바랍니다.
이 기사에서는 테스트의 다음과 같은 중요한 측면을 다뤘습니다.
- 코드를 테스트해야 하는 이유
- 다양한 유형의 성능 테스트
- Rails 앱의 성능을 테스트하는 방법
이유와 방법을 알고 있으므로 테스트를 작성하는 것이 왜 중요한지 이제 더 확신할 수 있기를 바랍니다.
로컬뿐만 아니라 프로덕션 또는 스테이징 환경에서도 앱의 성능을 모니터링하는 데 관심이 있다면 AppSignal도 확인해야 합니다.
추신 Ruby Magic 게시물이 언론에 공개되는 즉시 읽고 싶다면 Ruby Magic 뉴스레터를 구독하고 게시물을 놓치지 마세요!