性能测试

Tio handler

测试方式

通过 apache benchmark 工具进行压力测试

测试环境

JDK 信息:

java version "1.8.0_361" Java(TM) SE Runtime Environment (build 1.8.0_361-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)

硬件信息

CPU

root@ping-Inspiron-3458:/data/apps/tio-boot-web-hello# cat /proc/cpuinfo
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 69
model name	: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
stepping	: 1
microcode	: 0x26
cpu MHz		: 800.000
cache size	: 3072 KB
physical id	: 0
siblings	: 4
core id		: 0
cpu cores	: 2
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d
vmx flags	: vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit srbds mmio_unknown
bogomips	: 4788.83
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:

processor	: 1
vendor_id	: GenuineIntel
cpu family	: 6
model		: 69
model name	: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
stepping	: 1
microcode	: 0x26
cpu MHz		: 800.000
cache size	: 3072 KB
physical id	: 0
siblings	: 4
core id		: 1
cpu cores	: 2
apicid		: 2
initial apicid	: 2
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d
vmx flags	: vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit srbds mmio_unknown
bogomips	: 4788.83
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:

processor	: 2
vendor_id	: GenuineIntel
cpu family	: 6
model		: 69
model name	: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
stepping	: 1
microcode	: 0x26
cpu MHz		: 900.000
cache size	: 3072 KB
physical id	: 0
siblings	: 4
core id		: 0
cpu cores	: 2
apicid		: 1
initial apicid	: 1
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d
vmx flags	: vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit srbds mmio_unknown
bogomips	: 4788.83
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:

processor	: 3
vendor_id	: GenuineIntel
cpu family	: 6
model		: 69
model name	: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
stepping	: 1
microcode	: 0x26
cpu MHz		: 993.483
cache size	: 3072 KB
physical id	: 0
siblings	: 4
core id		: 1
cpu cores	: 2
apicid		: 3
initial apicid	: 3
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d
vmx flags	: vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit srbds mmio_unknown
bogomips	: 4788.83
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:

内存

root@ping-Inspiron-3458:/data/apps/tio-boot-web-hello# cat /proc/meminfo
MemTotal:        8041976 kB
MemFree:         3803364 kB
MemAvailable:    5479804 kB
Buffers:          142520 kB
Cached:          1787836 kB
SwapCached:            0 kB
Active:           882008 kB
Inactive:        2998216 kB
Active(anon):       4836 kB
Inactive(anon):  2033560 kB
Active(file):     877172 kB
Inactive(file):   964656 kB
Unevictable:         136 kB
Mlocked:               0 kB
SwapTotal:       9675772 kB
SwapFree:        9675772 kB
Dirty:                28 kB
Writeback:             0 kB
AnonPages:       1950008 kB
Mapped:           372608 kB
Shmem:             88524 kB
KReclaimable:     108528 kB
Slab:             207488 kB
SReclaimable:     108528 kB
SUnreclaim:        98960 kB
KernelStack:        6896 kB
PageTables:        11652 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    13696760 kB
Committed_AS:    4024676 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       50672 kB
VmallocChunk:          0 kB
Percpu:             3776 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      293152 kB
DirectMap2M:     4864000 kB
DirectMap1G:     3145728 kB

测试代码

开源地址

tio-boot-web-helloopen in new window

核心代码

pom.xml

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <tio.boot.version>1.5.6</tio.boot.version>
    <lombok-version>1.18.30</lombok-version>
    <hotswap-classloader.version>1.2.3</hotswap-classloader.version>
    <final.name>web-hello</final.name>
    <main.class>com.litongjava.tio.web.hello.HelloApp</main.class>
  </properties>
  <dependencies>
    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>tio-boot</artifactId>
      <version>${tio.boot.version}</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>${lombok-version}</version>
      <optional>true</optional>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2</artifactId>
      <version>2.0.12</version>
    </dependency>

    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>jfinal-aop</artifactId>
      <version>1.2.5</version>
    </dependency>
  </dependencies>

启动类

package com.litongjava.tio.web.hello;

import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.TioApplication;

@AComponentScan
public class HelloApp {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    TioApplication.run(HelloApp.class,args);
    long end = System.currentTimeMillis();
    System.out.println((end - start) + "ms");
  }
}

HelloHandler


import java.util.HashMap;
import java.util.Map;

