压测工具之wrk

Posted by Alexander Wang on August 5, 2016

压测工具之wrk

昨晚系统routecause压测,突然想记下些工具,还有之前经常用的Jmeter

Install

brew install wrk

or

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

Useway

wrk -t24 -c72 -d300s --latency -s api.lua http://localhost:6830/invoke/

parameter

-t : thread

-c : connection

-d : during

—latency :

  Latency Distribution
     50%  474.09ms
     75%  651.11ms
     90%  902.69ms
     99%    1.46s

-s : lua(script)

result

Running 30s test @ http://www.baidu.com
  12 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   525.47ms  271.92ms   2.00s    74.97%
    Req/Sec    16.17      8.90    60.00     77.08%
  Latency Distribution
     50%  474.09ms
     75%  651.11ms
     90%  902.69ms
     99%    1.46s
  5499 requests in 30.09s, 80.66MB read
  Socket errors: connect 0, read 2, write 0, timeout 3
Requests/sec:    182.74
Transfer/sec:      2.68MB

Stdev : 标准差

Latency : 响应时间

Req/Sec : 请求数/thread*s

Lua

wrk.method = "POST" 
wrk.body = '{"skuId":1}' -- 譬如NCP协议、restful
wrk.headers["Content-Type"] = "application/json"

Function

local counter = 1  
local threads = {}  
  
function setup(thread)  
   thread:set("id", counter)  
   table.insert(threads, thread)  
   counter = counter + 1  
end  
  
function init(args)  
   requests  = 0  
   responses = 0  
  
   local msg = "thread %d created"  
   print(msg:format(id))  
end  
  
function request()  
   requests = requests + 1  
   return wrk.request()  
end  
  
function response(status, headers, body)  
   responses = responses + 1  
end  
  
function done(summary, latency, requests)  
   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  

Instance

bash

#!/bin/bash

head="threadPool,concurrent,latency.min,latency.max,latency.mean,latency.stdev,upper_50,upper_90,upper_95,upper_99,duration,requests,bytes,errors.connect,errors.read,errors.write,errors.status,errors.timeout,qps,Transfer/sec(KB)"

## threadPoolSize
threadPool=100
## 压测持续时间,单位s、m
duration=1s
## 每轮压测结束后休息时间
sleepTime=5s
## 压测路径URL
url="http://localhost:38290/rpc" 

## 间隔递增并发数
concurrentInterval=12
## 停止压测并发数,超过此值停止压测
stopConcurrent=1000
# 并发计数器
i=0

echo $head;
while (($i <= $stopConcurrent))
do
	let i+=concurrentInterval
	ret=`wrk -t12 -c$i -d$duration --latency -s post.lua $url | sed -n '$p'`
	ret="$threadPool,$i,"$ret;
	echo $ret;
	sleep $sleepTime
done

post.lua

function response(status, headers, body)
  --print(body)
end

function init(args)
	for k, v in pairs(args) do
    	--print(k, v)
	end
end

function done(summary, latency, requests)
  print("latency.min,latency.max,latency.mean,latency.stdev,latency:percentile(50.0),latency:percentile(90.0),latency:percentile(95.0),latency:percentile(99.0),summary.duration,summary.requests,summary.bytes,summary.errors.connect,summary.errors.read,summary.errors.write,summary.errors.status,summary.errors.timeout,qps,Transfer/sec(KB)")
  print(latency.min/1000 .. "," .. latency.max/1000 .. "," .. latency.mean/1000 .. "," .. latency.stdev/1000 .. "," .. latency:percentile(50.0)/1000 .. "," .. latency:percentile(90.0)/1000 .. "," .. latency:percentile(95.0)/1000 .. "," .. latency:percentile(99.0)/1000 .. "," .. summary.duration/1000000 .. "," .. summary.requests .. "," .. summary.bytes .. "," .. summary.errors.connect.. "," .. summary.errors.read.. "," .. summary.errors.write.. "," .. summary.errors.status.. "," .. summary.errors.timeout .. "," .. summary.requests/(summary.duration/1000000) .. "," .. (summary.bytes/1024)/(summary.duration/1000000))
end

function file_exists(file)
  local f = io.open(file, "rb")
  if f then f:close() end
  return f ~= nil
end

function shuffle(paths)
  local j, k
  local n = #paths
  for i = 1, n do
    j, k = math.random(n), math.random(n)
    paths[j], paths[k] = paths[k], paths[j]
  end
  return paths
end

function non_empty_lines_from(file)
  if not file_exists(file) then return {} end
  lines = {}
  for line in io.lines(file) do
    if not (line == '') then
      lines[#lines + 1] = line
    end
  end
  return shuffle(lines)
end



function request()
    path = paths[counter]
    counter = counter + 1
    if counter > #paths then
      counter = 1
    end

    wrk.method = "POST"
    wrk.body = path
    wrk.headers["Content-Type"] = "application/json;charset=utf-8"
    return wrk.format(wrk.method,nil,wrk.headers,wrk.body)
end

counter = 1
math.randomseed(os.time())
math.random(); math.random(); math.random()

paths = non_empty_lines_from("paths.txt")

if #paths <= 0 then
  print("multiplepaths: No paths found. You have to create a file paths.txt with one path per line")
  os.exit()
end
print("multiplepaths: Found " .. #paths .. " paths")

paths.txt

{"ver":"1.0","soa":{"rpc":"1.2649","req":"86eca521-34ce-4f95-b114-ae966e2e04bc"},"iface":"com.github.alexanderwangsgithub.TestService","method":"test","args":{},"metas":{}}
{"ver":"1.0","soa":{"rpc":"1.2649","req":"86eca521-34ce-4f95-b114-ae966e2e04bc"},"iface":"com.github.alexanderwangsgithub.InfoService","method":"getInfo","args":{"id":"1001"},"metas":{}}

Creative Commons License
This work is licensed under a CC A-S 4.0 International License.