Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Railsのパフォーマンス、ストレス、および負荷テスト

テストは、メンテナンスが悪夢ではなく、新しい機能が一貫して追加されたり、既存の機能が改善されたりする、ほとんどの正常に機能するRailsアプリケーションの不可欠な部分です。残念ながら、多くのアプリケーションにとって、実稼働環境では、初めて大きなワークロードまたは大量のトラフィックが発生します。このようなテストには費用がかかるため、これは理解できます。

ありがたいことに、Railsは、ユニット、エンドツーエンド、統合テストだけでなく、パフォーマンスとロードに関連するテストも適切にサポートしています。これらすべてを記事で取り上げ、アプリケーションのパフォーマンスレベルをテストするツールを効率的に使用する方法を理解するのに役立ついくつかの実用的な例を示します。

この記事は2つのセクションに分かれています:

  • 理論的 —テストが必要な理由、実行できるテストの種類、およびアプリケーションでテストを実行する際に不可欠なメトリックを示します

  • 実用的 —手を汚し、実際のアプリケーションのテストを作成して出力を取得します

2つのセクションを読むと、さまざまなタイプのテストと、Railsアプリケーションでそれらを実行する方法をより深く理解できるようになります。興味深いですね?それでは、テストに関する理論のピンチから始めましょう。

理論でのテスト

テストは常に、あらゆるタイプのアプリケーションの開発に固有の部分である必要があります。それでも確信が持てない場合、またはまだテストを作成していない場合は、テストに関するいくつかの議論が役立ちます。

  • 何かを壊すことを心配せずに変更を導入する —これがテストが必要な主な理由です。小さな変更であっても、変更を加えるたびに何も壊れていないことを確認するために、アプリ全体をクリックする必要がある巨大なアプリで作業していると想像してみてください。テストでは、1つのコマンドを実行するだけで、検証プロセスが自動的かつ高速になります。
  • 簡単なリファクタリングプロセス —新しい機能を追加したり、変更を加えたりする場合は、テストが不可欠であることを前述しました。テストを実施することで、既存のコードをより快適に改善することもできます。
  • テストはドキュメントの形式です —適切に記述されたテストは、アプリケーションのさまざまな機能セットのドキュメントの形式になります。機能が何であるかだけでなく、どのように機能するかについても説明します。
  • 実装を再考する機会 —テストを作成するとき、コードを実装する方法が正しく、合理的であるかどうかをもう一度考える機会があります。また、コードが期待どおりに機能しているかどうかを確認するだけです。

上記の議論が、アプリの開発中にテストを使用することを納得させてくれることを願っています。コードをテストする理由を知ることは不可欠ですが、さまざまな種類のテストについて学ぶことも重要です。

さまざまな種類のテスト

Railsアプリケーションのパフォーマンスが正しく、インフラストラクチャが重いワークロードの下で正常に機能していることを確認するために作成できるテストには、主に3つのタイプがあります。それらのタイプは次のとおりです。

  • 負荷テスト —このタイプのテストは、次の質問に答えます。特定の期間にシステムが処理できる同時ユーザーの数。あなたがあなたのウェブサイトで一流の製品を立ち上げ、何千人ものユーザーが同時に注文したいと思っていると想像してみてください。適切な負荷テストがないと、最も重要な時期にクラッシュする危険があります。
  • ストレステスト —このタイプのテストでは、システムが同時に処理できるユーザー数の検証ではなく、ユーザーの制限に達したときのシステムの動作に焦点を当てます。
  • パフォーマンステスト —このタイプのテストは、ストレステストと負荷テストの親であると言えます。このようなテストの主な目的は、アプリケーションのコードを改善するために何らかのアクションを実行できる特定のメトリックのセットを取得することです。これらの指標については、後ほど説明します。

そうは言っても、これで理論部分の最後のステップに進む準備が整いました。Railsアプリケーションでパフォーマンステストを行うときに不可欠なメトリックを学習することです。その知識がないと、テスト出力を正しく解釈して、コードを変更する必要があるかどうかを判断できません。

重要な指標

受け取ることができる指標の種類は、テストに使用するツールによって異なる場合がありますが、一般的には、かなり一般的な一連の指標にグループ化できます。

  • 応答時間 —要求が行われてから応答がブラウザに表示されるまでの時間。このメトリックは、ユーザーが要求した情報を受け取るまでにユーザーが待機する必要がある時間を示します。処理時間と呼ばれることもあります。
  • メモリ使用量 —指定された要求で消費されたメモリの量。これは、システムがより速く応答し、より少ないリソースを使用できるようにコードを改善できる場所を示しているため、重要な情報です。
  • オブジェクトの割り当て —メモリ割り当てが多いと、メモリ使用量が多くなり、応答時間が長くなります。このメトリックは、多くのオブジェクトが割り当てられているコード内の正確な場所につながる可能性があるため、すぐにそれを調べることができます。

テスト時にさらに多くのメトリックを設定できますが、これら3つが最も重要であり、テストするすべてのアプリケーションで有効になります。これで、手を汚して実際のテストを書くことができます。

練習

テストするものがなければ、テストを書くことはできません。そのため、練習パートの最初のステップは、テストを作成できる単純なRailsアプリケーションを作成することです。

サンプルRailsアプリケーション

私はRuby3.0.1とRails6.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の小さな更新は1つだけです 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

ユーザーの割り当てを使用して1つのコントローラーを作成し、次に、すべてのユーザーとペットの名前を一覧表示します。後で改善を測定できるように、パフォーマンスの問題を引き起こしているコードを意図的に使用しています。

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

