技术标签: github git Linux 网络 压力测试
1.需要安装一下编译工具,通过运行下面命令来安装工具:
# 安装 make 工具
sudo apt-get install make
# 安装 gcc编译环境
sudo apt-get install build-essential
2、安装完成之后安装git:
2.1.使用git -version命令查看环境是否安装git,如下图:
2.2.如果没安装就使用命令:apt-get install git (需要root权限就使用:sudo apt-get install git )
3、安装完成之后使用 git 下载 wrk 的源码到本地:
#下载命令
git clone https://github.com/wg/wrk.git
#切换路径到wrk目录下
cd wrk
#使用make命令编译环境
make
就 ok了.
make 成功以后在目录下有一个 wrk 文件. 就是它了. 你可以把这个文件复制到其他目录, 比如 bin 目录. 或者就这个目录下执行.
如果编译过程中出现:
src/wrk.h:11:25: fatal error: openssl/ssl.h: No such file or directory
#include <openssl/ssl.h>
是因为系统中没有安装openssl的库.
sudo apt-get install libssl-dev
或
sudo yum install openssl-devel
我们先来做一个简单的性能测试:
命令如下:
./wrk -t12 -c100 -d30s http://www.baidu.com
30秒钟结束以后可以看到如下输出:
Running 30s test @ http://www.baidu.com
12 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 538.64ms 368.66ms 1.99s 77.33%
Req/Sec 15.62 10.28 80.00 75.35%
5073 requests in 30.09s, 75.28MB read
Socket errors: connect 0, read 5, write 0, timeout 64
Requests/sec: 168.59
Transfer/sec: 2.50MB
先解释一下输出:
12 threads and 100 connections
这个能看懂英文的都知道啥意思: 用12个线程模拟100个连接.
对应的参数 -t 和 -c 可以控制这两个参数.
一般线程数不宜过多. 核数的2到4倍足够了. 多了反而因为线程切换过多造成效率降低. 因为 wrk 不是使用每个连接一个线程的模型, 而是通过异步网络 io(异步IO解释见:两段文章清楚弄明白什么是异步IO、同步IO、同步阻塞IO、同步非阻塞IO、异步阻塞IO、异步非阻塞IO_土渣渣的博客-程序员宅基地) 提升并发量. 所以网络通信不会阻塞线程执行. 这也是 wrk 可以用很少的线程模拟大量网路连接的原因. 而现在很多性能工具并没有采用这种方式, 而是采用提高线程数来实现高并发. 所以并发量一旦设的很高, 测试机自身压力就很大. 测试效果反而下降.
简单说一下wrk里面各个参数什么意思?
结果:
Req/Sec:每个线程每秒钟的完成的请求数
+/- Stdev: 正负一个标准差占比
标准差如果太大说明样本本身离散程度比较高. 有可能系统性能波动很大.
如果想看响应时间的分布情况可以加上--latency参数
在 wrk 的测试结果中,有一项为Requests/sec
,我们一般称之为QPS(每秒请求数),这是一项压力测试的性能指标,通过这个参数我们可以看出应用程序的吞吐量。
下面是线程统计:
Thread Stats Avg Stdev Max +/- Stdev
Latency 538.64ms 368.66ms 1.99s 77.33%
Req/Sec 15.62 10.28 80.00 75.35%
Latency: 可以理解为响应时间, 有平均值, 标准偏差, 最大值, 正负一个标准差占比.
Req/Sec: 每个线程每秒钟的完成的请求数, 同样有平均值, 标准偏差, 最大值, 正负一个标准差占比.
一般我们来说我们主要关注平均值和最大值. 标准差如果太大说明样本本身离散程度比较高. 有可能系统性能波动很大.
接下来:
5073 requests in 30.09s, 75.28MB read
Socket errors: connect 0, read 5, write 0, timeout 64
Requests/sec: 168.59
Transfer/sec: 2.50MB
30秒钟总共完成请求数和读取数据量.
然后是错误统计, 上面的统计可以看到, 5个读错误, 64个超时.
然后是所以线程总共平均每秒钟完成168个请求. 每秒钟读取2.5兆数据量.
可以看到, 相对于专业性能测试工具. wrk 的统计信息是非常简单的. 但是这些信息基本上足够我们判断系统是否有问题了.
wrk 默认超时时间是1秒. 这个有点短. 我一般设置为30秒. 这个看上去合理一点.
如果这样执行命令:
./wrk -t12 -c100 -d30s -T30s http://www.baidu.com
可以看到超时数就大大降低了, Socket errors 那行没有了:
Running 30s test @ http://www.baidu.com
12 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.16s 1.61s 14.42s 86.52%
Req/Sec 22.59 19.31 108.00 70.98%
4534 requests in 30.10s, 67.25MB read
Requests/sec: 150.61
Transfer/sec: 2.23MB
通过 -d 可以设置测试的持续时间. 一般只要不是太短都是可以的. 看你自己的忍耐程度了.
时间越长样本越准确. 如果想测试系统的持续抗压能力, 采用 loadrunner 这样的专业测试工具会更好一点.
想看看响应时间的分布情况可以加上--latency参数:
./wrk -t12 -c100 -d30s -T30s --latency http://www.baidu.com
Running 30s test @ http://www.baidu.com
12 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.22s 1.88s 17.59s 89.70%
Req/Sec 14.47 9.92 98.00 77.06%
Latency Distribution
50% 522.18ms
75% 1.17s
90% 3.22s
99% 8.87s
3887 requests in 30.09s, 57.82MB read
Socket errors: connect 0, read 2, write 0, timeout 0
Requests/sec: 129.19
Transfer/sec: 1.92MB
可以看到50%在0.5秒以内, %75在1.2s 以内. 看上去还不错.
看到这里可能有人会说了, HTTP 请求不会总是这么简单的, 通常我们会有 POST,GET 等多个 method, 会有 Header, 会有 body 等.
在我第一次知道有 wrk 这个工具的时候他确实还不太完善, 要想测试一些复杂的请求还有点难度. 现在 wrk 支持 lua 脚本. 在这个脚本里你可以修改 method, header, body, 可以对 response 做一下自定义的分析. 因为是 lua 脚本, 其实这给了你无限的可能. 但是这样一个强大的功能如果不谨慎使用, 会降低测试端的性能, 测试结果也受到影响.
一般修改method, header, body不会影响测试端性能, 但是操作 request, response 就要格外谨慎了.
我们通过一些测试场景在看看怎么使用 lua 脚本.
POST + header + body.
首先创建一个 post.lua 的文件:
wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
就这三行就可以了, 当然 headers 可以加入任意多的内容.
然后执行:
./wrk -t12 -c100 -d30s -T30s --script=post.lua --latency http://www.baidu.com
当然百度可能不接受这个 post 请求.
对 wrk 对象的修改全局只会执行一次.
通过 wrk 的源代码可以看到 wrk 对象的源代码有如下属性:
local wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = nil,
}
schema, host, port, path 这些, 我们一般都是通过 wrk 命令行参数来指定.
wrk 提供的几个 lua 的 hook 函数:
setup 函数
这个函数在目标 IP 地址已经解析完, 并且所有 thread 已经生成, 但是还没有开始时被调用. 每个线程执行一次这个函数.
可以通过thread:get(name), thread:set(name, value)设置线程级别的变量.
init 函数
每次请求发送之前被调用.
可以接受 wrk 命令行的额外参数. 通过 -- 指定.
delay函数
这个函数返回一个数值, 在这次请求执行完以后延迟多长时间执行下一个请求. 可以对应 thinking time 的场景.
request函数
通过这个函数可以每次请求之前修改本次请求的属性. 返回一个字符串. 这个函数要慎用, 会影响测试端性能.
response函数
每次请求返回以后被调用. 可以根据响应内容做特殊处理, 比如遇到特殊响应停止执行测试, 或输出到控制台等等.
function response(status, headers, body)
if status ~= 200 then
print(body)
wrk.thread:stop()
end
end
done函数
在所有请求执行完以后调用, 一般用于自定义统计结果.
done = function(summary, latency, requests)
io.write("------------------------------\n")
for _, p in pairs({ 50, 90, 99, 99.999 }) do
n = latency:percentile(p)
io.write(string.format("%g%%,%d\n", p, n))
end
end
下面是 wrk 源代码中给出的完整例子:
测试复合场景时, 也可以通过 lua 实现访问多个 url.
例如这个复杂的 lua 脚本, 随机读取 paths.txt 文件中的 url 列表, 然后访问.:
counter = 1
math.randomseed(os.time())
math.random(); math.random(); math.random()
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
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")
request = function()
path = paths[counter]
counter = counter + 1
if counter > #paths then
counter = 1
end
return wrk.format(nil, path)
end
关于 cookie
有些时候我们需要模拟一些通过 cookie 传递数据的场景. wrk 并没有特殊支持, 可以通过 wrk.headers["Cookie"]="xxxxx"实现.
下面是在网上找的一个离职, 取 Response的cookie作为后续请求的cookie
代码:
function getCookie(cookies, name)
local start = string.find(cookies, name .. "=")
if start == nil then
return nil
end
return string.sub(cookies, start + #name + 1, string.find(cookies, ";", start) - 1)
end
response = function(status, headers, body)
local token = getCookie(headers["Set-Cookie"], "token")
if token ~= nil then
wrk.headers["Cookie"] = "token=" .. token
end
end
文章浏览阅读2.5k次,点赞2次,收藏9次。一 、保证信号完整性1)优先保证地回路的连通性,避免地回路走线过长过细2)VMCU、VDDIO、BTAVDD等电源退耦电容尽量靠芯片管脚放置,且地线回路要尽量短3)重点关注DCDC电源部分布局,要求远离天线并靠近电池端,请参考图1绿色方框:各退耦电容地就近大片回流到DCDC芯片地;蓝色方框:DCDC芯片地就近大片回流到主控芯片地/电池地具体地,对于DCDC电源LAYOUT要求如下:1)DCDC 芯片保证三点地的完整性,至少有一面的完整性(输入电容地、输出电容地、芯片地汇合走线尽量短), 特别_ac695x 电池
文章浏览阅读1.8k次,点赞3次,收藏7次。简介当前C#剪切图片的案例挺多的,但是用C++的还比较少。但目前的项目需要剪切图片,我也知道用OpenCV比较简单,但是自己又不想在项目中配置一大堆OpenCV的东西,因为项目不怎么需要哪个。本篇博文包含了 两个知识点:图片剪切,字节数组和IStream的转换,Stream和Image类的转换。图片剪切首先自己搜了网上C++的剪切图片的方法,然后发现GDI+ 中的DrawImag..._gdiplus 裁剪
文章浏览阅读61次。服务器的大用户量的承载方案一、前言 二、编译安装 三、 安装MySQL、memcache 四、 安装Apache、PHP、eAccelerator、php-memcache 五、 安装Squid 六、后记 一、前言,准备工作当前,LAMP开发模式是WEB开发的首选,如何搭建一个高效、可靠、稳定的WEB服务器一直是个热门主题,本文就是这个主题的一次尝试。我们采用的架构图如下:引用-------- -...
文章浏览阅读727次。Gamma校正(C++、OpenCV实现)1.作用:Gamma校正是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系:伽玛校正由以下幂律表达式定义: 2.函数原型void calcHist( const Mat* images, int nimages,const int* channels, InputArray mask,OutputArray hist, int ..._对输入图像进行伽马矫正
文章浏览阅读873次。出处:http://robin0925.cnblogs.com/archive/2006/06/14/425811.html1@ Page language="c#" Codebehind="$FILENAME$.cs" AutoEventWireup="false" Inherits="$INHERITS$" %> 2DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4_.net里的ajax代码
文章浏览阅读519次。转自:http://www.cnblogs.com/louissong/p/3832960.htmlMonoBehaviour里面有两个内置的延时方法Invoke123Invoke(methodName: string, time: float): void;methodName_unity3d invokerepeating
文章浏览阅读858次。1.任意目录下输入 vim ~/.vimrc 即可_配置文件显示数字
文章浏览阅读1k次,点赞4次,收藏9次。一、介绍QWebEngineView 是QT5.4版本加入的新浏览器引擎,用于编辑、查看web内容。在windows系统下 QWebEngineView支持MSVC编译器编译、不支持mingw编译。使用QWebEngineView时,需要在工程文件里增加webenginewidgets模块的引用,并加上#include <QWebEngineView> 头文件。Header:#include <QWebEngineView> qmake:QT += webenginew_qwebengine用的什么版本的引擎
文章浏览阅读3.8k次。编译纯静态库文件1.编译x264静态库libx264.a2.编译ffmpeg的静态库libavcodec.a libavdevice.a libavfilter.a libavformat.a libavutil.a libpostproc.a libswresample.a libswscale.a 并enable x2643.编译自己的程序,链接库的顺序为 -lavc_静态链接 libx264.a
文章浏览阅读1.8k次。第1关:创建线程任务描述 相关知识 什么是线程、什么是进程 如何创建线程 编程要求 测试说明任务描述本关任务:创建一个Java线程执行特定任务。相关知识不知道你有没有发现,截止目前,我们编写的代码都是在main()函数中依照编写代码的顺序从上到下依次运行的。但是我们平常使用的软件基本都是可以多个任务同时执行的,这其中的运行机制是什么呢?这一小节我们就来探讨。本小节我们来学习Java中程序是如何同时执行多个任务的。为了完成本关任务,你需要掌握:1.什么是线程、_java高级特性 - 多线程基础(1)使用线程
文章浏览阅读6.2k次。2012-01-05 22:02 by keepfool, 4835 阅读, 37 评论, 收藏, 编辑前言 数据显示的方式可以通过很多控件来实现,例如服务端的原生GridView,第三方控件ComponentArt、Telerik等,客户端_repeatitems属性
文章浏览阅读1.3w次,点赞7次,收藏26次。oracel创建uuid为主键的表时可以直接指定default uuid();但是mysql不支持,可以通过触发器实现。下面是创建一个产品表的sql语句。CREATE TABLE `product` ( `id` varchar(32) NOT NULL, `productNum` varchar(50) NOT NULL, `productName` varchar(50) DEF..._mysql创建某个表时给主键定义uuid