import com.litongjava.tio.boot.http.TioRequestContext;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.tio.utils.resp.RespVo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HelloHandler {
  public HttpResponse hello(HttpRequest request) {
    log.info(request.getRequestLine().toString());
    Map<String, String> data = new HashMap<>();
    RespVo respVo = RespVo.ok(data);
    return TioRequestContext.getResponse().setJson(respVo);
  }
}

配置类

package com.litongjava.tio.web.hello.config;

import java.io.IOException;

import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.aop.annotation.AInitialization;
import com.litongjava.tio.boot.context.TioBootConfiguration;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.http.server.router.RequestRoute;
import com.litongjava.tio.web.hello.handler.HelloHandler;

@AConfiguration
public class WebHelloConfig implements TioBootConfiguration {

  @Override
  @AInitialization
  public void config() throws IOException {
    HelloHandler helloHandler = new HelloHandler();

    RequestRoute r = TioBootServer.me().getRequestRoute();
    r.add("/hello", helloHandler::hello);
  }

}

测试过程

1.模拟 10 并发,每秒 10 个请求

ab -c10 -n100000 http://localhost/hello

2.模拟 10 并发,每秒 10 个 keep-alive 请求

ab -c10 -n100000 -k http://localhost/hello

测试结果

1.模拟 10 并发,每秒 10 个请求 测试结果

root@ping-Inspiron-3458:~# ab -n1000000 -c10 http://127.0.0.1/hello
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100000 requests
Completed 200000 requests
Completed 300000 requests
Completed 400000 requests
Completed 500000 requests
Completed 600000 requests
Completed 700000 requests
Completed 800000 requests
Completed 900000 requests
Completed 1000000 requests
Finished 1000000 requests


Server Software:        -io
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /hello
Document Length:        3 bytes

