-
Notifications
You must be signed in to change notification settings - Fork 9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
请改进利用多核CPU的计算能力 #2548
Comments
为什么要在路由器端跑呢?设备端不香吗? |
Golang 的协程是默认支持多核的,或者说不应该始终只有一个核心在处理任务。 |
在路由器上跑,路由器下面的所有设备自动具备访问油管的能力,无需对每个设备进行任何额外设置,哪怕一个不支持跑v2ray的8块钱的IOT设备也能自动翻墙了。 |
实际情况是路由器的CPU占用是28%-30%,而不是全部利用起来的CPU占用80%-90%,很明显只用到了单核。 |
那可能相关代码里并没有用协程,这的确是可以被优化的地方。 |
简单思考了一下,优化方案不应该是将单条流的加解密分配给多核(这可能是一个连续的过程,强行拆分只会让速度更慢),而应该是用协程(多核)同时处理多条流,包括加解密,改起来也更简单。 性能会有很大的提升,但我现在并不熟悉 v2ray-core 的整体代码,请项目组大佬们优化一下。 |
Who was that guy again saying V2 can never max out your CPU just a few days ago? @Kylejustknows |
其实不止这里可以优化 比如我知道一个不错的 ws 库:https://github.com/nhooyr/websocket 以及一个更高性能的 json 库:https://github.com/json-iterator/go go.mod 里面的几乎所有库都有更新不止一个版本(当然,我指的是小版本) 然后在 ARM64 平台上的 AES 指令集有点迷,按理来说应该因为 golang 两年前的一次升级而自动支持了,但总有人说没有开、耗电 |
lmao yea that was me 👍 saying that. On one of my cheapest VPS the v2ray maxed out @ ~7% CPU when its at hundreds mbp speed. |
V2 maxing out CPU on server is difficult, yes, but on client not so much. The point is, what you consider purely theoretical (or at least insignificant) improvement in performance is very real and important (in a everyday use case) to others. I'm by no mean a performance fanatic (like @RPRX), but we should never be cavalier about performance. |
补充:我在树莓派2上也发现同样问题。v2ray跑满单核,4K高码率60fps单流依然卡顿,而树莓派2是4核CPU,用top看CPU使用率35%。 |
@RPRX v2ray有使用 v2ray-core/app/proxyman/inbound/worker.go Lines 112 to 114 in 6b5d2fe
|
Can we first make sure if this issue is because of compilation settings, or if changes in the code is needed? |
@JimHan75d8c5 我之前也下载代码看了,很多地方用了协程,所以这就是奇怪的地方,不应该只用到一个核心 |
@RPRX |
@JimHan75d8c5 WebSocket 的确只有一个连接,但 VMess 和这是解耦的。或许问题出在里面的多条流没有用协程(比如 VMess)。 |
@JimHan75d8c5 我觉得很可能是这样,毕竟其它底层协议是一次性连接,所以现在的代码可能只在底层协议那个层面用了协程。但 WS 是特殊情况:长连接和连接复用,那么仅在 WS 的层面用协程是不够的,里面包裹的协议也要用协程才行。 |
@RPRX
可以试试用几个不同的浏览器同时打开4k视频,如果还是只用到单核那就是
我印象中
如果这里出问题,将 |
@JimHan75d8c5 抱歉,没往那方面想。 我刚刚测试了一个 youtube 视频,加载网页组件是 HTTP/2 的多路复用(并发,用同一个 TCP 连接),加载视频是 HTTP/1.1 的 keep-alive(序列,不过也是同一个 TCP 连接)。加载视频是 HTTP/1.1,有点意外,因为 keep-alive 是阻塞的,同一时间只能有一个请求,看来问题就在这里了。 |
@JimHan75d8c5 WebSocket 的情况是,一个连接建立之后,v2ray 只会用这个连接,直到它关闭为止,所以如果一个 WebSocket 内所有的 VMess 加解密始终只用一个核心处理就很尴尬了(我猜应该不会是这样吧)。 |
说到“只建立了一个链接”,我想提一下我之前开的一个 issue ,大意是把一个连接在v2ray的发送端使用多条连接发送,在接收端接收这些连接并重新组装成一条连接(类似多线程下载),以此来提升传输速度。如果把“多线程下载”的连接数设为和cpu的核心数一样,让每一个核负责一条连接的解密,这样是不是可以提升性能的同时提升传输速度(或者说绕开单条连接传输速度的上限) |
如果加密是调用的C/C++库的话,是不是编译库的时候使用OpenMP做循环展开就能支持多核加解密了? |
你们把多核想的过于简单了。线程之间同步什么的也是要消耗资源的。然后很多解密操作根本没办法分散到多核因为数据之间是有依赖的。最后V2不是从0开始写的,如果库自己不带多核处理那V2也没办法带上多核处理。如果开了多条连接进行下载,应该每个连接是可以独立处理的,这个之上的一个连接的数据分多个核就会比较困难了。 |
在现代加密算法设计上,算法的可并发计算绝对是重要考量项目,无论是美国的加密标准AES还是中国的国密标准,都是支持多CPU并发计算的的加密算法。 |
This may be true for decryption in the narrow, algorithm sense - but often not in the real world due to interdependence of different parts of the data within a given protocol. For an example, if part of the data being decrypted is some sort of authentication, you might want to wait for that part to finish (and successfully authenticate) before you proceed with decrypting anything else. |
说反了吧,路由器跑才香吧 |
这是BUG,不是单核心问题,你跑到25%那么大是不正常的 |
加密算法可并行计算是没有问题的。问题是:v2ray服务器不停地收到客户端数据包流串,每个包尺寸都很小,解密周期很简单,“不值得”把一个小包强行分拆到几个CPU来并行计算;但,如果强行把单个小包随机送到各个CPU线程来解密,因为客户发的所有包都“无状态”,解密完后必须加等待周期来汇总给包排序,增加的标记、分配、排序的运算量和增加的延迟,最终结果可能还不如分配一个TCP连接单独给一个CPU线程负责(更别说强行分配每个包增加的代码复杂度) 多数其他的高性能服务器(比如说网页服务器),也都是这么设计的;当几百、几千用户连接的时候,各个TCP连接会随机分配到CPU各个线程,很少听说有把一个TCP握手也强行分配给几个CPU线程来计算的。 现在的代码看起来,如果v2ray服务器连入几十用户,它是会把各个CPU线程都利用起来。但如果是单用户+单独一条TCP接入,那可能只会用到一个CPU线程。 |
我在使用小米路由器3G上也碰到了这个问题,MT7621处理器运行v2ray(ShadowSocksR Plus+)只有单线程调用,表现为使用Chrome浏览单个youtube视频最大码率是15mps,CPU占用25%;但如果浏览两个youtube视频最大码率分别分12mbps和11mpbs,CPU占用50%,总码率为23mps。证明v2ray对单个浏览只调用一个线程,无法完全发挥MT7261的处理性能。对比斐讯N1盒子,浏览单个youtube视频最大码率能到360-400mps,CPU占用能跑满。所以这应该是v2ray在MT7621上线程调度的bug。 |
就如小樱所讲,主要也是兴趣导向。我们也没有这种路由设备或者说没有需求,加上还有很多工作需要处理,最大的可能还是无人认领。 你可以Fork这个仓库,然后尝试修改(或者维护一个路由性能优化版本),这是最快的办法,并且能够分享给其他所有使用的人。 这个社区也欢迎各位的加入,参与到各个方面的工作。 |
MT7621的HW crypto设备驱动也快做出来了,因为MT7621处理器具有硬件AES加解密的片内资源。 |
@1265578519 chacha20的测试参数我搞清楚了,用MT7621测了一下64字节报文速度在28MB/s,可见用上openssl完全不会卡,现在的v2ray 2.5MB/s的性能问题不应该怪路由器CPU不行,毕竟其他程序就没这么慢,作为3W功耗的千兆路由器MT7621性价比还是很高的。
|
@kslr 如果没熟手接手的话,我也可以试试,不过我做就得等我先读完https://tour.golang.org/以及crypto/cipher crypto/aes 以及openssl库的用法之后了,粗略看了一下,golang的aes库和其他加密库的调用方式完全不同,要按它的方式实现一个接口,才能尽量少的改动v2ray原有的加解密部分。 |
你可以先评估一下工作量,如果工作比较多,我更建议的是维护一个优化版本。 |
如果实现接口,其实v2ray的部分应该不用动import之外的代码,sed搜索替换字符串"crypto/aes"替换为v2ray.com/core/common/crypto/openssl/aes"再编译就可以了。 |
如果 v2ray 不考虑以后开启 CGO 编译,用到外部的东西,我的建议是维护一个优化版本 潜在的麻烦请参考 v2ray/discussion#754 (comment) (歪个楼)其实你可以试一下 VLess,省一些硬件:https://github.com/rprx/v2ray-vless |
@RPRX 我的服务提供商最近从SSR全面换到V2RAY我才跟过来的,因为他那些服务器还比较稳定整个六月份都没掉链子所以我暂时也不打算换一家。所以他没提供VLess服务之前,我也是用不到的。 |
看下来我有两个问题:
|
是的aes-128-gcm要慢一些,但也在可以播放4K视频的范围内。
|
我之前测试过,youtube 加载单个视频时居然同时只有一条流,还是 http/1.1,你也可以看一下 |
如果我没理解错的话,替换到的 aes 库是对 c 写的 openssl 的封装,此时编译需要开启 CGO,并且使用对应架构和系统的 c 编译器。。。所以这个特定平台的优化版本,是否属于“额外维护”其实没有什么区别。 |
因为使用OpenWrt工具链构建依赖openssl的v2ray版本啊,这一套工具链很成熟的,而且有专门团队维护。 |
有针对就很简单,我的意思是无论怎样都算“额外维护”,与是否加入官方构建版本无关。 |
@RPRX 现在讨论这些还太早,我读Go指南也才到flowcontrol/1章节。就算搞出来openssl库的接口了,也要看iperf3 benchmark最终的结果数据,才知道这种路线有没有价值。只不过目前看来这个是付出代价最小的性能提升方式而已。 要是Go和C的混合方式效果还是不好,我重新用C写一份VMESS的redir极简实现,无非也就一两千行代码而已,一两百KB的执行程序,不比编译个16.4MB的v2ray放在路由器上舒心多了,而且速度还快。 |
加油,go 把密集计算交给 c 肯定会提升些性能的 不过这个。。。用 c 重现 vmess,一两千行后面可能得加个零(但有兴趣的话值得一试)。vless 能短时间内实现的原因,一是大量复用了 v2ray 已有的轮子,二是主要是对 vmess 的精简,即使这样也是新增了两千行左右的代码,这还是用 go 语言。。。 |
@RPRX tls+wss的类似v2ray的精简实现,两年多以前就有人用C写出来了,客户端1118行,服务器端753行,C库用了libevent和openssl。base64其实openssl里面就带作者可能不知道,还弄了个不知名base64的实现。 |
我的理解是要用 c 写同等功能的 vmess,这样才能保证兼容性,其中至少要有 vmess 编码解码、多路复用等必要功能的代码,然后还有一些非核心代码比如解析配置文件等。以及,非通用的轮子应该算入代码行数。总之,最终肯定也与完成度有关,如果是将现在用到的功能转译成 c,上万行是很有可能的。 |
@RPRX 给路由器用的极简实现,当然只考虑能把包转发到v2ray的server端,就完事了,其实连内置dns和geoip都不需要有,ipset+iptables+一些脚本就可以搞定。分开国内国外域名解析的DNS也有一堆现成的。 |
This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days |
怎么就从占用率认为是单核了,这个不好确定
在 2020年6月7日星期日,nobk <[email protected]> 写道:
… Golang 的协程是默认支持多核的,或者说不应该始终只有一个核心在处理任务。
实际情况是路由器的CPU占用是28%-30%,而不是全部利用起来的CPU占用80%-90%,很明显只用到了单核。
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#2548 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADB5GWL5HG7KFE7Y7VYU6PTRVLWJNANCNFSM4NWSNJEQ>
.
|
难道不是因为k2p的CPU太垃圾了吗?我10510U咋不卡? |
改用PC虚拟机运行v2ray则因单核性能强大,全无卡顿。 你在当复读机? |
现在很多路由器的CPU已经是多核的了,例如MediaTek MT7621A是双核4线程的CPU。
针对MT7621编译出的v2ray mipsel版本的执行文件,观看单条流的4K油管视频时,在路由器后台用top命令,可以看到CPU占用在28%-30%左右。
实际是将CPU的单核跑到100%左右了,而且造成计算力瓶颈,高码率4K视频观看卡顿。
改用PC虚拟机运行v2ray则因单核性能强大,全无卡顿。
如果单条流的加解密能使用多线程来进行,将MT7621A的空闲CPU算力也利用起来,而不是单线程加解密计算,应该能解决这个问题,让4K视频能顺畅观看。
能否考虑进行这部分的优化呢?
The text was updated successfully, but these errors were encountered: