< 返回版块

林深好材 发表于 2025-07-03 17:29

Tags:websocket,性能,CPU

断断续续的学习rust有一段时间了,终于上手用 tokio+fastwebsockets+crossbeam-channel 弄了个websocket服务器,以编译通过和业务正确为目标,没做特殊优化。测试下来,感觉性能不是很理想:

1、1000个客户端连接时,只有5秒为间隔的ping/pong,没有其它数据,cpu占用150%; 2、3000个客户端连接时,能正常工作,每个客户端只能接收6条消息每秒(每条消息大小约200byte)cpu占用高达400%; 3、更多连接时,出错几率大,基本不能工作;

想了解下,一个rust websocket服务,正常情况下(无性能bug,但是也没做特别优化),可以同时保持多少个连接,每个连接可以推送多少个消息,cpu占用是多少。

评论区

写评论
Bai-Jinlin 2025-07-04 13:00

你不会是用的std的sleep,和crossbeam-channel会block线程的send recv来写的tokio异步代码吧。。。

--
👇
林深好材: 火焰图不知道怎么折腾上来。下面是最核心的代码,晚上将crossbeam-channel换成了channel换成totio的,同时移除下面代码中的sleep(interval);,cpu方面的问题基本小时了,20K 连接 6%的样子

loop {
            match sender.try_send(info.clone()) {
                Ok(_) => break Ok(()),
                Err(err) => {
                    match err {
                        TrySendError::Disconnected(_) => break Err(ChannelError::Disconnected("连接已断开".to_string())),
                        TrySendError::Full(_) => {
                            if retry_times > max_times {
                                let micros_elapsed = interval.as_micros() * retry_times;
                                break Err(ChannelError::Busy(Duration::from_micros(micros_elapsed as u64)));
                            }
                            retry_times = retry_times + 1;
                            sleep(interval);
                            continue;
                        }
                    }
                }
            }
        }

--
👇
Bai-Jinlin: 1. 发出来代码。 2. 用perf看一下耗时点。

asuper 2025-07-04 09:33

你的N个测试客户端,是开了N个线程 + sleep()来控制的吗?建议都换成tokio的异步,线程切换开销还有有点消耗的,sleep()换成 tokio::time::sleep()

作者 林深好材 2025-07-04 08:37

火焰图不知道怎么折腾上来。下面是最核心的代码,晚上将crossbeam-channel换成了channel换成totio的,同时移除下面代码中的sleep(interval);,cpu方面的问题基本小时了,20K 连接 6%的样子

loop {
            match sender.try_send(info.clone()) {
                Ok(_) => break Ok(()),
                Err(err) => {
                    match err {
                        TrySendError::Disconnected(_) => break Err(ChannelError::Disconnected("连接已断开".to_string())),
                        TrySendError::Full(_) => {
                            if retry_times > max_times {
                                let micros_elapsed = interval.as_micros() * retry_times;
                                break Err(ChannelError::Busy(Duration::from_micros(micros_elapsed as u64)));
                            }
                            retry_times = retry_times + 1;
                            sleep(interval);
                            continue;
                        }
                    }
                }
            }
        }

--
👇
Bai-Jinlin: 1. 发出来代码。 2. 用perf看一下耗时点。

Bai-Jinlin 2025-07-03 20:35
  1. 发出来代码。
  2. 用perf看一下耗时点。
1 共 4 条评论, 1 页