1. 准备:AB命令 httpd-tool HTTP压测工具

$ sudo apt-get install apache2-utils 使用命令快捷安装 apache ab压测工具

  1. 用法:ab [options] [http[s]://]hostname[:port]/path
  2. 选项是:
  3. -n requests 要执行的请求数
  4. -c concurrency 一次发出的多个请求数
  5. -t timelimit 秒到最大值。花费在基准测试上
  6. 这意味着 -n 50000
  7. -s timeout 秒到最大值。等待每个响应
  8. 默认为 30
  9. -b windowssize TCP 发送/接收缓冲区的大小,以字节为单位
  10. -B address 建立传出连接时要绑定的地址
  11. -p postfile 包含要 POST 的数据的文件。还记得设置 -T
  12. -u putfile 包含要 PUT 的数据的文件。还记得设置 -T
  13. -T content-type 用于 POST/PUT 数据的内容类型标头,例如。
  14. '应用程序/x-www-form-urlencoded'
  15. 默认为“文本/纯文本”
  16. -v verbosity 要打印多少故障排除信息
  17. -w HTML 表格中打印结果
  18. -i 使用 HEAD 而不是 GET
  19. -x attributes 字符串作为表属性插入
  20. -y 属性 字符串作为 tr 属性插入
  21. -z attributes 字符串作为 td th 属性插入
  22. -C 属性 添加cookie,例如。 '阿帕奇 = 1234' (可重复)
  23. -H 属性添加任意标题行,例如。 '接受编码:gzip'
  24. 在所有正常标题行之后插入。 (可重复)
  25. -A 属性 添加Basic WWW Authentication,属性
  26. 是冒号分隔的用户名和密码。
  27. -P attribute 添加Basic Proxy Authentication,属性
  28. 是冒号分隔的用户名和密码。
  29. -X proxy:port 要使用的代理服务器和端口号
  30. -V 打印版本号并退出
  31. -k 使用 HTTP KeepAlive 功能
  32. -d 不显示服务表的百分位数。
  33. -S 不显示置信度估计器和警告。
  34. -q 处理超过 150 个请求时不显示进度
  35. -l 接受可变文档长度(用于动态页面)
  36. -g 文件名 将收集的数据输出到 gnuplot 格式文件。
  37. -e 文件名 输出带有百分比的 CSV 文件
  38. -r 不要在套接字接收错误时退出。
  39. -m method 方法名称
  40. -h 显示使用信息(此消息)
  41. -I 禁用 TLS 服务器名称指示 (SNI) 扩展
  42. -Z ciphersuite 指定 SSL/TLS 密码套件(参见 openssl ciphers
  43. -f 协议 指定 SSL/TLS 协议
  44. SSL2TLS1TLS1.1TLS1.2 或全部)
  45. -E certfile 指定可选的客户端证书链和私钥

* 压测重点关注的几个概念:

吞吐量(RPS Request per second):

对服务器并发处理能力的量化指标。 计算公式: 总请求数 / 总测试时间

并发数

某一时刻所能承受的总的连接数,即:session会话数量。

用户请求平均等待时长

计算公式: 总测试时间 / (总请求数 / 用户数)

服务器请求平均等待时长

计算公式:总测试时间 / 总请求数,是RPS的倒数

  • my_http_server.cpp: ```cpp

    include “../kit_server/http/http_server.h”

    include “../kit_server/Log.h”

static kit_server::Logger::ptr g_logger = KIT_LOG_ROOT(); static kit_server::Logger::ptr g_logger2 = KIT_LOG_NAME(“system”);

void run() {

  1. kit_server::Address::ptr addr = kit_server::Address::LookUpAnyIPAddress("0.0.0.0:8888");
  2. if(!addr)
  3. {
  4. KIT_LOG_ERROR(g_logger) << "get addr error";
  5. return;
  6. }
  7. kit_server::http::HttpServer::ptr server(new kit_server::http::HttpServer);
  8. while(!server->bind(addr))
  9. {
  10. sleep(1);
  11. }
  12. server->start();

}

int main(int argc, char argv[]) { g_logger2->setLevel(kit_server::LogLevel::Level::INFO); /起初为单线程处理*/ kit_server::IOManager iom(“http_server”, 1); iom.schedule(&run);

  1. return 0;

} ```

1.1 单线程测试

$ ab -n 1000000 -c 200 "[http://192.168.77.136:8888/kit"](http://192.168.77.136:8888/kit")
请求总数=100万,并发数量=200 短连接

1.1.1 测试结果

  • 总测试时间: 约45 s
  • 总传输量:26,300万字节
  • HTML总传输量:14,800万字节
  • RPS: 22,223.39 请求数/sec (平均)
  • 用户平均等待时长: 9 ms
  • 服务器平均等待时长:0.045 ms

image.png

1.1.2 资源使用情况:

image.png

1.2 两个线程测试

$ ab -n 1000000 -c 200 "[http://192.168.77.136:8888/kit"](http://192.168.77.136:8888/kit")
请求总数=100万,并发数量=200 短连接

BUG:程序发生断言

现象:单线程测试正常,而多线程发生错误,说明协程调度的模块有点问题。重点关注一下Scheduler::run()这个函数里面调度的一些情况。
image.png
通过断言打印的函数调用栈信息:断言发生在HOOK模块的do_io()::addEvent()函数中。也就说此时负责执行accept()的协程处于挂起HOLD状态。这很奇怪,HOLD状态的协程怎么会被调度?

修正:将YieldToHold()中对协程状态的修改注释掉就正常了

原因:笨办法试出来的,由于是一个HOLD状态的协程被调度了,就去检查所有调度前可能修改状态的地方,最后控制变量发现的这个地方………具体什么原因造成的不清楚。

找到问题:协程重入状态冲突。本质上是因为协程切入/切出之间的操作并非原子性的。
如何解决问题?

1.2.1 测试结果

  • 总测试时间: 约45 s
  • 总传输量:26,300万字节
  • HTML总传输量:14,800万字节
  • RPS: 22,032.43 请求数/sec (平均)
  • 用户平均等待时长: 9.078 ms
  • 服务器平均等待时长:0.045 ms

image.png

1.2.2 资源使用情况

image.png

1.3 5个线程测试

$ ab -n 1000000 -c 200 "[http://192.168.77.136:8888/kit"](http://192.168.77.136:8888/kit")
请求总数=100万,并发数量=200 短连接

1.3.1 测试结果

  • 总测试时间: 约45 s
  • 总传输量:26,300万字节
  • HTML总传输量:14,800万字节
  • RPS: 22,008.10 请求数/sec (平均)
  • 用户平均等待时长: 9.088 ms
  • 服务器平均等待时长:0.045 ms

image.png

1.3.2 资源使用情况

image.png

2. 准备:认识nginx

ubuntu20.04环境$ sudo apt-get install nginx即可便捷安装

概念:nginx是高性能HTTP和反向代理Web服务器。处理高并发的能力十分强大。

image.png

2.1 以nginx的压测作为对照

  • nginx单线程、短连接压测:

$ ab -n 1000000 -c 200 "http://192.168.77.136:80/kit"
image.png

  • 自己服务器框架单线程、短连接压测:

$ ab -n 1000000 -c 200 "http://192.168.77.136:8888/kit"
image.png

  • nginx单线程、长连接压测:

$ ab -n 1000000 -c 200 -k "http://192.168.77.136:80/kit"
image.png

  • 自己服务器框架单线程、长连接压测:

$ ab -n 1000000 -c 200 -k "http://192.168.77.136:8888/kit"
image.png