lesismal / go-websocket-benchmark

123 stars 14 forks source link

服务端可以开启压缩, 分别测试客户端开启/关闭压缩的不同表现 #1

Closed lxzan closed 1 year ago

lesismal commented 1 year ago

可以加,来PR一下啊。 我这个用的nbio自己的websocket client,是支持百万连接的。 昨晚上跑了下大概能这样: taskset 0-3 for server (4 cpu cores) 1m connection 1k payload arount 100k tps around 2g mem

gobwas的百万连接代码太麻烦了,我没加,不知道它的跑出来啥效果。其他库都跑不了百万连接

lxzan commented 1 year ago

gev 支持百万连接, 你可以和它对比.

gobwas/ws 给我的感觉就是一个工具集, 能用但不成系统不好用. 我的readme里原来有它, 后面加了压缩测试, 嫌弃它开启压缩很麻烦给去掉了

lxzan commented 1 year ago

建立1m耗时太久了, 节省时间测个10w就差不多了 😂

lxzan commented 1 year ago

初版完成后我再来PR吧

lesismal commented 1 year ago

考虑过加gev,但它不支持tls 所以我没加它

lesismal commented 1 year ago

gobwas配合netpoll存在问题,所以我也没加。不打算加半成品或者缺陷明显的

lxzan commented 1 year ago

目前支持TLS的百万连接方案只有NBIO, gnet有个TLS PR还没合.

lesismal commented 1 year ago

比如conn无锁那个可能存在问题。它的issue里到现在还有悬案呢

lxzan commented 1 year ago

周末写了个异步解析器demo, 和你们的大不一样啊

image
lxzan commented 1 year ago

比如conn无锁那个可能存在问题。它的issue里到现在还有悬案呢

还有一个concurrent map writes的issue,作者没有回应

lesismal commented 1 year ago

我那个异步解析器当时是不想在结构体上挂载多字段,所以没做状态机没把这些字段单独放到conn上。而是每次nextframe重新取,实际场景应该不至于那么倒霉每次只有读到一个字节,而且取那几个字段也就buffer上拿一下不会浪费太多,所以就取舍成现在这种了

lxzan commented 1 year ago

帧头14byte放conn结构体上能避免重复allocs

lesismal commented 1 year ago

帧头14byte放conn结构体上能避免重复allocs

跟重复allocs关系倒是不大,nextframe里不是重复alloc,而是如果一个head多次才读到、需要多次重复取这个几个字段+判断,而且就是这几个字节的,4字节的mask是等收到完整包才会操作一次,所以最多好像应该是前10个字节的字段的判断,通常包size没那么大,head也就6字节吧,所以成本也不高。 而如果读到一部分就buffer切割一下,对于nbio这种场景反倒需要更多alloc。因为这事异步解析器,不是从也给buffer里读出来到新buffer、旧的buffer一直是那一段,用pool管理这些buffer如果放回,应该保证这个buffer不是某个buffer的中间部分。所以切掉前面的一段,就要memmove把数据移动到头部去,否则pool.Put回去,这个buffer的前面有一部分隐藏的不可被用但却占用了内存

nbio是海量连接数优先,所以能少点字段就少点

lxzan commented 1 year ago

parser的实现和read buffer相关性很高啊。我感觉LinkedBuffer加状态机的实现很完美了,但是nbio, gnet, gev都没用这种方案😂

lesismal commented 1 year ago

parser的实现和read buffer相关性很高啊。我感觉LinkedBuffer加状态机的实现很完美了,但是nbio, gnet, gev都没用这种方案😂

你可以结合poller实现一下试试,如果好的话,欢迎pr到nbio来

lxzan commented 1 year ago

是结合EpollWait写的异步解析器,已经能够解出message了,但是其他部分还非常不完善,得好好研究下你们是怎么处理epoll事件的,先看看效果。

lxzan commented 1 year ago

一次系统调用从内核缓冲区读到公用的eventLoop.buffer,然后写入conn.LinkedBuffer,运气好的话可以直接回调OnMessage,运气不好的话从conn.LinkedBuffer copy一个新的Message.

lesismal commented 1 year ago

连接方案只有NBIO, gnet有

还好,刚又跑了几轮,1m建立连接大概25-35s范围,500w次echo,跑的时间长一点,non-blocking mod server内存总量上升到4.5G左右应该是稳定了,如果需要限制内存可以配合手动GC、GOMEMLIMIT=、debug.SetMemoryLimit(),上一次跑的比较少、只有2G左右。 其他库每个连接一个协程、1M*8K,协程自己就要8G内存了而且容易STW、不稳定