テストの構成

構成プロセスは、次の手順で構成されています。

  • スレッドグループの追加—ユーザーの数と各ユーザーがWebサイトにアクセスする時間を指定します
  • HTTPリクエストの設定—JMeterがヒットするエンドポイントを指定します
  • 関心のある指標を設定する

以前に作成したシンプルなアプリのメインページへのシングルユーザーリクエストをシミュレートするために、簡単なテスト構成を段階的に見ていきましょう。

スレッドグループを追加

「テストプラン」を右クリックすると展開されるメニューから、「追加」->「スレッド(ユーザー)」->「スレッドグループ」を選択します。

ユーザー数と追加の属性を指定します:

HTTPリクエストを設定する

前の手順で作成したスレッドを右クリックし、[追加]->[サンプラー]->[HTTPリクエスト]を選択します:

プロトコル、サーバー名、ポート、およびリクエストのパスを構成します。

結果ビューを指定する

HTTPリクエストを右クリックし、[追加]->[リスナー]->[結果ツリーの表示]を選択します:

テストの実行

これでテストが構成され、トリガーできます。これを行うには、緑色の再生ボタンをクリックするだけです:

ご覧のとおり、アプリケーションはテストに合格しましたが、それは1つのリクエストにすぎなかったため、結果は明らかでした。これで、ユーザー数やその他の構成オプションを試して、アプリケーションがどのように動作するかを確認できます。私のテストによると、約200人のユーザーが同時にアクセスを開始すると、シンプルなアプリがクラッシュし始めました。

次のステップ

負荷テストを実行すると、アプリケーションの問題点がわかります。ユーザー制限を理解すると、ストレステストを実行して、アプリケーションがどのように動作するかを確認できます。

Ruby-profを使用したパフォーマンステスト

パフォーマンステスト機能はバージョン3までRailsに組み込まれていましたが、その後、別のgemhttps://github.com/rails/rails-perftestに抽出されました。 Railsの最新バージョンでの使用に問題があったため、この記事には含めないことにしました。代わりに、非常にうまく機能するruby-profライブラリを使用します。

いつものように、最初のステップはアプリケーションに宝石を追加することです:

bundle add ruby-prof

構成プロセスの2番目で最後のステップは、config/application.rbを更新することです。 宝石のミドルウェアを使用して、ライブラリがリクエストを自動的に検査し、それに基づいてレポートを作成できるようにします。

module Simpleapp
  class Application < Rails::Application
    config.middleware.use Rack::RubyProf, :path => './tmp/profile'
  end
end

これでアプリにアクセスできるようになり、リクエストを実行するたびに、gemは新しいレポートを生成します。次のようになります:

これは、構成されたパス(tmp/profile)の下にあります。 私たちの場合には。 2番目のレポートも生成され、コールスタックが表示されます。これは、Railsアプリケーションのパフォーマンスの問題をデバッグするときにも非常に役立つメトリックです。

cache_classesを設定することを覚えておくことが重要です およびcache_template_loading trueへの設定 Railsが必要なファイルを読み込もうとするため、アプリケーションの速度が低下し、アプリケーションのメトリックが圧倒されます。

概要

テストは、すべての開発プロセスの重要な部分です。コードが期待どおりに動作するかどうかを確認することは、ソリューションのパフォーマンスが良好かどうかを確認することと同じくらい重要です。テストをスキップすると、アプリのパフォーマンスとユーザーの信頼に影響を与える深刻な問題が発生します。うまくいけば、テストはそれほど難しくありません。

この記事では、テストの次の重要な側面について説明しました。

  • コードをテストする必要がある理由
  • さまざまな種類のパフォーマンステスト
  • Railsアプリのパフォーマンスをテストする方法

理由と方法がわかっているので、なぜテストを書くことが重要なのかを理解していただければ幸いです。

ローカルだけでなく、本番環境やステージング環境でもアプリのパフォーマンスを監視することに関心がある場合は、AppSignalも確認する必要があります。

P.S。 Ruby Magicの投稿をマスコミから離れたらすぐに読みたい場合は、Ruby Magicニュースレターを購読して、投稿を1つも見逃さないでください。


  1. Byebug、Rails、Powを使用したリモートデバッグ

    byebugをこれまでに見たことがない場合は、チェックすることをお勧めします。これは、Ruby2.x用の優れたデバッガーです。その作者の言葉で: Byebugは、Ruby2用の使いやすく機能豊富なデバッガーです。実行制御に新しいTracePointAPIを使用し、コールスタックナビゲーションに新しいDebug Inspector APIを使用するため、内部のコアソースに依存しません。 C拡張機能として開発されているため、高速です。また、完全なテストスイートがあるため、信頼性があります。 基本的なセットアップは非常に簡単です。宝石をインストールするだけです。 byebugを使用する場合 コー

  2. RailsアプリをテストするためのDockerコンテナを設定する

    Ruby / Rails開発者として、私たちはテストを書くのが大好きです。テストはソフトウェア開発の不可欠な部分です。優れたテストは、高品質のコードを書くのに役立ちます。これらは開発プロセス全体に付加価値をもたらしますが、テストを適切に管理しないと、速度が低下する可能性があります。不適切に管理されているテストの症状の一部を次に示します。 テストの実行には長い時間がかかります。 テストは信頼性が低く、ランダムに失敗します。 テストはマシンによって動作が異なります。 すべてのテストスイートを実行すると、CIの速度が低下します。 このブログ投稿では、コンテナを使用してテストの信頼性を高める方法