最近、Railsアプリケーション開発でもReact.jsやVue.jsなどを使ったフロント開発の案件が増えてきました。 比較的規模が大きなシステムでは
- リリース前にどの程度の高負荷まで耐えられるか
- リリース後でもステージング環境でどの程度の高負荷まで耐えられるか
を事前に知りたい(もしくは、POやお客さんから依頼がある)ケースが少しずつ出てくるかと思います。
JMeterを使ったActionCable の負荷テストの設定を行ったので、設定内容とその背景を書いていきます。
- JMeterを使ってActionCableのテストを作るメリット
- 環境
- JMeterにJMeter WebSocket Samplersをインストール
- ①Rails側の設定
- ②JMeter側の設定
- 負荷テスト実行
- 参考資料
JMeterを使ってActionCableのテストを作るメリット
ActionCableの負荷テストをする方法は色々ありますが、Rubyでスクリプトを書いたり、ruby-jmeterやgatling他の負荷テストツールを使う場合と比較し、以下の観点で総合的にメリットが大きいと感じたため、JMeterを使うことにしました。
- 古くからあって安定している(遅いけど)
- => 途中で落ちたりしにくいので、うまく動かずはまるリスクが低い
- 情報量が多く、設定がしやすい
- => どんな挙動をするのか事前に想定を置いてテストを書きやすい
- そこそこ複雑なシナリオをテストできる
- => 適用できるシステムが多く、設定ファイルを他の案件にも再利用しやすい
- jmeter-serverを使うことで、複数端末からの攻撃にスケールが容易である
- => 実運用の想定に近い負荷テストの実行が可能
- GUIでグラフが表示できる
- => 早くテスト結果を把握できることで、チューニングとテストの再実行が容易になる
環境
JMeterにJMeter WebSocket Samplersをインストール
以下の記事を参考にインストールしてみてください。 simple-minds-think-alike.hatenablog.com
ちなみに今回使用したJMeter Pluginは「WebSocket Samplers by Peter Doornbosch version 1.2.1」です。
①Rails側の設定
既にActionCableを使ったアプリケーションがある想定で、JMeterの負荷テストを実施するために追加が必要な設定(リクエストオリジンの設定)だけを書いておきます。
リクエストオリジンの設定
以下のようにリクエストオリジンを設定することによってCSRF対策を回避しました。
まずは、ローカルでの動きをみたいのでconfig/environments/development.rb
に記載します。
config.action_cable.allowed_request_origins = ['https://load-testing.com']
補足
他の箇所としては、以下のように
- パス/cable がマウントされている状態
- HomeChannel#speakを呼び出す
というRails側実装を想定してテストを作りました。
config/routes.rb
Rails.application.routes.draw do # 〜〜〜 mount ActionCable.server => '/cable' end
app/channels/home_channel.rb
class HomeChannel < ApplicationCable::Channel def subscribed stream_from 'home_channel' end def unsubscribed # Any cleanup needed when channel is unsubscribed end def speak ActionCable.server.broadcast 'home_channel', content: Home.all end end
②JMeter側の設定
ここでは、JMeterでActionCable (WebSocket) のテストを行うための説明だけ記載します。 基本的なJMeterのテストの作り方に関しては以下の記事を参考にしてみてください。 simple-minds-think-alike.hatenablog.com
②-1. HTTPヘッダー、クッキーに関する設定
WebSocketで接続するテストを追加する前に、まずは基本的な設定を行っていきます。
リクエストオリジンの設定
次に、先程Rails側で行ったリクエストオリジン許可の設定でリクエストが通るようにHTTPヘッダーの設定を行います。
①HTTP Header Managerを追加
- スレッドグループを右クリック =>「追加」 => 「設定エレメント 」=> 「HTTP Header Manager」を追加
②HTTPヘッダーを設定
- 追加ボタンを押し、以下のように設定しました。
- 名前: 「Origin」
- 値: 「https://load-testing.com」
HTTPクッキーマネージャを追加
セッションを有効にするためにHTTPクッキーマネージャを追加します。 スレッドグループを右クリック => 「追加」 => 「設定エレメント 」=> 「HTTPクッキーマネージャ」を追加
設定変更は必要なく、Cookie Policyは初期の値「standard」のままで大丈夫です。
②-2. WebSocketのテストを追加
ここからは実際にWebSocketでアプリケーションに負荷をかけるテスト項目を追加していきます。 (ここのRequest dataの書き方を調べるのが時間がかかった。。。)
②-2-1. WebSocket Connectionを開く
スレッドグループを右クリック => 「追加」 => 「サンプラー」 => 「WebSocket Open Connection」を追加
以下はdevelopment環境で確認した際の設定ですが、Rails側の設定に合わせてPathには「/cable」を指定しました。
※この図では「シンプルコントローラ」という何の制御も行わないJMeterの要素の中に入れています。(コメントを記載するためのものです。)
この設定で、以下のエンドポイントにアクセスし、WebSocket通信を開くようになります。 ws://localhost:3000/cable
②-2-2. チャネルをサブスクライブする
Rails側で実装したHomeChanelをサブスクライブする動きを作ります。 スレッドグループを右クリック => 「追加」 => 「サンプラー」 => 「WebSocket Single Write Sampler」を追加
Data: はTextを選択し
Request data: {"command":"subscribe","identifier":"{\"channel\":\"HomeChannel\"}"}
を指定します。
②-2-3. Heartbeatする
ActionCableのコネクションを開くとクライアント側から3秒ごとにHeartbeatを送るようになるので、その動きも作ってみます。
スレッドグループを右クリック => 「追加」 => 「サンプラー」 => 「WebSocket Ping/Pong」を追加
Behaviorに「ping/pong」を選択します。
②-2-4. 発信する
最後にクライアント側から発信(Publish)して、ActionCableチャネルのメソッドを実行(BroadCast)されるように動きを作ります。
先程と同様に、 「WebSocket Single Write Sampler」を追加します。
Data: にはTextを選択し
Request data: {"command":"message","identifier":"{\"channel\":\"HomeChannel\"}","data":"{\"action\":\"speak\"}"}
を指定します
負荷テスト実行
Rails側をローカル環境でデバック実行し、JMeterの負荷テストを開始すると
該当メソッドのブレイクポイントが止まり、ログには「Successfully upgraded to WebSocket」と出力されることが確認できます。
JMeter側では、「結果をツリーで表示」リスナーでリクエストを確認し
Response code: 200が返ってきているので、エラーが発生せずに動いていそうです。
また、「WebSocket Single Read Sampler」をWebSocket open connectionやwriter samplerの直後に入れるとActionCableからのレスポンスを確認することができます。
「結果をツリーで確認」リスナーにおいて、以下のようにレスポンスを受け取れていることを確認できます。