root@ubuntu:~/go-websocket-benchmark# ./script/client.sh -f="nbio_mod_nonblocking" -c=1000000 -n=5000000
2023/05/29 15:29:13.237 [INF] NBIO[Benchmark-Client] start
2023/05/29 15:29:13 1000000 clients start connecting
2023/05/29 15:29:14 31216 clients connected
2023/05/29 15:29:15 80387 clients connected
2023/05/29 15:29:16 127612 clients connected
2023/05/29 15:29:17 178912 clients connected
2023/05/29 15:29:18 222956 clients connected
2023/05/29 15:29:19 272998 clients connected
2023/05/29 15:29:20 317510 clients connected
2023/05/29 15:29:21 365519 clients connected
2023/05/29 15:29:22 412712 clients connected
2023/05/29 15:29:23 467014 clients connected
2023/05/29 15:29:24 506130 clients connected
2023/05/29 15:29:25 551859 clients connected
2023/05/29 15:29:26 595780 clients connected
2023/05/29 15:29:27 642385 clients connected
2023/05/29 15:29:28 683865 clients connected
2023/05/29 15:29:29 733333 clients connected
2023/05/29 15:29:30 760540 clients connected
2023/05/29 15:29:31 803157 clients connected
2023/05/29 15:29:32 847922 clients connected
2023/05/29 15:29:33 879818 clients connected
2023/05/29 15:29:34 918057 clients connected
2023/05/29 15:29:35 961708 clients connected
2023/05/29 15:29:36 999768 clients connected
2023/05/29 15:29:37 999862 clients connected
2023/05/29 15:29:38 999937 clients connected
2023/05/29 15:29:39 999990 clients connected
2023/05/29 15:29:40 999990 clients connected
2023/05/29 15:29:40 1000000 clients connected
-------------------------
NAME     : nbio_mod_nonblocking
BENCHMARK: 5000000 times
SUCCESS  : 5000000, 100.00%
FAILED   : 0, 0.00%
TPS      : 102059
TIME USED: 48.99s
MIN USED : 0.05ms
MAX USED : 227.85ms
AVG USED : 19.59ms
TP50     : 18.26ms
TP75     : 25.80ms
TP90     : 33.77ms
TP95     : 39.43ms
TP99     : 51.98ms
-------------------------
lesismal commented 1 year ago

刚加上了 debug.SetMemoryLimit(1024*1024*1024*2),之前测试用 GOMEMLIMIT= 也是这个功能、同样效果。

TPS没降,内存峰值更稳定了

root@ubuntu:~/go-websocket-benchmark# ./script/client.sh -f="nbio_mod_nonblocking" -c=1000000 -n=5000000
2023/05/29 15:49:10.575 [INF] NBIO[Benchmark-Client] start
2023/05/29 15:49:10 1000000 clients start connecting
2023/05/29 15:49:11 40879 clients connected
2023/05/29 15:49:12 89065 clients connected
2023/05/29 15:49:13 134060 clients connected
2023/05/29 15:49:14 175804 clients connected
2023/05/29 15:49:15 229280 clients connected
2023/05/29 15:49:16 275145 clients connected
2023/05/29 15:49:17 322548 clients connected
2023/05/29 15:49:18 370763 clients connected
2023/05/29 15:49:19 410602 clients connected
2023/05/29 15:49:20 456983 clients connected
2023/05/29 15:49:21 510159 clients connected
2023/05/29 15:49:22 551169 clients connected
2023/05/29 15:49:23 601110 clients connected
2023/05/29 15:49:24 637219 clients connected
2023/05/29 15:49:25 689203 clients connected
2023/05/29 15:49:26 723821 clients connected
2023/05/29 15:49:27 766394 clients connected
2023/05/29 15:49:28 813606 clients connected
2023/05/29 15:49:29 840960 clients connected
2023/05/29 15:49:30 881367 clients connected
2023/05/29 15:49:31 918254 clients connected
2023/05/29 15:49:33 973108 clients connected
2023/05/29 15:49:33 984520 clients connected
2023/05/29 15:49:34 999960 clients connected
2023/05/29 15:49:35 999991 clients connected
2023/05/29 15:49:36 999995 clients connected
2023/05/29 15:49:37 999997 clients connected
2023/05/29 15:49:38 999997 clients connected
2023/05/29 15:49:39 1000000 clients connected
-------------------------
NAME     : nbio_mod_nonblocking
BENCHMARK: 5000000 times
SUCCESS  : 5000000, 100.00%
FAILED   : 0, 0.00%
TPS      : 103863
TIME USED: 48.14s
MIN USED : 0.03ms
MAX USED : 248.63ms
AVG USED : 19.25ms
TP50     : 18.10ms
TP75     : 25.45ms
TP90     : 32.69ms
TP95     : 37.75ms
TP99     : 49.53ms
-------------------------

