<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>性能测试 on 测试开发刚哥</title>
    <link>https://dongfanger.github.io/tags/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</link>
    <description>Recent content in 性能测试 on 测试开发刚哥</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Sun, 18 Jan 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dongfanger.github.io/tags/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Locust性能测试工具核心技术@task和@events</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000018-locustlocust%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF@task%E5%92%8C@events/</link>
      <pubDate>Sun, 18 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000018-locustlocust%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF@task%E5%92%8C@events/</guid>
      <description>Tasks和Events是Locust性能测试工具的核心技术，有了它们，Locust才能称得上是一个性能工具。</description>
    </item>
    <item>
      <title>locustfile中的User类和HttpUser类</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000017-locustlocustfile%E4%B8%AD%E7%9A%84user%E7%B1%BB%E5%92%8Chttpuser%E7%B1%BB/</link>
      <pubDate>Sat, 17 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000017-locustlocustfile%E4%B8%AD%E7%9A%84user%E7%B1%BB%E5%92%8Chttpuser%E7%B1%BB/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;locustfile是什么&#34;&gt;locustfile是什么？&lt;/h1&gt;
&lt;p&gt;locustfile是Locust性能测试工具的用户脚本，描述了单个用户的行为。&lt;/p&gt;
&lt;p&gt;locustfile是个普通的Python模块，如果写作&lt;code&gt;locustfile.py&lt;/code&gt;，那么路径切换到文件所在目录，直接执行命令就能运行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ locust
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果换个名字，那么只能通过&lt;code&gt;-f&lt;/code&gt;参数指定文件名运行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ locust -f locust_files/my_locust_file.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与一般Python模块不同的是：&lt;strong&gt;locustfile必须至少定义一个类，且继承自User类。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&#34;user类&#34;&gt;User类&lt;/h1&gt;
&lt;p&gt;User类表示性能测试的模拟用户，&lt;strong&gt;Locust会在运行时创建User类的实例&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;wait_time属性&#34;&gt;wait_time属性&lt;/h2&gt;
&lt;p&gt;设置等待时间，默认值不等待，立即执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Locust支持4种方式设置wait_time属性&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为了便于理解实际意义，我把源码贴在了下面。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;constant&lt;/code&gt;函数，常量，任务执行完毕等待X秒开始下一任务。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;constant&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;wait_time&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    Returns a function that just returns the number specified by the wait_time argument
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    Example::
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;        class MyUser(User):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            wait_time = constant(3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;lambda&lt;/span&gt; instance&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; wait_time
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;between&lt;/code&gt;函数，区间随机值，任务执行完毕等待X-Y秒（中间随机取值）开始下一任务。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;between&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;min_wait&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; max_wait&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    Returns a function that will return a random number between min_wait and max_wait.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    Example::
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;        class MyUser(User):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            # wait between 3.0 and 10.5 seconds after each task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            wait_time = between(3.0, 10.5)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;lambda&lt;/span&gt; instance&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; min_wait &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;random&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;max_wait &lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt; min_wait&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;constant_pacing&lt;/code&gt;函数，自适应，若任务耗时超过该时间，则任务结束后立即执行下一任务；若任务耗时不超过该时间，则等待达到该时间后执行下一任务。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;constant_pacing&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;wait_time&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    Returns a function that will track the run time of the tasks, and for each time it&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    called it will return a wait time that will try to make the total time between task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    execution equal to the time specified by the wait_time argument.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    In the following example the task will always be executed once every second, no matter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    the task execution time::
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;        class MyUser(User):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            wait_time = constant_pacing(1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            @task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            def my_task(self):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;                time.sleep(random.random())
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    If a task execution exceeds the specified wait_time, the wait will be 0 before starting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    the next task.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;    &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;wait_time_func&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;hasattr&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;_cp_last_run&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_wait_time &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; wait_time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_run &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; time&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; wait_time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;else&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            run_time &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; time&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_run &lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_wait_time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_wait_time &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; wait_time &lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt; run_time&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_run &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; time&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;_cp_last_wait_time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; wait_time_func
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自定义&lt;code&gt;wait_time&lt;/code&gt;方法，比如每次等待时间1秒2秒3秒递增：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;MyUser&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;User&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    last_wait_time &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;wait_time&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;last_wait_time &lt;span style=&#34;color:#0550ae&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;last_wait_time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Python技术栈性能测试工具Locust入门</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000016-locustpython%E6%8A%80%E6%9C%AF%E6%A0%88%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7locust%E5%85%A5%E9%97%A8/</link>
      <pubDate>Fri, 16 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000016-locustpython%E6%8A%80%E6%9C%AF%E6%A0%88%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7locust%E5%85%A5%E9%97%A8/</guid>
      <description>Locust是一款Python技术栈的开源的性能测试工具。Locust直译为蝗虫，寓意着它能产生蝗虫般成千上万的并发用户：</description>
    </item>
    <item>
      <title>性能测试指标TP99，比平均响应时间更需要关注</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000015-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%8C%87%E6%A0%87tp99%E6%AF%94%E5%B9%B3%E5%9D%87%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E6%9B%B4%E9%9C%80%E8%A6%81%E5%85%B3%E6%B3%A8/</link>
      <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000015-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%8C%87%E6%A0%87tp99%E6%AF%94%E5%B9%B3%E5%9D%87%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E6%9B%B4%E9%9C%80%E8%A6%81%E5%85%B3%E6%B3%A8/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;什么是tp99&#34;&gt;什么是TP99？&lt;/h1&gt;
&lt;p&gt;TP是Top Percentile的首字母缩写，TP99是指“前百分之九十九”，用来表示满足百分之九十九的网络请求所需的最低耗时。&lt;/p&gt;
&lt;p&gt;该怎么理解？举个简单例子，下图是100次请求的响应时间走势图：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e47a6fabaec14c8ebef5d085f0fa0399.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;第23次请求的响应时间为600ms，其他请求的响应全部为1ms，这个走势图也就是常说的“尖刺”。我们来计算一下：&lt;/p&gt;
&lt;p&gt;①平均响应时间&lt;/p&gt;
&lt;p&gt;平均响应时间 = 所有请求响应时间之和 / 请求次数，等于6.99ms&lt;/p&gt;
&lt;p&gt;②TP99&lt;/p&gt;
&lt;p&gt;TP99 = 把响应时间从小到大排列，取第99%那个位置的值，等于1ms&lt;/p&gt;
&lt;h1 id=&#34;为什么tp99更需要关注&#34;&gt;为什么TP99更需要关注？&lt;/h1&gt;
&lt;p&gt;平均响应时间受极端值的影响较大，因为出现1个尖刺，平均响应时间几乎是TP99的7倍！&lt;/p&gt;
&lt;p&gt;TP99更能反映大多数请求的情况，通过TP99为1ms可以知道，应用系统对于大多数请求，都能在1ms内响应，整体性能达标。而对于尖刺，我们可以通过走势图的MAX来发现，单独进行分析。&lt;/p&gt;
&lt;p&gt;在JMeter的Aggregate Report中，有3个字段：90% Line、95% Line、99%Line&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/de01b3cdbe37490f8dff7a9d105d28b5.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;其实就是指TP90、TP95、TP99。此外，在实际工作中，我们还会关注TP999，三个九，也就是99.9%。关注TP多少，取决于我们对性能的要求怎么样，我们希望应用系统满足多少请求。如果对性能要求不高，关注TP90就够了，允许10%请求出现波动。如果对性能要求很高，则需要关注TP999，99.9%请求都能够快速响应。&lt;/p&gt;</description>
    </item>
    <item>
      <title>你的下一个压测工具可以是nGrinder</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000014-ngrinder%E4%BD%A0%E7%9A%84%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%8E%8B%E6%B5%8B%E5%B7%A5%E5%85%B7%E5%8F%AF%E4%BB%A5%E6%98%AFngrinder/</link>
      <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000014-ngrinder%E4%BD%A0%E7%9A%84%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%8E%8B%E6%B5%8B%E5%B7%A5%E5%85%B7%E5%8F%AF%E4%BB%A5%E6%98%AFngrinder/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;ngrinder小众而实用&#34;&gt;nGrinder小众而实用&lt;/h1&gt;
&lt;p&gt;nGrinder在GitHub的star有1.6k，相比于JMeter6.4k来说，要少很多。在测试资料中，关于压测工具也是以JMeter居多，几乎没有专门针对nGrinder的学习资料。nGrinder既然这么小众，那为什么还要学它呢？因为听说咱们&lt;strong&gt;公司的压测平台，底层就是用的nGrinder&lt;/strong&gt;，对于企业级应用来说，nGrinder还是很实用的，正如它的介绍：“Enterprise level performance testing solution based on The Grinder”。&lt;/p&gt;
&lt;p&gt;nGrinder有以下特点：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1cc334dacd5b43a18998748c60aaeccd.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;我们编写压测脚本用到的就是第一个特点提到的Groovy脚本，跟Java语法类似，可以无成本切换。&lt;/p&gt;
&lt;h1 id=&#34;设计理念&#34;&gt;设计理念&lt;/h1&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/4a5323e837144767bf9b77159c816859.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;ngrinder架构&#34;&gt;nGrinder架构&lt;/h1&gt;
&lt;p&gt;nGrinder系统架构如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/a492956cd0794cd68032605a2318fbb3.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;nGrinder的底层是Grinder，基于Grinder的console和agent，nGrinder封装成了controller和agent：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;controller 提供了Web页面创建测试脚本和配置运行策略，这是nGrinder比较突出的特色了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;agent 虚拟用户生成器，创建压测负载。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当用户创建test后，会先创建一个console，AgentControllerServer会根据console分配相应的agent，AgentControllerServer管理着agent pool，负责agent的创建和释放。然后console将test脚本和资源多个已分配的agent，并控制整个test flow直到测试结束。测试结束后，agent会回收至AgentControllerServer以便其他test使用，console也会回收至ConsoleManager。&lt;/p&gt;
&lt;p&gt;nGrinder和Ginder最大的不同之处在于，nGrinder在controller中保留了多个console实例和agent。每个console都是跟其他console隔离的，能并发运行。&lt;/p&gt;
&lt;p&gt;不像其他压测工具在测试时，会保留agent以确保用户执行test时agent是可用的，也就是“预占”agent。nGrinder只有在真正测试执行时，动态分配agent，这个方案是nGrinder最独特的架构设计。它保证了多个压测任务能并发执行，并发上限只取决于空闲的agent数量。&lt;/p&gt;
&lt;p&gt;nGrinder3.1版本以前是单机架构的，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/ddc8a508a37a4721a9af652d9fc8a7b3.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;1、nGrinder使用SVNkit，即svn server，来管理脚本文件。svn仓库存放在&lt;code&gt;${NGRINDER_HOME}&lt;/code&gt;目录。&lt;/p&gt;
&lt;p&gt;2、nGrinder使用EhCache缓存，提升DB和SVN查询性能。&lt;/p&gt;
&lt;p&gt;3、nGrinder使用Spring Security保证安全，并使用Atlassian支持扩展。&lt;/p&gt;
&lt;p&gt;nGrinder3.1版本之后，支持集群：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/3f38396937d14876b2ef552c3c50cb71.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;1、集群中所有console共享同样的DB和文件系统，并指向NFS共享的同一个&lt;code&gt;${NGRINDER_HOME}&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;2、每个controller有它自己的&lt;code&gt;${NGRINDER_EX_HOME}&lt;/code&gt;，存放特殊配置和日志。&lt;/p&gt;
&lt;p&gt;3、所有controller相互复制EhCache，让某些数据在集群中都是可见的。&lt;/p&gt;
&lt;h1 id=&#34;ngrinder技术栈&#34;&gt;nGrinder技术栈&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Client层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Bootstrap、Bootstrap-slider、Jquery、Jquery Validate、Datatables、Select2、JqPlot、CodeMirror。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;FreeMarker、Spring Security、Spring MVC、GSon、SVNKit Dav。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Grinder、Atlassian Plugin Framework、Spring、EhCache。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Spring Data、H2、Cubrid、Liquibase、SVNKit。&lt;/p&gt;
&lt;h1 id=&#34;快速入门&#34;&gt;快速入门&lt;/h1&gt;
&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;
&lt;p&gt;在GitHub Release下载war包：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/naver/ngrinder/releases&#34;&gt;https://github.com/naver/ngrinder/releases&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/4549b3e0373b4d3c9a31f4a41d21cdfe.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;执行命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;java -jar ngrinder-controller-&lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;version&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;.war
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问&lt;code&gt;http://localhost:8080/&lt;/code&gt;即可。&lt;/p&gt;
&lt;p&gt;但是由于nGrinder需要占用大量内存，最好加上额外参数：&lt;/p&gt;</description>
    </item>
    <item>
      <title>JMeter扩展Java请求</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000013-jmeterjmeter%E6%89%A9%E5%B1%95java%E8%AF%B7%E6%B1%82/</link>
      <pubDate>Tue, 13 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000013-jmeterjmeter%E6%89%A9%E5%B1%95java%E8%AF%B7%E6%B1%82/</guid>
      <description>本文将通过WebRTC本地音视频流压测脚本，来说明JMeter如何扩展Java请求。</description>
    </item>
    <item>
      <title>JMeter响应断言够用了</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000012-jmeterjmeter%E5%93%8D%E5%BA%94%E6%96%AD%E8%A8%80%E5%A4%9F%E7%94%A8%E4%BA%86/</link>
      <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000012-jmeterjmeter%E5%93%8D%E5%BA%94%E6%96%AD%E8%A8%80%E5%A4%9F%E7%94%A8%E4%BA%86/</guid>
      <description>JMeter断言用来对服务器的响应数据进行验证，其中的响应断言基本能完成大多数的验证工作，但是JMeter还是提供了适用于多个不同场景的断言元件，一共16个，如下图所示：</description>
    </item>
    <item>
      <title>JMeter定时器设置延迟与同步</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000011-jmeterjmeter%E5%AE%9A%E6%97%B6%E5%99%A8%E8%AE%BE%E7%BD%AE%E5%BB%B6%E8%BF%9F%E4%B8%8E%E5%90%8C%E6%AD%A5/</link>
      <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000011-jmeterjmeter%E5%AE%9A%E6%97%B6%E5%99%A8%E8%AE%BE%E7%BD%AE%E5%BB%B6%E8%BF%9F%E4%B8%8E%E5%90%8C%E6%AD%A5/</guid>
      <description>JMeter定时器一般用来设置延迟与同步。它的作用域和优先级如下：</description>
    </item>
    <item>
      <title>JMeter逻辑控制器完整介绍</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000010-jmeterjmeter%E9%80%BB%E8%BE%91%E6%8E%A7%E5%88%B6%E5%99%A8%E5%AE%8C%E6%95%B4%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000010-jmeterjmeter%E9%80%BB%E8%BE%91%E6%8E%A7%E5%88%B6%E5%99%A8%E5%AE%8C%E6%95%B4%E4%BB%8B%E7%BB%8D/</guid>
      <description>JMeter逻辑控制器可以对元件的执行逻辑进行控制，就像编程一样，实现业务需求。</description>
    </item>
    <item>
      <title>JMeter36个内置函数及11个新增函数介绍</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000009-jmeterjmeter36%E4%B8%AA%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0%E5%8F%8A11%E4%B8%AA%E6%96%B0%E5%A2%9E%E5%87%BD%E6%95%B0%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000009-jmeterjmeter36%E4%B8%AA%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0%E5%8F%8A11%E4%B8%AA%E6%96%B0%E5%A2%9E%E5%87%BD%E6%95%B0%E4%BB%8B%E7%BB%8D/</guid>
      <description>JMeter内置了36个函数，这些函数可以通过函数助手进行编辑和测试。了解这些函数，不仅能提高JMeter的使用熟练度，也有助于知晓测试工具或测试框架通用的函数有哪些，在自主设计时，作为参考借鉴。</description>
    </item>
    <item>
      <title>JMeter四种参数化方式</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000008-jmeterjmeter%E5%9B%9B%E7%A7%8D%E5%8F%82%E6%95%B0%E5%8C%96%E6%96%B9%E5%BC%8F/</link>
      <pubDate>Thu, 08 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000008-jmeterjmeter%E5%9B%9B%E7%A7%8D%E5%8F%82%E6%95%B0%E5%8C%96%E6%96%B9%E5%BC%8F/</guid>
      <description>JMeter参数化是指&lt;strong&gt;把固定的数据动态化&lt;/strong&gt;，这样更贴合实际的模拟用户请求，比如模拟多个不同账号。JMeter一共有四种参数化方式，分别是：</description>
    </item>
    <item>
      <title>JMeter关联陌生又熟悉</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000007-jmeterjmeter%E5%85%B3%E8%81%94%E9%99%8C%E7%94%9F%E5%8F%88%E7%86%9F%E6%82%89/</link>
      <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000007-jmeterjmeter%E5%85%B3%E8%81%94%E9%99%8C%E7%94%9F%E5%8F%88%E7%86%9F%E6%82%89/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;jmeter关联是什么&#34;&gt;JMeter关联是什么&lt;/h1&gt;
&lt;p&gt;JMeter关联，这几个字看着可能会有点陌生，实际上却是工作中经常会做的一件事情，尤其是接口自动化，它指的是把一个接口的响应作为另一个接口的参数，从而&lt;strong&gt;把接口关联起来&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;JMeter关联是通过后置处理器来实现的，本文将介绍两个主流提取器：正则表达式提取器和JSON JMESPath提取器。&lt;/p&gt;
&lt;h1 id=&#34;正则表达式提取器&#34;&gt;正则表达式提取器&lt;/h1&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/ce535876d05748b98a16512d1e2f536e.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;name&#34;&gt;Name&lt;/h2&gt;
&lt;p&gt;最好有业务含义的名称。&lt;/p&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;p&gt;可以为空的注释。&lt;/p&gt;
&lt;h2 id=&#34;apply-to&#34;&gt;Apply to&lt;/h2&gt;
&lt;p&gt;匹配范围。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Main sample and sub-samples&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;匹配当前父取样器及其子取样器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Main sample only&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;仅匹配当前父取样器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sub-samples only&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;仅匹配子取样器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JMeter Variable Name to use&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;匹配JMeter变量。&lt;/p&gt;
&lt;h2 id=&#34;field-to-check&#34;&gt;Field to check&lt;/h2&gt;
&lt;p&gt;匹配响应的字段，共七个选项。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Body&lt;/strong&gt;：主体，最常用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Body(unescaped)&lt;/strong&gt; ：替换了所有的html转义符的响应主体内容，注意html转义符处理时不考虑上下文，因此可能有不正确的转换，不太建议使用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Body as a Document&lt;/strong&gt;：从不同类型的文件中提取文本，注意这个选项比较影响性能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Response Headers&lt;/strong&gt;：响应Headers。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Request Headers&lt;/strong&gt;：请求Headers。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;URL&lt;/strong&gt;：请求URL。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Response Code&lt;/strong&gt;：响应代码，比如200、404返回码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Response Message&lt;/strong&gt;：响应信息，比如“成功”、“OK”字样。&lt;/p&gt;
&lt;h2 id=&#34;name-of-created-variable&#34;&gt;Name of created variable&lt;/h2&gt;
&lt;p&gt;创建的变量名，比如变量名为token，通过&lt;code&gt;${token}&lt;/code&gt;进行访问。&lt;/p&gt;
&lt;h2 id=&#34;regular-expression&#34;&gt;Regular Expression&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;正则表达式。&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;正则表达式可阅读这篇文章进一步了解：&lt;a href=&#34;https://dongfanger.gitee.io/blog/%E6%9C%AA%E5%88%86%E7%B1%BB/001-5%E5%88%86%E9%92%9F%E8%BD%BB%E6%9D%BE%E5%AD%A6%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F.html&#34;&gt;https://dongfanger.gitee.io/blog/未分类/001-5分钟轻松学正则表达式.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;templatei-where-i-is-capturing-group-number-starts-at-1&#34;&gt;Template(&lt;code&gt;$i$&lt;/code&gt; where i is capturing group number, starts at 1)&lt;/h2&gt;
&lt;p&gt;用&lt;code&gt;$$&lt;/code&gt;引用起来，如果在正则表达式中有多个正则表达式（多个括号括起来的），则可以是&lt;code&gt;$1$&lt;/code&gt;、&lt;code&gt;$2$&lt;/code&gt;等等，&lt;code&gt;$1$&lt;/code&gt;指第一个模板，&lt;code&gt;$2$&lt;/code&gt;指第二个模板，依次类推，&lt;code&gt;$0$&lt;/code&gt;指全文匹配，&lt;code&gt;$1$$2$&lt;/code&gt;指同时取第一个和第二个模板。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JMeter100个线程竟然只模拟出1个并发</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000006-jmeterjmeter100%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%AB%9F%E7%84%B6%E5%8F%AA%E6%A8%A1%E6%8B%9F%E5%87%BA1%E4%B8%AA%E5%B9%B6%E5%8F%91/</link>
      <pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000006-jmeterjmeter100%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%AB%9F%E7%84%B6%E5%8F%AA%E6%A8%A1%E6%8B%9F%E5%87%BA1%E4%B8%AA%E5%B9%B6%E5%8F%91/</guid>
      <description>线程组编辑区如下：</description>
    </item>
    <item>
      <title>JMeter测试计划配置项解析</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000005-jmeterjmeter%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E9%85%8D%E7%BD%AE%E9%A1%B9%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000005-jmeterjmeter%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E9%85%8D%E7%BD%AE%E9%A1%B9%E8%A7%A3%E6%9E%90/</guid>
      <description>测试计划（Test Plan），是JMeter目录树的初始根节点，它的编辑区如下：</description>
    </item>
    <item>
      <title>JMeter元件作用域实践指南</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000004-jmeterjmeter%E5%85%83%E4%BB%B6%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000004-jmeterjmeter%E5%85%83%E4%BB%B6%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;从一个问题说起&#34;&gt;从一个问题说起&lt;/h1&gt;
&lt;p&gt;对于以下测试脚本：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/08bb056c95a34670a750060f1e04625a.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;为了能调用进入房间接口，需要从考场接口获取考场token。为了调用考场接口，需要从登陆接口获取登陆token。元件说明如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;学生登录，提取登录&lt;code&gt;${token}&lt;/code&gt;传入下个接口参数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加HTTP Header Manager：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/9f6015fb46ff4c3eba94cf40c38d5841.png&#34;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考场token，提取考场&lt;code&gt;${exam_token}&lt;/code&gt;传入下个接口参数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加HTTP Header Manager：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/4b3a68c97249434aae097fd43cada2f6.png&#34;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入房间&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;貌似挺合理，HTTP Header Manager会给下方的接口添加请求头，运行结果真的如我们所料么？&lt;/p&gt;
&lt;h1 id=&#34;运行顺序&#34;&gt;运行顺序&lt;/h1&gt;
&lt;p&gt;在回答这个问题之前，有必要搞懂JMeter元件的运行顺序，它是由2 个维度来决定的：从上往下和元件类型。&lt;/p&gt;
&lt;p&gt;从上往下，即目录树从上往下。元件类型，分为3类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程组、逻辑控制器。&lt;/li&gt;
&lt;li&gt;取样器。&lt;/li&gt;
&lt;li&gt;配置元件、前置处理器、定时器、后置处理器、断言、监听器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它们的运行顺序如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;配置元件（如果存在）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;前置处理器（如果存在）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定时器（如果存在）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;取样器（如果存在）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;后置处理器（如果存在且取样器的结果不为空）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;断言（如果存在且取样器的结果不为空）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;监听器（如果存在且取样器的结果不为空）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;换句话说，假设我们新建了1个线程，想用这个线程去发请求。&lt;/p&gt;
&lt;p&gt;第一步，初始化配置，比如参数化、设置Header、Cookie等，用到配置元件。&lt;/p&gt;
&lt;p&gt;第二步，可能需要给线程加点参数，比如用户参数，用到前置处理器。&lt;/p&gt;
&lt;p&gt;第三步，在发送请求前可能会等待一段时间，用到定时器。&lt;/p&gt;
&lt;p&gt;第四步，发送请求，用到取样器。&lt;/p&gt;
&lt;p&gt;第五步，可能需要提取响应数据，比如正则表达式提取器、JMESPath提取器，用到后置处理器。&lt;/p&gt;
&lt;p&gt;第六步，验证结果符合预期，用到断言。&lt;/p&gt;
&lt;p&gt;第七步，查看请求响应数据和测试结果，用到监听器。&lt;/p&gt;
&lt;h1 id=&#34;实践指南&#34;&gt;实践指南&lt;/h1&gt;
&lt;p&gt;对于以下所列元件：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/107fe872d0c84a08a81dcb909d80a028.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;JMeter会按以下步骤运行：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;线程组（如果有多个线程组可以在测试计划设置是顺序执行还是同时执行）&lt;/li&gt;
&lt;li&gt;简单控制器（父节点）&lt;/li&gt;
&lt;li&gt;HTTP Cookie管理器（配置元件）&lt;/li&gt;
&lt;li&gt;用户参数（前置处理器）&lt;/li&gt;
&lt;li&gt;Synchronizing Timer（定时器）&lt;/li&gt;
&lt;li&gt;HTTP 请求1（取样器）&lt;/li&gt;
&lt;li&gt;正则表达式提取器（后置处理器）&lt;/li&gt;
&lt;li&gt;响应断言（断言）&lt;/li&gt;
&lt;li&gt;HTTP Cookie管理器（配置元件）&lt;/li&gt;
&lt;li&gt;用户参数（前置处理器）&lt;/li&gt;
&lt;li&gt;Synchronizing Timer（定时器）&lt;/li&gt;
&lt;li&gt;HTTP 请求2（取样器）&lt;/li&gt;
&lt;li&gt;正则表达式提取器（后置处理器）&lt;/li&gt;
&lt;li&gt;响应断言（断言）&lt;/li&gt;
&lt;li&gt;HTTP 请求3（取样器）&lt;/li&gt;
&lt;li&gt;察看结果树（严格来讲是与第 6 步并行，也就是取样器之后）&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;作用域&#34;&gt;作用域&lt;/h1&gt;
&lt;p&gt;其中有个观察作用域实际效果的关键元件：HTTP请求2，它的前后并没有元件，但是也被作用上了。在JMeter中，同一层级的元件具有相同的作用域！&lt;/p&gt;</description>
    </item>
    <item>
      <title>JMeter英文版界面介绍</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000003-jmeterjmeter%E8%8B%B1%E6%96%87%E7%89%88%E7%95%8C%E9%9D%A2%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000003-jmeterjmeter%E8%8B%B1%E6%96%87%E7%89%88%E7%95%8C%E9%9D%A2%E4%BB%8B%E7%BB%8D/</guid>
      <description>JMeter的界面虽然不华丽，但是使用起来还是很便利。本文将基于英文版界面对整个可视区域进行介绍，如果想看中文版，请在菜单栏点击Choose Language切换：</description>
    </item>
    <item>
      <title>JMeter是如何运行施压的</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000002-jmeterjmeter%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%90%E8%A1%8C%E6%96%BD%E5%8E%8B%E7%9A%84/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000002-jmeterjmeter%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%90%E8%A1%8C%E6%96%BD%E5%8E%8B%E7%9A%84/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;运行文件&#34;&gt;运行文件&lt;/h1&gt;
&lt;p&gt;JMeter下载地址为：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jmeter.apache.org/download_jmeter.cgi&#34;&gt;https://jmeter.apache.org/download_jmeter.cgi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最新版本为5.4.1，依赖于Java8+，下载后无需安装，解压即用。解压后的目录和文件如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8882ce2b3e0f46aab689527e19940f07.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bin 二进制文件目录，包括配置文件、启动文件、启动jar包、示例脚本。比如Windows和Linux系统的两个启动脚本：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/90a79cc617a44ecb991bec7a4c75c2cf.png&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;docs API离线帮助文档。&lt;/li&gt;
&lt;li&gt;extras 辅助功能，可用于Ant、Jenkins集成。&lt;/li&gt;
&lt;li&gt;lib lib根目录下存放JMeter基础jar包，lib/ext目录下存放第三方或自定义扩展jar包。&lt;/li&gt;
&lt;li&gt;licenses 证书文本文件。&lt;/li&gt;
&lt;li&gt;printable_docs 离线帮助文档。&lt;/li&gt;
&lt;li&gt;LICENSE 证书说明。&lt;/li&gt;
&lt;li&gt;NOTICE 版权声明。&lt;/li&gt;
&lt;li&gt;README 简介。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;测试计划&#34;&gt;测试计划&lt;/h1&gt;
&lt;p&gt;JMeter以图形界面方式启动后，首先映入眼帘的是左侧的TestPlan，测试计划：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/08391c0919354b15aaf9807d7d60e07f.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;JMeter的UI界面只能同时编辑一个测试计划，如果想再编辑另外一个测试计划，必须再打开一个JMeter界面。这是因为测试计划对应的是.jmx文件！不同的.jmx文件只能在不同的界面中编辑。&lt;/p&gt;
&lt;p&gt;JMeter界面是通过组件拖拽的方式来编写脚本的，脚本的根目录是测试计划。根节点只能有一个，作为根节点，测试计划很适合来做全局配置，比如在User Defined Variables处添加键值对格式的全局变量。&lt;/p&gt;
&lt;p&gt;测试计划是默认节点，JMeter还有另外一个不可缺少的次节点：Thread Group，线程组。&lt;/p&gt;
&lt;h1 id=&#34;多线程&#34;&gt;多线程&lt;/h1&gt;
&lt;p&gt;性能测试工具的目的是用少量电脑产生成百上千个并发请求。多进程和多线程正好能用来实现这个需求，书上有句关于进程和线程的至理名言：“进程是操作系统分配资源的最小单位，线程是程序执行的最小单位”。该如何理解呢？前一句的意思是说，每个应用程序都有对应的进程，按照进程来分配资源，可以使得资源利用最大化，避免浪费。后一句的理解得从一个故事讲起，很久以前，进程拿着资源找CPU执行。CPU一看进程太大，说我处理不了。进程只能拆成多个线程给CPU，不但能执行了，还能在线程之间灵活切换。&lt;/p&gt;
&lt;p&gt;多进程和多线程都可以用来模拟并发请求。JMeter是用Java语言写的程序，运行在JVM虚拟机之上，进程的开销比线程大很多，JVM为了保证足够性能，控制了进程的数量。如果用多线程，单台电脑能提供了负载有限，那么就只能用多线程。JMeter只支持多线程！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;另外一个性能测试工具LoadRunner支持多进程和多线程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;用户即线程&#34;&gt;用户即线程&lt;/h1&gt;
&lt;p&gt;JMeter除了Thread Group，其他地方都是用的另外一个词：User。实际上它们是一个意思，用户就是线程。JMeter的运行原理就是用多个线程来模拟多个用户！以下是简单示例：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/aa6bb9b7be474396862a0b81a3c68463.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;从图中可以看出，有两个线程组，Thread Group 1和Thread Group 2，它们分别定义了自己组内的用户要做的事情。不同线程组做的事情是不一样的，但是同一线程组内部做的事情是一模一样的。我们在写JMeter脚本的时候，实际上是在定义每个用户要做哪些事。当运行脚本的时候，JMeter会启动多个线程，都来执行这个脚本，按照我们写的进行执行。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;由于每个线程启动时间不一样，线程执行时资源环境也有区别，导致线程的执行进度并不完全一致，比如一些线程已经登录完了，另一些线程可能才刚开始登录。后面的文章会给出一些解决办法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;远程运行&#34;&gt;远程运行&lt;/h1&gt;
&lt;p&gt;一台机器提供了线程数量有限，如果想要施压更大的并发，那么就需要多台机器。JMeter天然支持多台机器并发：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/cca61040161c43e8a0d833613f1aa247.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;控制机和负载机本质上没有区别，同一台机器既可以做控制机，也可以做负载机，取决于你的负载设计。控制机的作用是管理多台远程负载机，控制远程负载机脚本运行，收集远程负载机测试结果。负载机是实际产生并发的机器，它们向被测应用系统发起负载。&lt;/p&gt;
&lt;p&gt;运行逻辑如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;远程负载机启动Agent客户端，等待控制机连接。&lt;/li&gt;
&lt;li&gt;控制机连接上远程负载机。&lt;/li&gt;
&lt;li&gt;控制机发送指令到远程负载机启动线程。&lt;/li&gt;
&lt;li&gt;远程负载机运行脚本，回传结果数据。&lt;/li&gt;
&lt;li&gt;控制机收集结果并显示。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;操作步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;远程负载机启动jmeter-server.bat。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在控制机bin\JMeter.properties文件中，修改remote_hosts，添加远程负载机的ip和port，多个远程负载机ip 用逗号分隔，如remote_hosts=192.168.0.1:1664,192.168.0.2:1664。1664是默认RMI端口号（Remote Method Invocation，远程方法调用）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在控制机菜单栏Run执行Remote命令：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/70903ad24ce243368980c6b411ecd767.png&#34;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;如果远程负载机需要参数或jar包，可以手动先把环境准备好，也可以使用自动化工具在脚本运行前从控制机发送到远程负载机。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;小结&#34;&gt;小结&lt;/h1&gt;
&lt;p&gt;本文先从JMeter运行文件讲起，启动后默认有测试计划，建线程组，线程即用户，用多线程来模拟多用户，这就是JMeter运行起来施压的原理。为了解决单台机器负载能力有限的问题，JMeter还提供了远程运行方式，既可以在局域网用多台机器来控制，也可以部署到云服务器上，进行云压测。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JMeter全部组件概览</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000001-jmeterjmeter%E5%85%A8%E9%83%A8%E7%BB%84%E4%BB%B6%E6%A6%82%E8%A7%88/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/000001-jmeterjmeter%E5%85%A8%E9%83%A8%E7%BB%84%E4%BB%B6%E6%A6%82%E8%A7%88/</guid>
      <description>JMeter是性能测试工具，在使用JMeter变多以后，越来越觉得之所以它能成为当今时代最主流测试工具，是因为它太成熟了，举个小例子，编写GET请求的时候，需要把查询参数，也就是?号后面的请求参数添加进去，JMeter竟然有个Add from Clipboard功能，在浏览器复制以后，点这个按钮就填充好了:</description>
    </item>
  </channel>
</rss>