Concurrency Level:      10
Time taken for tests:   415.179 seconds
Complete requests:      1000000
Failed requests:        0
2xx responses:          1000000
Total transferred:      234000000 bytes
HTML transferred:       3000000 bytes
Requests per second:    2408.60 [#/sec] (mean)
Time per request:       4.152 [ms] (mean)
Time per request:       0.415 [ms] (mean, across all concurrent requests)
Transfer rate:          550.40 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.5      0      15
Processing:     0    4  38.1      2   11457
Waiting:        0    3  38.0      2   11457
Total:          0    4  38.1      3   11458
ERROR: The median and mean for the initial connection time are more than twice the standard
       deviation apart. These results are NOT reliable.

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      4
  75%      4
  80%      4
  90%      5
  95%      7
  98%     13
  99%     36
 100%  11458 (longest request)

1. 基本信息

  • Server Software: 服务器软件名称 (t-io)。如果是自定义服务器可能没有具体名称。
  • Server Hostname: 测试目标服务器的主机名或 IP 地址(这里是 127.0.0.1)。
  • Server Port: 服务器的端口号(这里是 80)。
  • Document Path: 请求的 URL 路径(这里是 /hello)。
  • Document Length: 请求返回的文档大小(这里是 3 bytes,表示返回内容只有 3 个字节)。

2. 负载配置

  • Concurrency Level: 并发连接数,测试中每次请求发送的并发数量(这里是 10)。
  • Time taken for tests: 测试总耗时(这里是 415.179 seconds)。
  • Complete requests: 成功完成的请求数(这里是 1000000)。
  • Failed requests: 失败的请求数(这里是 0,表示没有失败请求)。
  • 2xx responses: 2xx 状态码的响应数(这里 1000000,表明所有响应都是 2xx)。
  • Total transferred: 从服务器传输的总字节数(这里是 234000000 bytes)。
  • HTML transferred: 传输的 HTML 内容字节数(这里是 3000000 bytes,即请求返回的文档长度)。
  • Requests per second: 平均每秒处理的请求数(这里是 2408.60 [#/sec])。
  • Time per request: 每个请求的平均响应时间(并发请求条件下,单个请求的平均时间为 4.152 ms)。
  • Transfer rate: 数据传输速率(以每秒千字节表示,这里是 550.40 Kbytes/sec)。

3. 连接时间分布

  • Connection Times (ms): 各个请求在不同阶段的响应时间统计:
    • min: 最小时间。
    • mean: 平均时间。
    • median: 中位数(50% 的请求在这个时间以内完成)。
    • max: 最大时间。
    • Connect: 建立连接时间。
    • Processing: 服务器处理请求的时间。
    • Waiting: 等待服务器响应的时间。
    • Total: 完整请求的总时间。

4. 响应时间分布百分比

  • 这个部分显示在不同百分位数下,处理完请求所需的时间。例如:
    • 50% 的请求在 3 ms 内完成。
    • 95% 的请求在 7 ms 内完成。
    • 100% 的请求最长为 11458 ms(表示服务器中有些请求可能需要更长的处理时间)。

5. 错误提示

  • ERROR: 在连接时间部分中,报告显示均值和中位数的差异较大(均值与标准差相差过大),提示结果可能不可靠。这个问题通常是由于部分请求异常导致的,如某些长时间未响应的请求。

2.模拟 10 并发,每秒 10 个 keep-alive 请求

root@ping-Inspiron-3458:~# ab -n1000000 -c10 -k http://127.0.0.1/hello
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100000 requests
Completed 200000 requests
Completed 300000 requests
Completed 400000 requests
Completed 500000 requests
Completed 600000 requests
Completed 700000 requests
Completed 800000 requests
Completed 900000 requests
Completed 1000000 requests
Finished 1000000 requests


Server Software:        t-io
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /hello
Document Length:        3 bytes

Concurrency Level:      10
Time taken for tests:   163.772 seconds
Complete requests:      1000000
Failed requests:        0
2xx responses:          1000000
Keep-Alive requests:    1000000
Total transferred:      188001000 bytes
HTML transferred:       3000000 bytes
Requests per second:    6106.05 [#/sec] (mean)
Time per request:       1.638 [ms] (mean)
Time per request:       0.164 [ms] (mean, across all concurrent requests)
Transfer rate:          1121.04 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       2
Processing:     0    2   3.6      1     668
Waiting:        0    2   3.6      1     668
Total:          0    2   3.6      1     668

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      2
  75%      2
  80%      2
  90%      3
  95%      4
  98%      5
  99%      6
 100%    668 (longest request)


分析一下这个报告

总体信息:

  • 总请求数: 1000000 (100 万次请求)
  • 并发数: 10 (每次并发发送 10 个请求)
  • 总时间: 163.772 秒 (完成所有请求所花的时间)
  • 失败请求: 0 (没有请求失败,表明服务器在处理这次测试时没有出现问题)
  • 2xx 响应: 1000000 (所有请求都返回非 2xx 状态码)
  • Keep-Alive 请求: 1000000 (使用了 HTTP Keep-Alive 机制)

性能指标:

  • 每秒请求数: 6106.05 [#/sec] (平均每秒处理 6106.05 个请求)
  • 平均每个请求处理时间: 1.638 毫秒 (这是处理单个请求的平均时间)
  • 并发下的每个请求处理时间: 0.164 毫秒 (并发条件下,每个请求的处理时间分摊下来是 0.164 毫秒)
  • 传输速率: 1121.04 Kbytes/sec (服务器每秒传输的字节数)

响应时间的详细信息:

  • 连接时间:
    • 最小:0 毫秒
    • 平均:0 毫秒 (连接时间几乎是瞬时的,表明服务器和客户端之间的网络连接速度很快)
    • 最大:2 毫秒
  • 处理时间:
    • 最小:0 毫秒
    • 平均:2 毫秒 (请求在服务器端的处理时间)
    • 最大:668 毫秒 (最长处理时间是 668 毫秒,表明某些请求的处理耗时较长)
  • 等待时间:
    • 平均:2 毫秒 (等待服务器响应的时间)
  • 总时间:
    • 最小:0 毫秒
    • 平均:2 毫秒 (从请求发出到响应完成的总时间)
    • 最大:668 毫秒

百分比分布:

这个部分表示不同百分比的请求在特定时间范围内完成:

  • 50% 的请求 在 1 毫秒内完成
  • 66% 的请求 在 2 毫秒内完成
  • 75% 的请求 在 2 毫秒内完成
  • 80% 的请求 在 2 毫秒内完成
  • 90% 的请求 在 3 毫秒内完成
  • 95% 的请求 在 4 毫秒内完成
  • 98% 的请求 在 5 毫秒内完成
  • 99% 的请求 在 6 毫秒内完成
  • 100% 的请求 在 668 毫秒内完成 (最长的请求时间)

结论:

  • 服务器性能非常好,大部分请求都能在 1-2 毫秒内处理完成,只有少数请求处理时间较长(最大 668 毫秒)。
  • 平均每秒处理 6106 个请求,表现相当不错,适合高并发场景。
  • 100% 的请求都返回了非 2xx 状态码,这意味着这些请求可能没有正常返回成功响应(可能是 3xx 重定向或 4xx/5xx 错误)。这个需要进一步检查服务器的响应代码,确认是否有错误或重定向发生。