[独立开发] 单机 Rust 如何抗住 10w+ 在线行情推送?告别 Redis/Kafka,聊聊我的“极简主义”架构 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
kai92zeng
V2EX    程序员

[独立开发] 单机 Rust 如何抗住 10w+ 在线行情推送?告别 Reis/Kafka,聊聊我的“极简主义”架构

  •  
  •   kai92zeng 1 天前 2402 次点击

    大家好,我是《交易学徒》的独立开发者。

    最近在重构后端行情网关,目标是支撑 10w+ 同时在线用户。在技术选型时,很多“标准答案”是微服务、Redis 集群、Kafka 消息队列。但作为独立开发者,维护这一套重型架构的运维成本和心智负担太高了。

    于是我反其道而行之,选择了一种“极致单机”的方案:没有任何外挂组件( No Redis, No Kafka ),所有状态在进程内解决,纯 Rust 函数调用。

    经过实战验证,这套架构不仅部署简单(就一个 Binary ),而且足够稳定。今天分享一下我是如何用 Rust 的特性“白嫖”性能的,欢迎 V 友们拍砖。

    一、 核心理念:按需订阅,算一笔带宽的账 早期的 demo 喜欢大包大揽,客户端连上来就推 Top 20 币种。这在用户量大时是灾难。我的做法是“用户看哪里,就只推哪里”

    客户端停留在 BTC/USDT 的 15 分钟 K 线界面,服务端就只建立这一个订阅关系。一旦切换,立马移除旧订阅。

    算一笔账( Resource Cost ): 假设一个行情包 Payload 是 200 Bytes ,推送频率 5 次/秒。

    全量推送(推 Top 20 ):10 万用户 x 20 个币种 x 200B x 5 = 2 GB/s (带宽直接破产)。

    按需订阅(推 1 个):10 万用户 x 1 个币种 x 200B x 5 = 100 MB/s 。

    结论: 简单的逻辑改变,带宽节省 95%,单机千兆网卡轻松抗住。

    二、 列表行情:Polling + 边缘计算(白嫖 CF ) 对于“行情列表”这种一屏显示几十个数据的页面,建立长连接维护成本太高。 我采用了 1 秒轮询 + Cloudflare 边缘缓存 的策略。

    策略: 设置 HTTP 响应头,让 CF Edge Cache TTL = 1 秒。

    效果:10 万人同时刷新列表,99% 的流量被 CF 的全球节点挡住了,真正打到我源服务器 Rust 进程的 QPS 只有个位数。

    收益: 既利用了 CDN 的带宽,又保护了单机后端。

    三、 架构做减法:进程内通信替代中间件 这是我这次重构最大的感悟:单机并发足够高时,不需要 Redis 和 Kafka 。

    替代 Redis: 使用 Rust 的 DashMap (Concurrent HashMap)。数据就在内存里,读写是纳秒级,没有网络 IO 开销,没有序列化/反序列化成本。

    替代 Kafka: 使用 tokio::sync::broadcast 和 mpsc::channel 。

    优势: 传统的“发布-订阅”为了解耦上了 MQ ,但在单机 Rust 里,一个 Arc<Channel> 就能解决问题。部署时不需要操心 MQ 挂没挂,只要我的进程活着,消息系统就活着。

    四、 信使模式 (Messenger Pattern) 与背压 在 Tokio 异步编程中,最忌讳 await 阻塞。 如果客户端网络卡顿(比如进电梯),socket.send().await 可能会阻塞,导致同个 Loop 下的心跳包处理被卡死,造成“假死”。

    我的解法:

    读写分离: 为每个连接 spawn 一个独立的 send_task ,通过 mpsc::channel(128) 通信。

    严格背压 (Backpressure): 使用 try_send 。如果 Channel 满了(说明客户端来不及收),直接丢弃新行情。

    理由: 实时行情旧数据无价值。这行代码是系统的“保命符”,防止慢客户端拖垮服务端内存( OOM )。

    五、 极致性能:Zero-Copy (零拷贝) 在广播行情时,不要为 10 万个用户 copy 10 万份数据。

    Rust // 内存中只有一份二进制 Payload let payload = Arc::new(Bytes::from(vec![...]));

    // 10 万次分发只是增加了 10 万次引用计数( Reference Counting ) // 几乎没有任何内存分配开销 for client in clients { client.tx.try_send(payload.clone()); } 利用 Rust 的 Arc 和 Bytes ,让 CPU 缓存极其友好。 六、 扫地僧:资源清理 长运行的单机服务最怕内存泄漏。 当 socket 断开时,必须像外科手术一样精准清理:

    从 DashMap 移除 Client 。

    清理反向索引 subscriptions 。

    如果某个 Topic 无人订阅,立即 drop 掉对应的 channel 发送端,停止上游数据生产。

    总结 作为独立开发者,资源有限。这套“Rust 单机 + 无外挂组件”的架构,让我用最低的成本(一台服务器)抗住了业务压力,而且睡得很安稳。

    Simplicity is the ultimate sophistication.

    V 友专属福利 软件名字叫 《交易学徒》,是一个辅助交易员复盘、模拟、练盘感的工具。前端也是我用 Flutter 写的( Rust + Flutter 真是全栈开发的绝配)。

    官网下载: https://www.zgjiazu.top

    Google Play: https://play.google.com/store/apps/details?id=com.zengkai.jyxtclient

    回帖福利: 在本帖回复并附上 App 内的 ID (在‘我的页面’可以看到),我后台人肉送一个月 VIP 会员。

    同时也欢迎大家在评论区提 Bug ,或者交流关于 Rust 后端与 Flutter 前端开发的坑!

    34 条回复    2026-01-24 09:03:08 +08:00
    ljkgpxs
        1
    ljkgpxs  
       1 天前
    消息会持久化存储吗,程序挂了消息咋处理
    twocold0451
        2
    twocold0451  
       1 天前
    学习一下
    kai92zeng
        3
    kai92zeng  
    OP
       1 天前
    @ljkgpxs 私聊会存储,大厅聊天不会存储,只会在内存里保留最新的 N 条,新用户进入聊天服务器可以选择发不发最近的聊天数据,再远的数据没有意义。行情报价也是,行情价格时存储在数据库的,可以同步缺失的数据,服务挂了也不会影响行情报价数据的缺失,启动起来数据会完整的。
    Gilfoyle26
        4
    Gilfoyle26  
       1 天前
    你这样做从性能来说确实可以,但是使用 Redis 和 Kafka 其实更多是为了高可用,更多不是为了性能
    scholes1989
        5
    scholes1989  
       1 天前
    这个项目没有苹果的吗
    shine1996
        6
    shine1996  
       1 天前
    极致的优化
    Yangpengxu
        7
    Yangpengxu  
       1 天前
    新颖的想法
    scholes1989
        8
    scholes1989  
       1 天前
    大佬问下这个数据源是 从哪里接哈
    grayish
        9
    grayish  
       1 天前
    10+下载量就开始幻想 10W 在线了么
    lusi1990
        10
    lusi1990  
       1 天前 via iPhone
    是个 C100k 的问题。
    kai92zeng
        11
    kai92zeng  
    OP
       1 天前
    @Gilfoyle26 哥们说得很对,在通用的互联网架构中,Redis 和 Kafka 确实是高可用的基石,不过在高频行情推送这个业务场景下,架构的权衡逻辑有点不一样。我需要的时极致的性能和稳定,越简单的架构,故障率和延迟就会越低。行情的特点是“过期即废”,用户不需要堆积的数据,我个人认为,我这个单机会比 redis 和 kafka 更加高可用,对于我的项目来说。
    kai92zeng
        12
    kai92zeng  
    OP
       1 天前
    kai92zeng
        14
    kai92zeng  
    OP
       1 天前
    @Yangpengxu 独立开发,各方面都要省着花,挖空心思把性能提高一点。
    kai92zeng
        15
    kai92zeng  
    OP
       1 天前
    @scholes1989 花点小钱,网上太多公司卖数据了。
    kai92zeng
        16
    kai92zeng  
    OP
       1 天前
    @grayish 目标是十万在线,我会持续努力的,请大佬见证
    kai92zeng
        17
    kai92zeng  
    OP
       1 天前
    @lusi1990 开发过程就奔着十万在线目标去的,现在也达到了这个目标(模拟十万连接),整个项目,开发反而是最简单的,难一点的是 UI 设计和整体风格界定,更难得是怎么获取用户和留住用户,任重而道远……
    Charlie17Li
        18
    Charlie17Li  
       1 天前
    想问下行情数据从哪里弄的呢? akshare ?
    KyleRicardo
        19
    KyleRicardo  
       1 天前
    这思路不错啊就,值得学习。
    另外请教下大佬,官网是 AI 写的吗?或者用的什么模板?
    gongxuanzhang
        20
    gongxuanzhang  
       1 天前   1
    思路非常对,支持,我觉得程序员就是应该去考虑如何榨干一台机器,而不是"加机器的问题都不是问题"
    drymonfidelia
        21
    drymonfidelia  
       1 天前
    不写 rust ,不过 C#的 MemoryCache 和 R3 用起来也超爽
    Sawyerhou
        22
    Sawyerhou  
       1 天前
    A 股的话各大主流 app 和券商 app 都带模拟盘功能,但没怎么炒过币,不清楚币圈对此的需求情况。
    visper
        23
    visper  
       1 天前
    大佬 rust 高级优化,极限压榨性能。
    kai92zeng
        24
    kai92zeng  
    OP
       1 天前
    @Charlie17Li 网上找的公司接的,实时毫秒级详情,如果不是照顾服务器,我可以做到每秒推 5 次以上的报价,如果这个品种一秒报价能够跳动五次的话。
    kai92zeng
        25
    kai92zeng  
    OP
       1 天前
    @KyleRicardo 官网是 AI 写的,改过几版,后期还会改,只不过现在没时间,一个人经历实在有限
    kai92zeng
        26
    kai92zeng  
    OP
       1 天前
    @gongxuanzhang 感谢支持!对于个人开发者而言,极简就意味着稳定,更多的时间应该用在打磨产品功能,软件最终会给用户带来怎样的蜕变,然后就是运营了。酒香也怕巷子深……
    kai92zeng
        27
    kai92zeng  
    OP
       1 天前
    @drymonfidelia 立的时候我也考虑过 C#,在资源占用和执行效率上还是对我的资金有压力,JAVA 第一时间就被我抛弃了,最后选择了 rust 。
    kai92zeng
        28
    kai92zeng  
    OP
       1 天前
    @Sawyerhou 我会打造差异化软件,基本的模拟交易就不谈了,我要做的是让用户从交易技巧到交易心理分析两方面进行提高,同时对整个交易群体的不同级别交易员有清晰的认识,这需要足够的用户量,软件要暴露足够多的数据信息,交易只是最基本的数据来源。
    kai92zeng
        29
    kai92zeng  
    OP
       1 天前
    @visper 还可以继续压榨,方方面面,不过,先获取用户才是最重要的。
    lasuar
        30
    lasuar  
       23 小时 48 分钟前
    如果要打造个人影响力,可以直接开源
    drank20L
        31
    drank20L  
       23 小时 36 分钟前
    只有安卓版,Mac 和 iOS 什么时候上线
    kai92zeng
        32
    kai92zeng  
    OP
       22 小时 32 分钟前
    @lasuar 等有饭吃了,我考虑将数据源开出去
    kai92zeng
        33
    kai92zeng  
    OP
       22 小时 31 分钟前
    @drank20L 今天准备斥巨资购买二手 mac mini ,估计半个月内上架。
    FH0
        34
    FH0  
       3 小时 52 分钟前
    加油加油!我刚开始接触 Rust 的时候也有这样的代码洁癖,后来变成需求能稳定满足就行,不知道是好事还是坏事。尤其是现在,定个框架,让 AI 去做,自己只负责每个模块去验收。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2656 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 04:55 PVG 12:55 LAX 20:55 JFK 23:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86