只截取了最后几条:

root@ubuntu:~/go-websocket-benchmark/script# top -d 1 | grep -e nbio                                                                                                                         
  41004 root      20   0 7068640   1.9g   5660 S 155.0  12.0   3:32.71 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7068768   1.9g   5660 S 158.4  12.0   3:34.31 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7068832   1.9g   5660 S 159.0  12.0   3:35.90 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7068960   1.9g   5660 S 159.4  12.0   3:37.51 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7069024   1.9g   5660 S 164.0  12.0   3:39.15 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7069152   1.9g   5660 S 164.4  12.0   3:40.81 nbio_mod_nonblo                                                                                                                    
  41004 root      20   0 7069216   1.9g   5660 S 165.0  12.0   3:42.46 nbio_mod_nonblo    
lxzan commented 1 year ago

避免了runtime频繁向系统申请内存,所以更平滑了?

lesismal commented 1 year ago

估计是回收更及时吧

lesismal commented 1 year ago

初版基本成型了,添加了 Markdown 文件输出,这种格式:

Framework Total Success Failed TimeUsed Min Avg Max TPS TP50 TP75 TP90 TP95 TP99 CPU Min CPU Avg CPU Max MEM Min MEM Avg MEM Max
gobwas 1000000 1000000 0 10.55s 70.11us 21.04ms 136.82ms 94826 18073358 26321531 33498583 40032605 63269575 175.97% 309.97% 350.78% 86.86M 87.11M 87.93M
gorilla 1000000 1000000 0 6.24s 61.76us 12.47ms 54.06ms 160185 12029922 14179334 16701994 18821624 25674223 70.96% 257.24% 315.83% 250.96M 253.64M 256.21M
gws 1000000 1000000 0 5.43s 35.07us 10.85ms 55.06ms 184193 10563797 12666350 15038558 16953985 22934293 127.87% 268.22% 310.53% 128.86M 145.12M 154.01M
gws_basedon_stdhttp 1000000 1000000 0 5.90s 39.21us 11.78ms 70.53ms 169604 11311124 13470497 16111496 18418293 26496843 0.00% 239.04% 319.17% 257.30M 260.07M 268.89M
nbio_basedon_stdhttp 1000000 1000000 0 5.86s 50.12us 11.70ms 54.82ms 170568 11438240 13533392 15715321 17399096 24149547 279.68% 319.74% 333.61% 178.35M 187.53M 191.03M
nbio_mod_blocking 1000000 1000000 0 5.74s 103.10us 11.45ms 61.81ms 174326 11227015 13092554 14990388 16437055 22280866 244.91% 317.46% 345.74% 145.40M 168.12M 187.06M
nbio_mod_mixed 1000000 1000000 0 5.81s 73.00us 11.61ms 46.38ms 172005 11468030 13276521 15079115 16375475 21465446 257.83% 323.30% 345.30% 173.99M 201.11M 228.48M
nbio_mod_nonblocking 1000000 1000000 0 8.07s 53.90us 16.12ms 79.27ms 123950 15486615 21213664 26814677 30310507 38270766 20.99% 266.57% 303.90% 58.83M 62.78M 65.34M
nhooyr 1000000 1000000 0 8.72s 295.12us 17.41ms 119.88ms 114658 16089235 17809695 19976927 24335647 58001122 275.83% 362.35% 381.76% 573.47M 573.85M 574.00M
lxzan commented 1 year ago

TP是延迟百分位吗, 纳秒换成毫秒好看点

lxzan commented 1 year ago

没想到不开压缩 nhooyr/websocket 内存占用也这么高

lxzan commented 1 year ago

我在 linux arm64 虚拟机里面跑了一下试试, 发现 http hijack 拖后腿挺多的

