Azure Load Testing に JMeter スクリプトの事前準備が不要なクイックテスト機能が追加されたので使ってみた

2022.06.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

以前、Azure のマネージド JMeter なサービスである Azure Load Testing をご紹介したことがあります。

このサービスを使うためには事前にJMeterスクリプトが必要でした。
JMeterに馴染みがないとこの部分が最初の障壁になりそうな気がしますが、今回のアップデートで事前にスクリプトを準備せずにWebURLと負荷数値を入力するだけですぐにテストを開始することが出来る「Quick test」が追加されましたので試してみました。

本機能は投稿日時点でパブリックプレビューです。
プレビュー機能利用時の使用条件や注意事項はこちらをご確認ください。

Quick test実行

まず、事前にテスト対象のWebサービスは準備済みです。
この記事では App Service を使っていますが、ここの手順は省略します。

今回紹介するQuick test機能はAzure Load Testingの一機能なので、まずAzure Load Testingのリソースは作成しておく必要があります。

Azure Load Testingリソースが作成出来たら、テストを作成します。
作成方法は2つあります。

  • OverviewからQuick testを選択
  • TestsからCreate a quick testを選択

あとは Quick test に必要なパラメータを入力します。
テスト対象のURLと負荷に関する数値をいくつか入力するだけです。
各数値上限値があったり、仮想ユーザーが251以上の場合の挙動などいくつか留意点はあるのですが、この記事では「Quick test簡単だったぜ」を紹介したいのでややこしいところは割愛します。

詳細は以下を確認してください。
クイックスタート: Azure Load Testing を使用してロード テストを作成して実行する | Microsoft Docs

これらのパラメータを入力し、Runでもうすぐにテストが始まります。
そしてすぐにテスト結果が表示されました。なんとこれだけで終わり、お手軽だー。

カスタマイズも可能

簡単なURLベースで一定数負荷かけたいよだけであれば先程の手順で終わりです。
ただ、もう少し詳細にパラメータなど変更したいというケースも多いと思います。

Quick runで作成されたテストはJMeterスクリプトをアップロードして作成したテストと変わらないです。
テストの編集画面からパラメータやエンジンインスタンス数などなど、変更可能です。

また、Quick testを実行するとApache JMeter スクリプトが自動生成されます。
そしてテストの実行ダッシュボードからダウンロード出来ます。

quick_test.jmx

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Azure Load Testing Quickstart" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments">
          <elementProp name="threads_per_engine" elementType="Argument">
            <stringProp name="Argument.name">threads_per_engine</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("threads_per_engine") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="ramp_up_time" elementType="Argument">
            <stringProp name="Argument.name">ramp_up_time</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("ramp_up_time") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="duration_in_sec" elementType="Argument">
            <stringProp name="Argument.name">duration_in_sec</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("duration_in_sec") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="domain" elementType="Argument">
            <stringProp name="Argument.name">domain</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("domain") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="protocol" elementType="Argument">
            <stringProp name="Argument.name">protocol</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("protocol") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="path" elementType="Argument">
            <stringProp name="Argument.name">path</stringProp>
            <stringProp name="Argument.value">${__BeanShell( System.getenv("path") )}</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
        </collectionProp>
      </Arguments>
      <hashTree/>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">${threads_per_engine}</stringProp>
        <stringProp name="ThreadGroup.ramp_time">${ramp_up_time}</stringProp>
        <boolProp name="ThreadGroup.scheduler">true</boolProp>
        <stringProp name="ThreadGroup.duration">${duration_in_sec}</stringProp>
        <stringProp name="ThreadGroup.delay">5</stringProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Homepage" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">${domain}</stringProp>
          <stringProp name="HTTPSampler.port"></stringProp>
          <stringProp name="HTTPSampler.protocol">${protocol}</stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">${path}</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

config.yaml

testName: Get_hoge0612web.azurewebsites.net
testPlan: quick_test.jmx
description: 
engineInstances: 1
env:
- name: domain
  value: hoge0612web.azurewebsites.net
- name: protocol
  value: https
- name: path
  value: ''
- name: threads_per_engine
  value: 10
- name: ramp_up_time
  value: 5
- name: duration_in_sec
  value: 10

さいごに

本日はAzure Load TestingのQuick run試してみました。
これはまた最高なアップデートなんじゃないかなーと思います。

JMeterスクリプトに精通していなくても、まずは「Azure Load Testing から始めてみるか」というユーザーが増えそうな気がしますね。
私の観測範囲では「JMeterはわからんが負荷テストはやらないとな...」というパターン多いはずなので、実際需要はあるんじゃないかと思います。

また、スクリプトのダウンロードが出来るので、カスタマイズ出来ますし、痒いところに手が届かないということのないようなバランスの良い最高なアップデートですね。