c++多线程实现反向代理 QPS 达到 Haproxy/Nginx 的 3 倍

2023-09-12 16:32:08 +08:00
 shaoyie

NiubiX.

项目地址

实验性项目,NiubiX 只提供反向代理功能,大家轻拍有不好的地方可以留言或提 issue/pr. 觉得好就点个 star ,我会持续完善它

与 Nginx/Haproxy 对比测试

Linux 5.19.0-1030-gcp #32~22.04.1-Ubuntu
Instacne 1 GCP cloud VM, 2 cores, 4GB RAM 10.146.0.2 (nginx,haproxy, niubix run at here)
Instacne 2 GCP cloud VM, 2 cores, 4GB RAM 10.146.0.3 (backend, wrk run at here)

nginx version config

nginx version: nginx/1.18.0 (Ubuntu)

server {
    listen       8082 reuseport;
    server_name  localhost;

    access_log  off;
    error_log off;

    location / {
        proxy_pass http://10.146.0.3:8080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

root         516       1  0 Aug24 ?        00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data  417322     516  0 12:13 ?        00:00:06 nginx: worker process
www-data  417323     516  0 12:13 ?        00:00:08 nginx: worker process

haproxy version config

HAProxy version 2.4.22-0ubuntu0.22.04.2 2023/08/14

listen niubix
    bind 0.0.0.0:8083
    mode http
    option forwardfor
    server s1 10.146.0.3:8080

ps -eLf | grep haproxy
root      449421       1  449421  0    1 15:11 ?        00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
haproxy   449423  449421  449423  0    2 15:11 ?        00:00:05 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
haproxy   449423  449421  449429  0    2 15:11 ?        00:00:05 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock

单独测试后端程序处理能力, 确保不存在吞吐量瓶颈

run at 10.146.0.2

wrk -t 2 -c 100 -d 10s  http://10.146.0.3:8080/xxx
Running 10s test @ http://10.146.0.3:8080/xxx
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   520.95us  203.98us   4.09ms   68.03%
    Req/Sec    59.25k     2.68k   63.62k    52.50%
  1179133 requests in 10.00s, 173.17MB read
Requests/sec: 117888.45
Transfer/sec:     17.31MB

为了数据真实性,我只取了 1 次测试结果,连续对 3 个服务测试截图

对于 nginx 的数据声明一下:只有偶尔能跑到 1.7w 的 qps ,如果 proxy_pass http://10.146.0.3:8080; 换到 127.0.0.1:8080 ,qps 能到 9000 qps ,至于局域网内为什么这么低通过 strace 也没看到异常,而且 cpu 也通跑满,不知道它在干嘛

tcpdump tcp port 8080 抓包查看 niubix 实际数据,包含 X-Real-IP, XFF ,并且响应在微秒级

目前具备功能:

测试声明

接下来开发计划

8288 次点击
所在节点    程序员
125 条回复
learningman
2023-09-13 11:57:05 +08:00
反代没开 proxy_http_version 1.1 ,keep alive 没打开
proxy_set_header Connection "";
proxy_http_version 1.1;

upstream 里可以单独配,你也没设
zengzizhao
2023-09-13 12:03:09 +08:00
@shaoyie #52 你这是怼了人不自知啊......
kkk9
2023-09-13 12:41:56 +08:00
@shaoyie #21 我也不会测,但是我知道美团把 haproxy 作为数据库集群的负载均衡支撑,每天的流量应该比你测试高。实战也比我们整个小机器测试的真实。

还是建议换个 8c16g 的真实主机测试,应该会有新的发现,同时,随便拿一台 GCP 测试的数据挨喷很正常,不要太玻璃心。
ShuA1
2023-09-13 13:18:27 +08:00
upstream
shaoyie
2023-09-13 13:34:29 +08:00
@xiaooloong 感谢,
我试了一下,还是不行,qps 还是 2000+
```
upstream backend {
server 10.146.0.3:8080;
keepalive 16;
}
server {
listen 8082 reuseport;
server_name localhost;

access_log off;
error_log off;

location / {
#proxy_pass http://127.0.0.1:8080;
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
shaoyie
2023-09-13 13:43:53 +08:00
@learningman 开了啊,我只有一个 backend ,用 proxy_pass 就可以了,不用 upstream 也没事,这不影响性能
shaoyie
2023-09-13 13:47:22 +08:00
感谢提出意见的各位,不用怼了,haproxy 的数据已经可以做为参考了,至少证明了我的猜想是可行的,我会持续去完善 niubix ,争取能给 LBS 带来一个新的选项。
encro
2023-09-13 13:52:12 +08:00
@shaoyie

“国内这个社区氛围不好”



少一些标题党估计能更好?!
shaoyie
2023-09-13 13:56:48 +08:00
@encro 测试数据就是个结果啊,我也声明了,程序还不完善,但要懂其底层原理的人应该明白,补上缺少的那些功能并不会带来 2 倍的性能差异,数据只是参考,不是定性,每个人通过数据分析到的结果是不一样的。
yunyuyuan
2023-09-13 14:02:07 +08:00
你自己看看的回复,就你戾气最重,谁 tm 惯着你了?还骂起人来
我替他们骂你:臭煞笔,已 b
hankai17
2023-09-13 14:06:47 +08:00
nginx 开启 upstream 的 keepalive 后 如果 qps 上不去 看一下是不是 upstream 端的压测工具是不是有问题

测代理别用 wrk 测 可以试试 ats 的 jtest 同时充当客户端与服务端
hankai17
2023-09-13 14:27:41 +08:00
@shaoyie
worker_connections 1024; 改大点
还有文件描述符限制 也改大点
shaoyie
2023-09-13 14:31:43 +08:00
@hankai17 嗯 感谢,我研究研究 backend
shaoyie
2023-09-13 14:38:51 +08:00
@hankai17 这个 fd 数量不影响,默认 ulimit -n 就是 1024 ,实际并发链接数 wrk 也才 100 ,
hikarugo
2023-09-13 15:38:15 +08:00
在相对专业的论坛发一个 uc 类标题(难听点就是一眼假),被嘲讽就反嘲讽回去,然后怪论坛人戾气重,一眼假的结论还不允许别人批评,如果你不是显摆也不是来寻求建议,那你发帖的标题出发点是?你完全标题可以加上“是我测试方法不对吗”。这种圈内常识性的结论性标题被喷难道不应该吗?多少人厌恶这种标题党。

楼上的 v 友说得很好“测出这种荒唐的结果,首先应该是怀疑自己的问题,而不是感觉发现了新大陆”
看你的回复骂人的话是真的难听,你的戾气应该是他们的 3 倍吧
chaorenguilai198
2023-09-13 15:49:14 +08:00
我擦,我竟然看完了所有回复。确实喷的精彩。
ragnaroks
2023-09-13 15:53:56 +08:00
1 virtual thread E5-2689 + 512 MiB RAM

root@cn1427:~# wrk -t2 -c100 -d10s http://localhost
Running 10s test @ http://localhost
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.61ms 2.49ms 13.74ms 80.17%
Req/Sec 18.19k 3.59k 21.09k 81.00%
362030 requests in 10.01s, 39.22GB read
Requests/sec: 36181.29
Transfer/sec: 3.92GB

root@cn1427:~# podman exec openresty nginx -V
nginx version: openresty/1.21.4.2
built with OpenSSL 1.1.1s 1 Nov 2022
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl111/include' --add-module=../ngx_devel_kit-0.3.2 --add-module=../echo-nginx-module-0.63 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.33 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.09 --add-module=../srcache-nginx-module-0.33 --add-module=../ngx_lua-0.10.25 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.34 --add-module=../array-var-nginx-module-0.06 --add-module=../memc-nginx-module-0.19 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.9 --add-module=../ngx_stream_lua-0.0.13 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl111/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl111/lib' --with-pcre-jit --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-stream --with-http_ssl_module
ragnaroks
2023-09-13 15:56:52 +08:00
root@cn1427:~# cat /var/lib/containers/storage/volumes/openresty-config/_data/nginx.conf
# nginx.conf -- docker-openresty
#
# This file is installed to:
# `/usr/local/openresty/nginx/conf/nginx.conf`
# and is the file loaded by nginx at startup,
# unless the user specifies otherwise.
#
# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server`
# section and adds this directive:
# `include /etc/nginx/conf.d/*.conf;`
#
# The `docker-openresty` file `nginx.vh.default.conf` is copied to
# `/etc/nginx/conf.d/default.conf`. It contains the `server section
# of the upstream `nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#

user root;
worker_processes 2;
worker_rlimit_nofile 65535;
pcre_jit on;
error_log /logs/error.log;

events {
use epoll;
worker_connections 16384;
accept_mutex off;
multi_accept on;
}

http {
include mime.types;
default_type application/octet-stream;
log_format main '$time_local # $remote_addr => $http_x_real_ip[$http_x_forwarded_for] | $status | $http_referer | $http_user_agent | $request';
access_log /logs/access.log main;
client_body_temp_path /var/run/openresty/nginx-client-body;
proxy_temp_path /var/run/openresty/nginx-proxy;
fastcgi_temp_path /var/run/openresty/nginx-fastcgi;
uwsgi_temp_path /var/run/openresty/nginx-uwsgi;
scgi_temp_path /var/run/openresty/nginx-scgi;
sendfile on;
keepalive_timeout 65;
server_tokens off;
more_clear_headers Server;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
resolver 223.5.5.5;
include /etc/nginx/conf.d/*.conf;
}
shaoyie
2023-09-13 16:13:39 +08:00
@fyxtc 感谢回复,就是要打破所谓的“圈内常识”,我从来都没说我吹 NB ,我只是写了一个 3 倍(也是有数据支撑的,而且我也声明了,我实现的功能不完全)数据只供参考,我相信等功能完善了也不会降低 2 倍的性能差。至于 nginx 的问题,完全可以忽略,参考 haproxy 的就够了。nginx 的配置我确实没搞定,也研究过,也试了上边热心网友提供的配置,都不行。
shaoyie
2023-09-13 16:17:04 +08:00
铁子们,搞定了 @xiaooloong @learningman @picone

wrk -t 2 -c 100 -d 10s -H 'Connection: keep-alive' http://10.146.0.2:8082/xxx
Running 10s test @ http://10.146.0.2:8082/xxx
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.99ms 1.16ms 28.64ms 81.99%
Req/Sec 12.61k 526.49 13.93k 78.50%
250914 requests in 10.00s, 38.52MB read
Requests/sec: 25083.91
Transfer/sec: 3.85MB


wrk 是不带 connection header 的,nginx 默认就按 close 处理了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/973075

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX