wrk性能测试工具

目录

1. wrk 是什么

2. 它的作用和优势

3. 详细的测试报告

4. 跨平台支持

5. 使用方便

6.wrk在linux安装

7.在 macOS 上,您可以使用Homebrew来安装wrk也可以下载源码make 

8.使用wrk进行简单的性能测试

9.wrk压测复杂场景

示例:

wrk模拟下单请求,执行lua脚本

统计脚本每一个线程执行,lua脚本

10.根据测试结果优化应用性能

代码层面优化:

JVM优化:

架构层面优化:

硬件层面优化:

其他优化:


1. wrk 是什么


wrk 是一个现代的 HTTP 基准测试工具,用于对 Web 服务器进行性能测试和负载测试。它可以模拟大量的并发连接,并测量服务器的响应时间、吞吐量和错误率等指标,帮助开发人员评估和优化 Web 服务器的性能。

2. 它的作用和优势


性能测试: wrk 可以帮助开发人员评估 Web 服务器在高并发情况下的性能表现,发现性能瓶颈和优化空间。
负载测试: 通过模拟大量并发连接,wrk 可以对服务器进行负载测试,以确定服务器在不同负载下的响应能力。
结果分析: wrk 提供详细的测试结果,包括平均响应时间、吞吐量、请求错误率等指标,帮助开发人员分析服务器的性能表现和瓶颈。
wrk 的主要特点和功能介绍:
1. 灵活的配置选项:
可以通过命令行参数灵活地配置并发连接数、测试持续时间、请求方式、请求头、请求体等参数,以满足不同的测试需求。
2. 高性能的并发模拟:
wrk 使用高效的事件驱动模型和多线程并发机制,可以模拟大量的并发连接,以确保测试结果的准确性和可靠性。


3. 详细的测试报告


wrk 提供详细的测试报告,包括平均响应时间、吞吐量、请求错误率等指标,以及请求响应时间分布图表,帮助开发人员全面了解服务器的性能表现。


4. 跨平台支持


wrk 支持在 Linux、Windows 和 macOS 等主流操作系统上运行,具有良好的跨平台兼容性。


5. 使用方便


wrk 的使用方法简单明了,可以通过命令行轻松启动测试,并且提供了丰富的文档和示例,方便开发人员快速上手和定制测试。

6.wrk在linux安装

命令行输入一下命令下载 wrk 源码

git clone https://github.com/wg/wrk.git

随后进入 wrk 目录并进行编译

cd wrk
make

随后将生成一个可执行的 wrk 文件,我们可以把这个文件拷贝到我想要的地方,或者直接拷贝到 bin 目录

cp wrk /usr/local/bin/

7.在 macOS 上,您可以使用Homebrew来安装wrk也可以下载源码make 

brew install wrk
wrk -v或wrk

如果有以下显示,则说明安装成功了 


wrk 4.2.0 [kqueue] Copyright (C) 2012 Will Glozer
Usage: wrk <options> <url>                            
  Options:                                            
    -c, --connections <N>  Connections to keep open   
    -d, --duration    <T>  Duration of test           
    -t, --threads     <N>  Number of threads to use   
                                                      
    -s, --script      <S>  Load Lua script file       
    -H, --header      <H>  Add header to request      
        --latency          Print latency statistics   
        --timeout     <T>  Socket/request timeout     
    -v, --version          Print version details      
                                                      
  Numeric arguments may include a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)

8.使用wrk进行简单的性能测试

下面是一个使用wrk进行简单性能测试的示例:

wrk -t10 -c30 -d2s -T5s --latency http://www.baidu.com

Running 2s test @ http://www.baidu.com
  10 threads and 30 connections
                            平均值     标准差    最大值   正负一个标准差占比 
      线程统计 Thread Stats   Avg      Stdev     Max      +/- Stdev
       响应时间   Latency   200.85ms  192.21ms   1.08s     87.09
每线程每秒完成请求数Req/Sec     17.29     10.65    50.00     68.75%
  Latency Distribution  延迟统计
     50%  135.61ms      有50%的请求执行时间是在135.61ms内完成
     75%  201.79ms      有75%的请求执行时间是在201.79ms内完成
     90%  456.45ms      有90%的请求执行时间是在456.45ms内完成
     99%  899.49ms      有99%的请求执行时间是在899.49ms内完成
  322 requests in 2.05s, 3.25MB read  2秒执行了322个请求,读了3.25MB数据
Requests/sec:    157.42   每秒请求数
Transfer/sec:    1.59MB   每秒钟读取1.59MB数据量

在这个示例中:

  • -t10:指定10个线程。
  • -c30:指定30个并发连接。
  • -d2s:指定测试持续时间为2秒。
  •  -T5s:超时的时间
  • --latency:显示延迟统计

  • http://www.baidu.com:指定要测试的目标URL。

运行以上命令后,wrk将模拟10个线程,每个线程30个并发连接,持续2秒地向www.baidu.com发送HTTP请求,并记录测试结果,包括请求速率、平均响应时间、吞吐量等指标。 

 更多参数释义

-s 或 --script:     指定脚本路径

-H, --header:      添加http header, 比如. "User-Agent: wrk"

9.wrk压测复杂场景

定制化压力测试参数:
使用 wrk 进行高级压力测试时,可以通过调整以下参数来定制化压力测试:

线程数 (-t):使用 -t 参数可以指定并发连接数,即同时发起的请求线程数。例如,wrk -t20 表示使用 20 个线程进行测试。

连接数 (-c):使用 -c 参数可以指定每个线程的连接数,即每个线程同时保持的连接数。例如,wrk -c100 表示每个线程同时保持 100 个连接。

测试时长 (-d):使用 -d 参数可以指定测试的持续时间,以秒为单位。例如,wrk -d30 表示测试持续 30 秒。

请求速率 (-R):使用 -R 参数可以指定每秒钟发送的请求速率。例如,wrk -R1000 表示每秒发送 1000 个请求。

自定义请求头 (-H):使用 -H 参数可以添加自定义的 HTTP 请求头。例如,wrk -H "Authorization: Bearer token" 可以添加 Authorization 头。

wrk 还支持使用 Lua 脚本进行更复杂的测试场景。通过编写 Lua 脚本,可以实现更多定制化的功能和测试场景,例如:

模拟不同类型的请求:通过 Lua 脚本可以模拟不同类型的请求,包括 GET、POST、PUT 等,并携带不同的请求参数和请求体。

实现复杂的请求逻辑:可以在 Lua 脚本中实现复杂的请求逻辑,包括动态生成请求数据、处理响应数据等。

自定义报告输出:可以通过 Lua 脚本自定义报告输出格式,包括统计数据、图表等

示例:

wrk模拟下单请求,执行lua脚本
-- post.lua

math.randomseed(os.time())

function generate_uuid()
    local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
    return string.gsub(template, '[xy]', function (c)
        local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
        return string.format('%x', v)
    end)
end

local counter = 1
local threads = {}
 
function setup(thread)
-- 给每个线程设置一个 id 参数
   thread:set("id", counter)
-- 将线程添加到 table 中
   table.insert(threads, thread)
   counter = counter + 1
end
 
-- thread table
local threads = {}

-- set up some variable for each thread
function setup(thread)
   success_counter=0
   thread:set("success_counter", success_counter)
   table.insert(threads, thread)
end

-- record successful response
function response(status, headers, body)
      success_counter = success_counter + 1
end

-- calculate tps
function done(summary, latency, requests)
    --sum up successful response from each thread
    total_success_counter = 0
    for _, thread in ipairs(threads) do
          total_success_counter = total_success_counter +thread:get("success_counter")
    end
    print("total_success_counter = " .. total_success_counter )
    print("TPS = "  ..     1000*1000*total_success_counter/summary.duration)
end

request = function()
   local headers = {
      ["Content-Type"] = "application/json",
   }

   local body = {
    version = "1.0",
    signType = "MD5",
    sign = "no",
    reqTime = "1723623525",
    mchNo = "M1711114860",
    shopNo = "MS17111486018",
    channelExtra = "{}",
    mchOrderNo = generate_uuid(),
    wayCode = "MOCK",
    payScene = "1",
    amount = 2,
    currency = "CNY",
    subject = "压测",
    body = "压测内容",
    notifyUrl = "https://xxx.xxxx.com"
   }

   -- 简单的JSON序列化函数
   local function serialize(obj)
      local lua = ""
      for k, v in pairs(obj) do
         lua = lua .. string.format("%q:%q,", k, v)
      end
      lua = string.sub(lua, 1, -2) -- 移除最后的逗号
      return "{" .. lua .. "}"
   end


   -- 将table转换为JSON字符串
   local body_json = serialize(body)

   return wrk.format('POST', nil, headers, body_json)
end

wrk -t12 -c400 -d30s -s /Users/fei.y/wrk/post.lua --latency http://127.0.0.1:9216/api/test/order/mock

Running 30s test @ http://127.0.0.1:9216/api/test/order/mock
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.31s    10.61ms   1.65s    94.31%
    Req/Sec    33.30     42.23   192.00     80.39%
  Latency Distribution
     50%    1.31s 
     75%    1.31s 
     90%    1.31s 
     99%    1.35s 
  4114 requests in 30.10s, 1.11MB read
  Socket errors: connect 0, read 550, write 0, timeout 1478
Requests/sec:    136.69
Transfer/sec:     37.91KB
total_success_counter = 4114
TPS = 136.6932403332
统计脚本每一个线程执行,lua脚本
--count.lua
local counter = 1
local threads = {}
 
function setup(thread)
-- 给每个线程设置一个 id 参数
   thread:set("id", counter)
-- 将线程添加到 table 中
   table.insert(threads, thread)
   counter = counter + 1
end
 
function init(args)
-- 初始化两个参数,每个线程都有独立的 requests、responses 参数
   requests  = 0
   responses = 0
 
-- 打印线程被创建的消息,打印完后,线程正式启动运行
   local msg = "thread %d created"
   print(msg:format(id))
end
 
function request()
-- 每发起一次请求 +1
   requests = requests + 1
   return wrk.request()
end
 
function response(status, headers, body)
-- 每得到一次请求的响应 +1
   responses = responses + 1
end
 
function done(summary, latency, requests)
-- 循环线程 table
   for index, thread in ipairs(threads) do
      local id        = thread:get("id")
      local requests  = thread:get("requests")
      local responses = thread:get("responses")
      local msg = "thread %d made %d requests and got %d responses"
-- 打印每个线程发起了多少个请求,得到了多少次响应
      print(msg:format(id, requests, responses))
   end
end
wrk -t12 -c400 -d30s -s /Users/fei.y/wrk/count.lua --latency http://127.0.0.1:9216/api/test/count/mock
thread 1 created
thread 2 created
thread 3 created
thread 4 created
thread 5 created
thread 6 created
thread 7 created
thread 8 created
thread 9 created
thread 10 created
thread 11 created
thread 12 created
Running 30s test @ http://127.0.0.1:9216/api/test/count/mock
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   484.03ms  496.50ms   2.00s    83.41%
    Req/Sec    16.48     11.88   100.00     68.57%
  Latency Distribution
     50%  188.42ms
     75%  767.67ms
     90%    1.25s 
     99%    1.93s 
  4862 requests in 30.10s, 50.13MB read
  Socket errors: connect 0, read 0, write 0, timeout 684
Requests/sec:    161.54
Transfer/sec:      1.67MB
thread 1 made 443 requests and got 409 responses
thread 2 made 507 requests and got 474 responses
thread 3 made 372 requests and got 339 responses
thread 4 made 487 requests and got 454 responses
thread 5 made 526 requests and got 493 responses
thread 6 made 323 requests and got 291 responses
thread 7 made 289 requests and got 256 responses
thread 8 made 420 requests and got 387 responses
thread 9 made 450 requests and got 417 responses
thread 10 made 413 requests and got 380 responses
thread 11 made 383 requests and got 350 responses
thread 12 made 645 requests and got 612 responses

更多脚本示例请参考icon-default.png?t=N7T8https://github.com/wg/wrk/tree/master/scripts

分析和优化压力测试结果
1. 解读wrk测试结果:
吞吐量 (Throughput):表示服务器在单位时间内处理的请求数量,通常以请求数/秒 (Requests per Second, RPS) 表示。吞吐量越高,服务器性能越好。

平均响应时间 (Average Response Time):表示服务器平均处理每个请求所花费的时间,通常以毫秒为单位。平均响应时间越低,服务器响应速度越快。

延迟百分比 (Latency Percentiles):表示在一定时间范围内的延迟分布情况,通常以百分比表示。例如,50% 的请求在多少毫秒内完成,90% 的请求在多少毫秒内完成等。

错误率 (Error Rate):表示测试过程中出现错误的请求比例,通常以百分比表示。错误率越低,服务器稳定性越好。

10.根据测试结果优化应用性能

代码层面优化:

  1. 减少不必要的对象创建:使用对象池、静态工厂方法等方式减少对象创建的开销。
  2. 优化数据结构:使用更适合当前场景的数据结构,比如使用ArrayList代替LinkedList,在特定场景下可以提高性能。
  3. 算法优化:选择更高效的算法,减少计算复杂度。
  4. 减少锁的竞争:使用并发数据结构,比如ConcurrentHashMap,或者减少同步块的大小,使用读写锁代替独占锁。
  5. 使用并发编程:合理使用线程池,充分利用多核CPU的优势。
  6. 异步日志:缩减打印日志,核心日志打印

JVM优化:

  1. 垃圾回收调优:选择合适的垃圾回收器(如CMS、G1、ZGC等),调整垃圾回收相关的参数。
  2. 堆内存优化:合理分配堆内存大小,避免频繁的Full GC。
  3. 栈内存调整:适当调整线程栈大小,减少内存开销。

架构层面优化:

  1. 缓存:使用缓存减少对数据库的直接访问,如Redis、Memcached,本地缓存等,构建多级缓存
  2. 数据库优化:优化SQL语句,使用索引,分库分表,读写分离等。
  3. 负载均衡:通过负载均衡分散请求到多个服务器,提高系统整体的TPS。
  4. 异步处理:使用消息队列等异步处理方式,可以提高系统的吞吐量。

硬件层面优化:

  1. 增加内存:增加服务器的内存,可以减少内存交换,提高处理速度。
  2. 使用SSD:使用SSD代替HDD,可以显著提高I/O性能。
  3. 网络优化:提高网络带宽,减少网络延迟。

其他优化:

  1. 代码级别分析:使用Java性能分析工具(如JProfiler、VisualVM)找出性能瓶颈。
  2. 系统监控:持续监控系统性能,及时发现并解决问题。
  3. 压力测试:通过压力测试找出系统的极限,并根据测试结果进行优化。

在进行优化时,应该综合考虑性能瓶颈出现在哪个层面,然后有针对性地进行优化。优化过程中,应该密切监控系统的各项性能指标,确保优化措施是有效的,并不会引入新的问题。

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值