Golang Go语言中哪个 websocket 好用?
gorilla 已经不维护了
Golang Go语言中哪个 websocket 好用?
更多关于Golang Go语言中哪个 websocket 好用?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
- gorilla 虽然不维护了,但是生产被用了那么多,已经足够稳定,可以继续使用,从另一个角度讲,人家足够稳定没有必要继续维护了,凭什么就不能用了
2. 基于 gorilla 的 melody 接口设计比较不错,推荐
3. gorilla 虽然不错,但性能一般,而且需要类似 melody 那种做些额外的封装,比如广播场景需要单独的写协程、否则遇到单个 conn 阻塞可能导致其他 conn 被卡
4. fasthttp/websocket 在 gorilla 基础上改造,性能也一般
推荐下我自己的吧:
https://github.com/lesismal/nbio
1. 可以直接基于标准库 http 的框架之上使用、性能好于 gorilla ;
2. 可以使用 nbio 自带的 poller 作为网络异步 io ,能够支持海量并发比如百万连接,而其他基于标准库阻塞 io 接口的框架连接数太多时协程数量太大,内存容易 oom ,gc 容易卡顿;
3. 支持多种 io 模式,IOModMixed 模式下能够同步阻塞 io 与异步非阻塞 io 共用,新连接到来时根据当前在线量是否在设置的阈值以内,低于阈值使用标准库的同步阻塞 io 接口获得更高性能,高于阈值使用 nbio 的异步非阻塞 io 、协程数量最高占用配置的数量、动态退出,协程数量、内存各项占用均衡稳定
4. 不需要额外封装读写协程,只需要设置好 OnOpen/OnClose/OnMessage/KeepaliveTime 等用户需要的参数,用户专心处理业务逻辑
欢迎也来瞧瞧。gws 比较新、我也有提 issue 可以看下
nbio websocket 直接基于标准库 http 的例子以及多种 io 模式的说明:
https://github.com/lesismal/nbio/releases/tag/v1.3.5
旧帖发了那么久,一条回复都没有:
https://www.v2ex.com/t/892703
本来想推荐你的,没记起来项目名字,他最近发了个对比帖所以记得他的
哈哈哈,感谢关注支持!
刚看到 melody 里有人提到因为 gorilla 不维护了、要不要切换到基于 nbio 或者其他基于框架,我也去凑热闹回复了下
https://github.com/olahol/melody/issues/73
魔改的 x/net/websocket [websocket/x]( https://github.com/Asutorufa/yuhaiin/blob/main/pkg/net/proxy/websocket/x/server.go)
谢谢老铁
自荐一下 gws, 性能在基于 net/http 的 websocket 实现里面可以说是一骑绝尘
### Features
- 无依赖
- 每个连接只会有一个常驻的协程
- 支持异步非阻塞 Write; 支持单连接内并发处理多个请求, 控制好了并发上限
- 默认模式下即可 100%通过 autobahn-testsuite websocket 协议测试
https://github.com/lxzan/gws
https://dev.to/lxzan/go-websocket-benchmark-31f4
gorilla 比 nhooyr 和 gobwas 强多了,但性能和易用性不如 gws
感觉 nhooyr ws 的 net.Conn wrapper 挺好用的
可以看看我的 WebSocket Event ,借鉴自 JavaScript
nhooyr API 挺精简的,但 rps, latency, cpu 均不如 gorilla
我最近公司项目,用的 go 自带的 ws,不清楚各种 ws 库主要差别在哪
golang.org/x 那个很挫
差别在于性能,feature, 以及对 websocket 协议的支持程度.
大神也有维护 melody 啊,牛逼
哈哈哈,没参与日常维护,就之前偶尔读了下 melody 源码,发现那有个并发的问题会低概率导致 panic ,肉眼看出来,写测试一模拟果然就复现了,然后 pr 了下,那时候正好是疫情严重时期,作者消失很久了,我都担心他会不会感染了严重了之类的,还好后来他又出现了,并且 merge 了我的 pr
一些知名库的作者对并发这块的实现其实也不够好,一是被 go 官方和很多人鼓吹要用 chan 、少用锁,二是 go 这种多并发流确实复杂、肉眼难看出问题、测试压测也很难测出问题、甚至没办法模拟复现只能靠肉眼和想象力。。。
最近一个比较火的 conc 库也扫了几眼,接口设计非常优雅美丽,但是代码的实现也是受到太多尽量用 chan 少用锁这种观点的影响,所以它的实现是性能差一些的,不过这点性能损失对通常的项目也没什么影响、也还好
#9 gws 不是一骑绝尘的。。。你看我 #19 ,你把 tinyws 和 nbio 的 IOModBlocking 和 IOModMixed 也跑来对比下试试。。
nbio 的 websocket 解析器,是支持异步流数据解析的、同步 io 的数据丢进去也一样解析,所以本身是有点吃亏的、逻辑比同步解析复杂得多,而且涉及半包 cache 之类的,否则只是同步解析,还能实现得更快。同步和异步 io 都能处理,所以结合自身的 IOModMixed ,能把性能和硬件消耗做到最佳,不同在线量全 cover ,其他框架高在线量太吃硬件资源了
好像很久没出现了,是在忙着搬砖嘛 :joy:
做测试很费时间,在测评里我只测了 1KiB ,
是啊,多个框架跑一轮还得统计很麻烦,而且可以测试得内容太多了,tls non-tls http ws rpc 各种,所以一些项我也只跑了简单测试
别提了,搬砖已经冒出火星子了。最近最大的痛点就是搬得不够快。副作用就撸了一个 https://github.com/antlabs/h2o ,日产千行代码不是梦。
用 Prometheus+Grafana 统计挺方便的,就
就怕机器不够强大
我是超级不喜欢 grpc ,哈哈哈,用我自己的 arpc 一把梭才是爽。。。
#27
这有点杀鸡用牛刀了,而且还是要统计 qps/tps 结合进程自己的消耗,压测里自带这些工具就可以的,比如字节这种:
github.com/cloudwego/kitex-benchmark
但是字节这个 perf 不跨平台,我自己用 gopsutil 简单封装了些:github.com/lesismal/perf
我之前的简单压测是几个字节的 payload ,刚才又试了下 1k 字节 payload ,我环境得到的数据:
1k-1w 范围连接数时,tinyws 和 gws qps 差不多,nbio 略快,内存占用 gws > tinyws > nbio ,但内存差距不算特别大
10w 连接时,nbio 快更多一些,内存占用 gws 约 4.17G ,tinyws 约 3.73G, nbio 约 1.2G ,内存占用差距比较明显,而且 gws 和 tinyws 的 qps 不稳定、qps 摆动幅度较大,应该是连接数太多 gc 时 stw 更明显导致,nbio 的 qps 比较稳定
相同连接数压测的 cpu 消耗差不多,nbio 好像略低
连接数太多 net/http 肯定干不过 gnet/nbio 这些实现的
ws 客户端我是用的 tcpkali, cpu 占用率超低
刚测了一下 1000 连接, nbio IOModBlocking 跑了 2600Mbps, gws:dev 同步读异步写是 5800Mbps, nbio 兼容多种 IO 模式是有开销的吧
Prometheus+Grafana 可视化效果好, 配置一次就可以了, 有钱的话真想搞一台线程撕裂者, 跑 k8s 来做测试.
很多人被带偏了,无脑选择 channel 。随便想想就知道,有锁的 channel 怎么可能比直接用锁高效
> 刚测了一下 1000 连接, nbio IOModBlocking 跑了 2600Mbps, gws:dev 同步读异步写是 5800Mbps, nbio 兼容多种 IO 模式是有开销的吧
代码发我下我试试看。多种 io Upgrade 后就没什么大影响了
go 做简单 curd 确实不难,但是这种遍地并发对绝大多数人来说都挺难的,chan 适合解耦、串行化,能避免并发不熟的人一不小心就死锁了,但是性能肯定差一些
运维用这种监控集群健康挺好,做 benchmark ,尽量保持测试环境稳定、少部署额外软件好些
测试环境是 Ubuntu20.04
https://github.com/lxzan/go-websocket-testing
对 channel 使用不熟悉也很容易死锁
用普罗米修斯监控确实影响了测试 RPS, 同样的命令, 去掉监控后跑到了 8000Mbps, 加上监控只有 4400Mbps.
但是我那个测试项目里面, gws 和 nbio 运行条件都是一样的
gws 同步读同步写: Aggregate bandwidth: 4384.217↓, 4381.833↑ Mbps
nbio 阻塞模式: Aggregate bandwidth: 2558.850↓, 2471.334↑ Mbps
命令: tcpkali -c 1000 --connect-rate 500 -r 2000 -T 3000s -f assets/1K.txt --ws 127.0.0.1:${port}/connect
#42
我刚跑了下 tcpkali ,按照你的参数确实 gws 更快,但是我本地得到的数据差异没那么大。
netstat 查了下,tcp 收发缓冲区待读写的 size 较大、远超过单个包 size ,加上 tcpkali 的-r 参数你设置的 500 (每秒向每个连接发送 500 个包),这说明 tcpkali 压测方式是不管对方是否回包,都会按照-r 这个频率往对方发包。
nbio 的解析器是异步流解析器,在-r 500 这种测试情况下,相比于 gws 的同步读同步解析,nbio 要处理更多的包边界、半包缓存之类的,所以会不划算。但实际场景中单个连接 client 向 server 每秒 500 个包是不太可能的、fps 类也远低于此。server 端推送也不会有这么高的频率。如果是有人来攻击 server 、这个连接响应慢了也不怕。
1000 连接这种,如果把-r 调整到正常交互频率,性能就都差不多了。
我又尝试把-r 20 、连接数提高到 2w ,nbio 的数据会更好些:
tcpkali -c 20000 --connect-rate 5000 -r 20 -T 30s -f ./1K.txt --ws 127.0.0.1:28001/ws
2w 连接 gws 遇到过一次不知道是不是触发了 bug ,2w 在线、协程数却达到了 3w+,tcpkali 30 秒竟然也没返回,不知道是不是 tcpkali 测试 bug 导致不断有新连接才导致 gws 协程 3w+,忘记了保存现场、后面多跑了几轮没再遇到,所以暂时没法分析这个了
更大连接数用 tcpkali 不太好测了,多个节点一是卡、二是建立连接的时段不一样,有的节点建立连接后就开始猛发数据把 server 打满了,新节点再进入就困难了。但一些海量连接的业务的话可能是连接数多但频率没这么高所以新连接进来速度也还好。
这也是为什么我之前没用第三方的工具进行百万链接的测试、而是自己写 client 来测试的原因:
https://github.com/lesismal/nbio-examples/blob/master/websocket_1m/client/client.go
tinyws 在-r 500 的情况下跟 nbio 差不多可能略慢,我没看 tinyws 的代码、暂时没有分析慢的原因
> 用普罗米修斯监控确实影响了测试 RPS, 同样的命令, 去掉监控后跑到了 8000Mbps, 加上监控只有 4400Mbps.
对,额外的重量级工具本身带来的消耗影响大,而且他们的消耗也不是平均持续稳定的、没法保障对不同框架测试时段的环境公平性,所以大家做压测通常不使用这些
我能想到的高频发包的场景,比如 RPC ,但是 RPC 通常内网,TCP 更具优势(所以我非常抵制 GRPC ),而且 RPC 服务承载的 client 连接数并不会特别大,所以基于标准库同步方案、同步解析就 ok 了,我的 arpc 也是这样。但是 arpc 也支持 web 前端 client 直接通过 http/websocket 交互,这时候虽然可能连接数量也很大,但是这种用户并不是服务之间的 RPC 调用、所以也不会有服务之间 RPC 那种单个连接高频发包的场景、真有攻击的话它自己这个连接慢了也活该。。。
我暂时没看懂 tcpkali 有没有办法进行类似 echo 测试这种,发-收-发-收,这样即使连接数不是特别大也可以把 server 性能跑满、更符合实际场景一些,而不是像上面那样通过-r 超过正常需求范围的情况下打满
iops 较低的情况下,gorilla, gws, nbio 性能都够用了,上限越高说明库本身的开销越小
没有任何业务负载的情况下,gws 的性能上限是每秒收发各 100w+个 1KB 的 websocket frame ,可以看到上下行带宽是对等的
#46
不同的参数下,跑出来的数据是不一样的。 -r 500 这种,在正常的服务里限流机制直接就把它 close 了的。
不同连接数、包体、 -r 取正常值范围的情况下,你可以试一下看看各个框架带宽和消耗能跑到多少,我环境下得到的数据并不是哪个固定第一,cpu 占用有差别,有的 cpu 高一些但是同样获得了更高的吞吐,有的 cpu 利用率上不去、跑多轮也还是低消耗低带宽比较奇怪。框架数量太多参数太多,跑几轮下来我眼睛都花了
不能只以一种参数来确定性能
控制下变量就很好对比性能了, 同样的网络库, 连接数和 IOPS 下, 对比延迟分布, 延迟百分位和 CPU 内存占用. nbio 我最佩服的是手搓 tls, 那玩意一看就不简单.
对,得多弄点不同变量参数对比,鸟窝老师 rpc 的测试里不同参数对比就相对全面一些
tls 直接标准库 copy 一份魔改的,难度倒是不大,主要是琐碎,debug 、覆盖比较烦躁
好些个开源的 IM 项目用的都是基于标准库同步 io 的 conn ,真要是在线量大,他们那个服务器节点数量成本会很高,如果换 nbio ,估计能省掉至少三分之二硬件成本,集群内部通信用的 GRPC 如果换成 arpc 走 tcp 、性能又能提高不少。
nbio 最初的定位是解决 1m-connection ,几个月前还都不支持多 io 模式的,一般在线量的场景,纯 poller 的响应性能跟基于标准库的相比实在是没得比,现在平衡多了
其实如果放到量大的业务上做基础设施,都能省很多成本。但如果真的量巨大,公司有钱,还是 rust 或者 c/cpp 好些。前阵子 cloudflare 说他们内部的 rust proxy 性能相当好
go 版本的这些,跟 rust/c/cpp 的相比,实在是撵不上了,如果还年轻,我就去玩 rust 了,但是年纪不小,玩不动了
#32
我最早的时候是看到 evio ,国人又有人改进写了 gev 和 gnet ,想直接用他们的,但是功能太少了,只能用于 4 层,7 层自定义协议,tls/http/ws 这些统统没有,而且 gnet 性能略好于 gev ,但是没有实现 net.Conn ,想基于它封装也是非常麻烦,所以放弃了,自己撸着玩,慢慢就把功能加得越来越多了
我本来想学 rust 刷题玩玩,直接劝退了,写点数据结构太劳心了.
不看好 rust ,门槛决定了小众,底层开发才会考虑.
c/cpp/rust 掌控力强,我就最喜欢 c void*,无拘无束,go 虽然写着省力写的快挺爽,但是找不到那种尽情优化做到极致控场的感觉,虽然爽但爽不到极致,只是均衡的感觉
c/cpp 自由,rust 是被编译器教做人
我是真有点想搞 rust 了:
mp.weixin.qq.com/s/1dB4P54tVz-aM2iYIkE4fg
时间充裕就学起来吧
被编译器教做人, 哈哈,笑死
自引用结构没法玩
gobwas/ws 存在明显缺陷,我有在它的 issue 列表里讨论,有兴趣可以翻看下。作者的意思是不想解决并且 close 了 issue (其实按 gobwas 的思路也确实没办法解决)
在Go语言中,有多个优秀的WebSocket库和框架可供选择,它们各有千秋,适合不同的应用场景。以下是一些推荐的WebSocket库和框架:
-
Echo:
- 优点:轻量级、高性能,且易用性极佳。它内置了对WebSocket的支持,并提供了一个方便的API来处理WebSocket事件和消息。
- 适用场景:适合大多数WebSocket应用,尤其是需要快速开发和部署的项目。
-
Gorilla WebSocket:
- 优点:成熟稳定,提供了一组低级API,允许开发人员完全控制WebSocket通信。可扩展性和定制性高。
- 适用场景:适合需要对WebSocket通信进行更精细控制的复杂应用。
-
fasthttp:
- 优点:高性能,非常适合处理大量并发的WebSocket连接。
- 适用场景:适合需要处理数千个并发连接的高性能应用程序。
综上所述,对于大多数WebSocket应用,Echo是一个不错的选择,它易于使用且功能丰富。如果需要对WebSocket通信进行更精细的控制,Gorilla WebSocket是更好的选择。而如果需要处理大量并发连接,那么fasthttp将是你的理想之选。在实际开发中,可以根据项目的具体需求和开发团队的熟悉程度来选择合适的WebSocket库或框架。