Framework Total Success Failed TimeUsed Min Avg Max TPS TP50 TP75 TP90 TP95 TP99 CPU Min CPU Avg CPU Max MEM Min MEM Avg MEM Max
gobwas 1000000 1000000 0 8.28s 85.21us 16.55ms 76.78ms 120729 14079417 21361459 26699583 30164500 37035625 47.94% 154.77% 177.98% 89.29M 89.31M 89.32M
gorilla 1000000 1000000 0 5.72s 127.33us 11.42ms 45.05ms 174926 11097292 12705334 14749167 16737583 23256917 108.68% 142.68% 153.78% 231.68M 234.01M 236.09M
gws 1000000 1000000 0 5.35s 26.67us 10.67ms 56.48ms 187066 10170333 12086542 14819208 17514625 25013709 49.91% 122.51% 143.93% 138.50M 142.93M 154.45M
gws_basedon_stdhttp 1000000 1000000 0 6.40s 38.21us 12.78ms 85.68ms 156226 12060792 14405459 17925750 20603750 29465667 56.96% 128.54% 149.98% 232.13M 253.63M 272.52M
nbio_basedon_stdhttp 1000000 1000000 0 6.78s 44.83us 13.54ms 65.21ms 147505 13090959 15041542 17852916 20489417 28092750 120.95% 145.34% 152.75% 167.96M 173.89M 179.01M
nbio_mod_blocking 1000000 1000000 0 6.85s 58.92us 13.67ms 50.45ms 145940 13121708 15277584 18381292 20915834 29823792 132.93% 148.96% 156.96% 153.34M 157.37M 166.83M
nbio_mod_mixed 1000000 1000000 0 6.97s 180.38us 13.92ms 54.54ms 143502 13513281 15550792 18004333 20148711 28054209 0.00% 130.74% 158.72% 189.61M 223.10M 248.52M
nbio_mod_nonblocking 1000000 1000000 0 9.58s 31.81us 19.15ms 65.75ms 104332 18850733 24962120 30841336 34388295 41655984 85.91% 126.93% 138.97% 64.74M 65.60M 66.31M
nhooyr 1000000 1000000 0 9.73s 325.95us 19.45ms 119.75ms 102722 16722066 19283760 24890199 38114597 65481270 141.85% 174.04% 195.87% 558.90M 559.53M 559.80M
lesismal commented 1 year ago

TP是延迟百分位吗

默认、最小百分位,大于100的比如111,则取千分位,是自动判断、base循环往上乘以10直到base大于传入的分位值: https://github.com/lesismal/perf/blob/main/caculator.go#L240

纳秒换成毫秒好看点

Avg那几个转换了,TPN那几个字段漏掉了,已经更新了,之前ms us也搞错了

又增加了个SimpleReport,少取点字段,两个都生成markdown文件,SimpleReport这种格式: Framework Total Success Failed Used Avg TPS TP50 TP90 TP99 CPU Avg MEM Avg
gobwas 1000000 1000000 0 9.40s 18.78us 106381 15.53us 30.76us 68.07us 317.19% 85.53M
gorilla 1000000 1000000 0 5.79s 11.56us 172797 11.19us 16.04us 24.43us 280.20% 252.48M
gws 1000000 1000000 0 5.38s 10.74us 185827 10.40us 14.75us 24.41us 255.25% 144.80M
gws_basedon_stdhttp 1000000 1000000 0 5.37s 10.73us 186140 10.53us 14.68us 20.90us 264.88% 273.19M
nbio_basedon_stdhttp 1000000 1000000 0 5.83s 11.63us 171658 11.38us 15.88us 23.48us 299.60% 179.62M
nbio_mod_blocking 1000000 1000000 0 5.89s 11.76us 169726 11.60us 15.36us 24.27us 260.65% 169.28M
nbio_mod_mixed 1000000 1000000 0 5.78s 11.54us 173048 11.34us 15.34us 24.67us 306.75% 202.17M
nbio_mod_nonblocking 1000000 1000000 0 8.03s 16.04us 124501 15.31us 26.78us 38.62us 256.73% 61.99M
nhooyr 1000000 1000000 0 8.61s 17.19us 116171 16.03us 20.73us 53.48us 340.32% 565.29M

后面再看看要不要支持excel、生成image之类的,感觉没太大必要

lesismal commented 1 year ago

这几天搞这个也是挺累,得歇一歇了

lxzan commented 1 year ago

信息量很大,需要很多张图,一张图只能对比一个维度。不出图也没关系。

lxzan commented 1 year ago

很棒了,好好休息吧

lesismal commented 1 year ago

信息量很大,需要很多张图,一张图只能对比一个维度。不出图也没关系。

是的,所以我README TODO里新增了一些内容,以及report文件支持配置后缀,都是为后面自动跑多轮做准备的:

  1. Different Args
  2. Add more frameworks
lesismal commented 1 year ago

几个脚本都拆了下,单独测试也方便,然后就把nbio百万连接测试说明也放到README里了,方便用户嗨起来,哈哈哈

lxzan commented 1 year ago

不给百万连接找个参照物吗😄

lxzan commented 1 year ago

我想提个PR把客户端换成gws,一万连接还是撑得住的🐸

哎,明天得认真上班了

lesismal commented 1 year ago

我想提个PR把客户端换成gws,一万连接还是撑得住的🐸

你先跑跑看gws百万占用多少内存,得高配点机器才行了

所以不要来PR gws client了,或者单独起一个目录也可以

lxzan commented 1 year ago

百万连接再见

lesismal commented 1 year ago

8K*1M,协程基础内存就8G了,压力有点大,STW也会非常不友好,而且是持续占用,手动GC能解决一小部分问题

lesismal commented 1 year ago

其实这种 echo 测试, gorilla 那些允许用户自己 ReadMessage/NextReader 的 client 也可以做,不需要每个连接持久占用一个协程,nbio-examples/websocket_1m 就是用 gorilla 做 client 的。 但是真实的业务里它们往往做不了,我之前是考虑可能会加入更复杂的压测功能,所以就没用它做。

之前给你提的几点还有一些你不打算做的,我再列一下:

  1. 把 Read 接口放出来,允许用户自己掌控什么时候都
  2. WriteMessage 大包分帧
  3. OnFrame 这种,免得单个 Message 过大

nbio因为主要是异步,所以通用的接口做不了 Read 外放给用户了。只能在 IOModBlocking 的情况下支持、以及同步解析器,但是我不想搞它们了,兼容各种功能的代码复杂度太高了

还有啥来着,有点想不起来了

lxzan commented 1 year ago

设计理念不一样,gobwas是手动挡,而gws是自动挡。

1.5.x我不打算加新特性了,大包优化以后再考虑加吧,超过阀值把消息写入临时文件?

ReadMessage是不可能暴露的,暴露出来现有的API设计全毁了

lesismal commented 1 year ago

超过阀值把消息写入临时文件?

跟这个没啥关系

ReadMessage是不可能暴露的,暴露出来现有的API设计全毁了

不会的,我列的3个都可以继续兼容现在的

lxzan commented 1 year ago

ReadMessage 暴露出来的话 , OnPing, OnPong, OnMessage 全部会失效; 错误处理需要手动触发; 分帧需要手动合并; 任务队列那些参数也没什么用了. 大大提高了普通用户的学习负担, 然后又给我提 issue

lesismal commented 1 year ago

ReadMessage 暴露出来的话 , OnPing, OnPong, OnMessage 全部会失效; 错误处理需要手动触发; 分帧需要手动合并;

各走各的,ReadMessage不复用现在的ReadLoop、里面不主动回调就可以了

任务队列那些参数也没什么用了. 大大提高了普通用户的学习负担, 然后又给我提 issue

任务队列是异步写的队列?如果是写,不受这个读的影响 好些天没看,不记得gws里具体的了

lxzan commented 1 year ago

各走各的,ReadMessage不复用现在的ReadLoop、里面不主动回调就可以了

各走各的太割裂了. 我不追求功能的大而全.

任务队列是异步写的队列?如果是写,不受这个读的影响 好些天没看,不记得gws里具体的了

读写都有任务队列.

lesismal commented 1 year ago

刚扫了下: https://github.com/lxzan/gws/blob/master/reader.go#L162

这个不该叫 ReadAsyncEnabled ,而是异步处理消息才对,用户自己 ReadMessage 时这个选项无效就可以了

lxzan commented 1 year ago

没想到好名字, 将就着用吧

lxzan commented 1 year ago

50000连接下gws和nbio_mod_nonblocking表现比较接近了;

100000连接gws已经不能正常完成测试

lesismal commented 1 year ago

没想到好名字, 将就着用吧

nbio里的配置项也是有点多,有的内容我自己也得每次查了才知道,时间久了的都快忘记有某些可配置的内容了

lesismal commented 1 year ago

100000连接gws已经不能正常完成测试

我机器上其他框架10w还好,nhooyr太拉垮了跑不了

lxzan commented 1 year ago

可能我给虚拟机的配置太低了

lesismal commented 1 year ago

嗯,配高点试试。

lxzan commented 1 year ago

字节那个websocket内存占用挺高的