Closed lxzan closed 1 year ago
gev
支持百万连接, 你可以和它对比.
gobwas/ws
给我的感觉就是一个工具集, 能用但不成系统不好用. 我的readme里原来有它, 后面加了压缩测试, 嫌弃它开启压缩很麻烦给去掉了
建立1m耗时太久了, 节省时间测个10w就差不多了 😂
初版完成后我再来PR吧
考虑过加gev,但它不支持tls 所以我没加它
gobwas配合netpoll存在问题,所以我也没加。不打算加半成品或者缺陷明显的
目前支持TLS的百万连接方案只有NBIO, gnet有个TLS PR还没合.
比如conn无锁那个可能存在问题。它的issue里到现在还有悬案呢
周末写了个异步解析器demo, 和你们的大不一样啊
比如conn无锁那个可能存在问题。它的issue里到现在还有悬案呢
还有一个concurrent map writes的issue,作者没有回应
我那个异步解析器当时是不想在结构体上挂载多字段,所以没做状态机没把这些字段单独放到conn上。而是每次nextframe重新取,实际场景应该不至于那么倒霉每次只有读到一个字节,而且取那几个字段也就buffer上拿一下不会浪费太多,所以就取舍成现在这种了
帧头14byte放conn结构体上能避免重复allocs
帧头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是海量连接数优先,所以能少点字段就少点
parser的实现和read buffer相关性很高啊。我感觉LinkedBuffer加状态机的实现很完美了,但是nbio, gnet, gev都没用这种方案😂
parser的实现和read buffer相关性很高啊。我感觉LinkedBuffer加状态机的实现很完美了,但是nbio, gnet, gev都没用这种方案😂
你可以结合poller实现一下试试,如果好的话,欢迎pr到nbio来
是结合EpollWait写的异步解析器,已经能够解出message了,但是其他部分还非常不完善,得好好研究下你们是怎么处理epoll事件的,先看看效果。
一次系统调用从内核缓冲区读到公用的eventLoop.buffer,然后写入conn.LinkedBuffer,运气好的话可以直接回调OnMessage,运气不好的话从conn.LinkedBuffer copy一个新的Message.
连接方案只有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
-------------------------
刚加上了 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
避免了runtime频繁向系统申请内存,所以更平滑了?
估计是回收更及时吧
初版基本成型了,添加了 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 |
TP是延迟百分位吗, 纳秒换成毫秒好看点
没想到不开压缩 nhooyr/websocket
内存占用也这么高
我在 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 |
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之类的,感觉没太大必要
这几天搞这个也是挺累,得歇一歇了
信息量很大,需要很多张图,一张图只能对比一个维度。不出图也没关系。
很棒了,好好休息吧
信息量很大,需要很多张图,一张图只能对比一个维度。不出图也没关系。
是的,所以我README TODO里新增了一些内容,以及report文件支持配置后缀,都是为后面自动跑多轮做准备的:
几个脚本都拆了下,单独测试也方便,然后就把nbio百万连接测试说明也放到README里了,方便用户嗨起来,哈哈哈
不给百万连接找个参照物吗😄
我想提个PR把客户端换成gws,一万连接还是撑得住的🐸
哎,明天得认真上班了
我想提个PR把客户端换成gws,一万连接还是撑得住的🐸
你先跑跑看gws百万占用多少内存,得高配点机器才行了
所以不要来PR gws client了,或者单独起一个目录也可以
百万连接再见
8K*1M,协程基础内存就8G了,压力有点大,STW也会非常不友好,而且是持续占用,手动GC能解决一小部分问题
其实这种 echo 测试, gorilla 那些允许用户自己 ReadMessage/NextReader 的 client 也可以做,不需要每个连接持久占用一个协程,nbio-examples/websocket_1m 就是用 gorilla 做 client 的。 但是真实的业务里它们往往做不了,我之前是考虑可能会加入更复杂的压测功能,所以就没用它做。
之前给你提的几点还有一些你不打算做的,我再列一下:
nbio因为主要是异步,所以通用的接口做不了 Read 外放给用户了。只能在 IOModBlocking 的情况下支持、以及同步解析器,但是我不想搞它们了,兼容各种功能的代码复杂度太高了
还有啥来着,有点想不起来了
设计理念不一样,gobwas是手动挡,而gws是自动挡。
1.5.x我不打算加新特性了,大包优化以后再考虑加吧,超过阀值把消息写入临时文件?
ReadMessage是不可能暴露的,暴露出来现有的API设计全毁了
超过阀值把消息写入临时文件?
跟这个没啥关系
ReadMessage是不可能暴露的,暴露出来现有的API设计全毁了
不会的,我列的3个都可以继续兼容现在的
ReadMessage
暴露出来的话 , OnPing, OnPong, OnMessage
全部会失效; 错误处理需要手动触发; 分帧需要手动合并; 任务队列那些参数也没什么用了. 大大提高了普通用户的学习负担, 然后又给我提 issue
ReadMessage
暴露出来的话 ,OnPing, OnPong, OnMessage
全部会失效; 错误处理需要手动触发; 分帧需要手动合并;
各走各的,ReadMessage不复用现在的ReadLoop、里面不主动回调就可以了
任务队列那些参数也没什么用了. 大大提高了普通用户的学习负担, 然后又给我提
issue
任务队列是异步写的队列?如果是写,不受这个读的影响 好些天没看,不记得gws里具体的了
各走各的,ReadMessage不复用现在的ReadLoop、里面不主动回调就可以了
各走各的太割裂了. 我不追求功能的大而全.
任务队列是异步写的队列?如果是写,不受这个读的影响 好些天没看,不记得gws里具体的了
读写都有任务队列.
刚扫了下: https://github.com/lxzan/gws/blob/master/reader.go#L162
这个不该叫 ReadAsyncEnabled ,而是异步处理消息才对,用户自己 ReadMessage 时这个选项无效就可以了
没想到好名字, 将就着用吧
50000连接下gws和nbio_mod_nonblocking表现比较接近了;
100000连接gws已经不能正常完成测试
没想到好名字, 将就着用吧
nbio里的配置项也是有点多,有的内容我自己也得每次查了才知道,时间久了的都快忘记有某些可配置的内容了
100000连接gws已经不能正常完成测试
我机器上其他框架10w还好,nhooyr太拉垮了跑不了
可能我给虚拟机的配置太低了
嗯,配高点试试。
字节那个websocket内存占用挺高的
可以加,来PR一下啊。 我这个用的nbio自己的websocket client,是支持百万连接的。 昨晚上跑了下大概能这样: taskset 0-3 for server (4 cpu cores) 1m connection 1k payload arount 100k tps around 2g mem
gobwas的百万连接代码太麻烦了,我没加,不知道它的跑出来啥效果。其他库都跑不了百万连接