V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Drinker
V2EX  ›  Java

一个 Java 项目如果需要启用上万个 websocket,有什么好办法么

  •  
  •   Drinker · 2020-02-26 10:16:52 +08:00 · 12914 次点击
    这是一个创建于 1767 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大概是这样,对方有个 api,这个 api 对应的参数有个上万个,每个参数对应一个 websocket,现在要做的是拿到参数,每个参数启动一个 websocket 去保存发送下来的数据,保存现在使用消息队列应该没什么问题,就是如果启动了上万个 websocket 会不会内存直接爆炸?或者还是有没有其他的办法,老哥们。

    92 条回复    2020-02-27 17:50:48 +08:00
    GM
        1
    GM  
       2020-02-26 10:24:57 +08:00
    你不会做个遍历一个一个去连接吗?
    misaka19000
        2
    misaka19000  
       2020-02-26 10:24:59 +08:00
    测一下不就知道了
    sudodo
        3
    sudodo  
       2020-02-26 10:28:46 +08:00
    上万个 ws,一台服务器是不可能的啊……
    Drinker
        4
    Drinker  
    OP
       2020-02-26 10:30:00 +08:00
    @GM 连接么可以连接,关键问题是内存会不会爆掉,现在在做技术方案,上万个 websocket,且每个 websocket 同一时间很大概率会有信息传过来,所以性能这块需要考虑一下。所以问问各位老大哥有没有什么好办法。
    lbfeng
        5
    lbfeng  
       2020-02-26 10:30:32 +08:00
    不是每个 websocket 链接占一个端口么?
    misaka19000
        6
    misaka19000  
       2020-02-26 10:30:57 +08:00
    你测一下每个 ws 要多少内存,然后算一下不就知道内存够不够了
    Drinker
        7
    Drinker  
    OP
       2020-02-26 10:31:03 +08:00
    @misaka19000 上万个 websocket,且每个 websocket 同一时间很大概率会有信息传过来,感觉不用测,性能可能有点悬,所以咨询一下各位老大哥。
    misaka19000
        8
    misaka19000  
       2020-02-26 10:31:35 +08:00
    @lbfeng #5 每个 ws 占一个 fd,所有的 ws 可以共用一个端口啊
    binux
        9
    binux  
       2020-02-26 10:33:18 +08:00   ❤️ 9
    你问下对面是怎么做到同时支持上万个 websocket 的。
    GM
        10
    GM  
       2020-02-26 10:33:37 +08:00
    说实话,你们这个获取数据方式有点奇葩。
    Drinker
        11
    Drinker  
    OP
       2020-02-26 10:34:14 +08:00
    @sudodo 我也感觉不行,如果多台服务器,类似这种案例这个有没有现有的解决方案,老哥。
    Vegetable
        12
    Vegetable  
       2020-02-26 10:35:26 +08:00
    @lbfeng 你说的好像是出口,服务端就开一个吧
    Drinker
        13
    Drinker  
    OP
       2020-02-26 10:35:45 +08:00
    @lbfeng 一个端口就可以了。
    GM
        14
    GM  
       2020-02-26 10:36:12 +08:00
    先把每个参数丢到一个队列里去,然后做个 100 线程的线程池,每个线程做个死循环从队列拿参数、启动 ws 获取数据、关闭 ws,保证内存不爆。

    如果内存足够,那就启动 500、1000 个线程。
    Drinker
        15
    Drinker  
    OP
       2020-02-26 10:37:03 +08:00
    @misaka19000 嗯,内存这个可以测试看看,如果每个 websocket 同一时间数据量很大,cpu 也是一个问题,麻烦。
    ryd994
        16
    ryd994  
       2020-02-26 10:38:57 +08:00 via Android
    讲道理,这不就是 C10K 问题?
    Drinker
        17
    Drinker  
    OP
       2020-02-26 10:38:57 +08:00
    @binux 这个方法可以,可以问问对面技术是咋做到的,(*^_^*)
    janxin
        18
    janxin  
       2020-02-26 10:39:59 +08:00
    内存可以估算出来的,会不会爆炸也不知道你的内存多少啊...
    Drinker
        19
    Drinker  
    OP
       2020-02-26 10:40:18 +08:00
    @GM 对方提供获取数据方法就这些,而且数据还是实时的,就是现在如果你不连接获取到数据,时间已过就没数据啦。
    Drinker
        20
    Drinker  
    OP
       2020-02-26 10:41:41 +08:00
    @janxin 嗯,cpu 这个也是个问题,同一时刻,有个几千个 websocket 同时有数据过来,内存不炸,cpu 也不会爆满吧。
    Drinker
        21
    Drinker  
    OP
       2020-02-26 10:43:20 +08:00
    @GM 数据具有实时性,很大概率需要全部 websocket 开着,不能关闭,关闭了数据就没了。
    liuguang
        22
    liuguang  
       2020-02-26 10:48:40 +08:00
    这种事情 go 和 rust 应该可以做到。至于 java,用 nginx 反代分流,每台 Java 服务器处理一部分 ws 流量,应该也可以搞定.
    casillasyi
        23
    casillasyi  
       2020-02-26 10:51:53 +08:00
    jvm 本身就是个负担。这种场景建议用 rust
    polythene
        24
    polythene  
       2020-02-26 10:56:37 +08:00
    做 sharding 吧,单机器估计扛不住
    sagaxu
        25
    sagaxu  
       2020-02-26 10:56:51 +08:00 via Android
    参数不能作为 message 的一部分吗?
    zzcworld
        26
    zzcworld  
       2020-02-26 10:57:37 +08:00
    建议拆成 worker,每个 worker 连接几千个 websockets。如果能订阅多个 channel,减少 websockets 连接,也是一个好办法
    sagaxu
        27
    sagaxu  
       2020-02-26 11:03:01 +08:00 via Android
    @polythene 2 代树莓派开 2 万个 websocket 毫无压力,比树莓派性能还差的服务器?
    @liuguang Java 正常服务器单机 100K 个 websocket 应该问题不大
    ftfunjth
        28
    ftfunjth  
       2020-02-26 11:04:44 +08:00 via Android
    对参数 hash 然后想办法分布式多台服务器。数据落地可以想办法被动写回或者主动扔到 redis 然后再定时持久化。
    wizardoz
        29
    wizardoz  
       2020-02-26 11:04:50 +08:00
    内存会不会爆炸取决于你的内存有多少,而且直觉上这个内存消耗不大。
    我觉得最应该考虑的问题是多线程方式处理每个连接还是通过异步 IO 的方式处理。如果异步 IO,我相信对服务器的要求不高。
    如果是多线程,那么服务器就难了。
    XRR
        30
    XRR  
       2020-02-26 11:05:53 +08:00
    @sagaxu 100000 个 websocket 都超过服务器的端口数了,肯定不行,服务器一共就六万多个逻辑端口
    gemini767
        31
    gemini767  
       2020-02-26 11:09:39 +08:00
    团队没有专业人员建议 http 轮训,简单有效,最重要的可控
    liqingcan
        32
    liqingcan  
       2020-02-26 11:11:51 +08:00
    什么需求需要这么多 websocket im 类的需求?这玩意也不会用一台机器吧。挺好奇的
    lscho
        33
    lscho  
       2020-02-26 11:13:47 +08:00
    @XRR 想啥呢。。。websocket 和端口有什么关系,又不是 TCP。

    实践出真知,几万个 websocket 连接数肯定是没啥问题的,几十万也没问题,需要考虑的就是数据量问题,数据量过大同时进来肯定不行。
    gemini767
        34
    gemini767  
       2020-02-26 11:14:24 +08:00
    @sagaxu 开 2w 个 socket 和支持 2w 个长链接业务还是有很大差别的吧
    realpg
        35
    realpg  
       2020-02-26 11:16:31 +08:00
    你们老板需要一个架构师。。。
    pubby
        36
    pubby  
       2020-02-26 11:17:39 +08:00 via Android
    会不会理解有偏差,上万个参数其实可以一起传的?
    ftfunjth
        37
    ftfunjth  
       2020-02-26 11:19:33 +08:00 via Android
    @lscho 我记得 spring websocket 默认是一个连接一个 socket 用的是异步套接字。如果是 epoll,两万个 websocket,cpu 包处理速度够的话应该没问题。怕 socket 的 receive buffer 过大。导致内核内存缓冲区不够用。如果内核内存满了的话一直在用虚拟内存怕是电脑会卡死?
    realpg
        38
    realpg  
       2020-02-26 11:20:15 +08:00
    我这里有个类似的东西。
    也是客户端 开 4400 个 TCP 连接到远程,然后保存下推流,解码,入库。
    用了 12 台垃圾 1U 服务器,服务器总成本一万五千元……
    realpg
        39
    realpg  
       2020-02-26 11:21:49 +08:00
    @pubby #36
    你没理解他的业务模型。
    lasuar
        40
    lasuar  
       2020-02-26 11:28:46 +08:00
    你这个场景有点像是对 ws 服务端做鲁棒性测试
    lasuar
        41
    lasuar  
       2020-02-26 11:29:51 +08:00
    哪有正常的逻辑是一方使用上 W 个端口去连接 ws 的,我建议楼主把逻辑理清楚说清楚,无厘头。。。
    Xusually
        42
    Xusually  
       2020-02-26 11:33:05 +08:00
    需要长链接吗?
    怎么感觉你这场景是股票行情信息同步推送?
    Drinker
        43
    Drinker  
    OP
       2020-02-26 11:35:26 +08:00
    @ryd994 哈哈,我去搜了一下,这个的确和 C10K 的场景差不多。
    Drinker
        44
    Drinker  
    OP
       2020-02-26 11:38:52 +08:00
    @sagaxu 相当于 ws 连接前缀相同,加了参数就是一个 ws 连接,现在参数的变化有一万多种,所以就有一万多连接。
    Drinker
        45
    Drinker  
    OP
       2020-02-26 11:39:41 +08:00
    @ftfunjth 嗯,我们这边考虑一下。谢谢。
    Drinker
        46
    Drinker  
    OP
       2020-02-26 11:47:50 +08:00
    @wizardoz 主要就是通过 WebSocketClient 来连接,不过没找到 onMessage 是异步 IO 还是多线程,搜了一下,好像都没提到。现在暂时的想法是 onMessage 有信息的时候立马推到 jms 里面,另外一台服务从队列里面一个个取出数据保存起来。
    Drinker
        47
    Drinker  
    OP
       2020-02-26 11:48:22 +08:00
    @gemini767 嗯,这边考虑一下,谢谢。
    Drinker
        48
    Drinker  
    OP
       2020-02-26 11:50:02 +08:00
    @liqingcan 有点类型直播的这种,比如虎牙直播,每个直播间的信息其实是一个 ws 连接,现在我知道一万个房间号,我就可以连接一万个房间的直播信息,然后把直播信息保存下来。类似这种。
    Drinker
        49
    Drinker  
    OP
       2020-02-26 11:50:54 +08:00
    @realpg 哈哈,都在考虑方案当中。
    fancy111
        50
    fancy111  
       2020-02-26 11:51:19 +08:00
    上万个 WS 是肯定没问题的,问题是带宽会爆
    Drinker
        51
    Drinker  
    OP
       2020-02-26 11:51:34 +08:00
    @pubby 有点类型直播的这种,比如虎牙直播,每个直播间的信息其实是一个 ws 连接,现在我知道一万个房间号,我就可以连接一万个房间的直播信息,然后把直播信息保存下来。类似这种。
    Drinker
        52
    Drinker  
    OP
       2020-02-26 11:52:32 +08:00
    @lasuar 有点类型直播的这种,比如虎牙直播,每个直播间的信息其实是一个 ws 连接,现在我知道一万个房间号,我就可以连接一万个房间的直播信息,然后把直播信息保存下来。类似这种。
    Drinker
        53
    Drinker  
    OP
       2020-02-26 11:53:55 +08:00
    @Xusually 对呢。很类似。不能断,断了数据就没了。启动就需要很多连接。对方提供的只是 ws。
    lasuar
        54
    lasuar  
       2020-02-26 12:01:23 +08:00
    @Drinker 直播的 N 个 ws 连接是存在于服务端,只会占用服务端一个 ws 服务端口,程序存储的 N 个 conn 对象都是占用的同一个的端口,你这个场景就类似于拿一台机器模拟上 W 个 ws 客户端,所以才需要上 W 个端口,不要搞混了。
    tinybaby365
        56
    tinybaby365  
       2020-02-26 12:16:05 +08:00   ❤️ 2
    之前用 golang 实现过,单机用了 24GB 的内存,大概 160w 个连接。诀窍是省内存,降低你服务的每个连接的内存消耗,我没用 net/http,虽然我用的 websocket 库是依赖 net/http,但 go 的鸭子类型可以让我用一个简陋消耗更小的 conn 替代。
    另一个就是降低系统 socket 的读写 buffer。root 权限加 rlimit 设置,突破单进程的限制。
    maichael
        57
    maichael  
       2020-02-26 12:22:39 +08:00   ❤️ 1
    我记得之前看过测试,一台还可以的机器撑 100 万左右的 Websocket 没问题。
    aguesuka
        58
    aguesuka  
       2020-02-26 12:34:59 +08:00 via Android
    理论上 nio10k 个 tcp 连接没有问题,用 netty 试试呗。我估计系统瓶颈 io,cpu,然后才是内存
    no1xsyzy
        59
    no1xsyzy  
       2020-02-26 12:37:35 +08:00
    @Drinker 附加信息不要一个个回复,可以 append,可以 @ 多个人。不然你容易被降权导致别人根本收不到你的消息。
    no1xsyzy
        60
    no1xsyzy  
       2020-02-26 12:39:35 +08:00
    @lasuar #41 可是楼主也没提到端口啊,是上面有人(#5、#30 )觉得一个链接一个端口,而且已经被人反驳了。
    zjsxwc
        61
    zjsxwc  
       2020-02-26 12:40:51 +08:00
    1 万连接,java 没有问题的
    realpg
        62
    realpg  
       2020-02-26 12:57:04 +08:00
    @lasuar #41
    你没见过不代表不存在且不合理
    我这就有跟楼主一样的 只是 TCP

    一个服务用几千个 TCP 频道实时广播信息
    一般一个客户只需要订阅一个频道

    但是因为性能问题,自建的地区中继,就得所有频道信息 relay
    就是一组服务器几千个客户端
    zfish
        63
    zfish  
       2020-02-26 12:58:39 +08:00
    使用 elixir/erlang 开发吧,上万并发不要太轻松
    lasuar
        64
    lasuar  
       2020-02-26 13:01:55 +08:00
    对于 ws 服务端来说,一台普通服务器倒不是说承受上 w 个 client 连接无压力,这个还要看消息 size 和传输频率,几十万人直播间那种一台机器的网卡都受不住了。
    sampeng
        65
    sampeng  
       2020-02-26 13:06:11 +08:00 via iPhone
    先搞清楚 ws 和 tcp 的关系…另外有一句说一句。你确定对方能支持上万的 qps ?
    gamexg
        66
    gamexg  
       2020-02-26 13:16:16 +08:00
    上万个没难度啊
    网关类单服务器连入几十万连接,连接空闲时 120m 一个 ping,外加数据传输网卡跑到 500M+,毫无问题。
    gamexg
        67
    gamexg  
       2020-02-26 13:17:18 +08:00
    @gamexg #66 120m->120s
    lasuar
        68
    lasuar  
       2020-02-26 13:27:34 +08:00
    @realpg 好吧,只能说确实太少见了,这得是多大的项目规模了
    x66
        69
    x66  
       2020-02-26 13:37:10 +08:00
    这是要爬直播平台的弹幕和礼物吧
    paoqi2048
        70
    paoqi2048  
       2020-02-26 13:42:30 +08:00
    Drinker
        71
    Drinker  
    OP
       2020-02-26 13:54:55 +08:00
    @tinybaby365 好呢,我们这边考虑一下,谢谢。
    @maichael 好的,找个时间测试一波看看。
    @no1xsyzy 多谢提醒,我这边已经被禁止回复好几次啦,哈哈
    @zfish 多谢建议,我们去了解一下。
    @lasuar 嗯,我们先测试一下看看,谢谢。
    @sampeng 对方可以搞,实时的几万个频道的广播,现在就是不知道对方怎么弄的,/(ㄒoㄒ)/~~
    @gamexg 好呢,我们测试一下,谢谢
    @x66 不是,类似这种消息中转和消息概要记录。
    @paoqi2048 谢谢,我们了解一下。
    tairan2006
        72
    tairan2006  
       2020-02-26 13:59:14 +08:00 via Android
    上万个没啥难度啊…你可以用 mqtt broker,开源的都能单机上万了
    pinews
        73
    pinews  
       2020-02-26 14:23:37 +08:00
    小白请教一下
    这个 api 对应的参数有个上万个,每个参数对应一个 websocket !每个参数对应的难道不应该是一个频道吗?
    zfish
        74
    zfish  
       2020-02-26 14:38:00 +08:00   ❤️ 1
    @Drinker elixir 单机 4GB 开百万进程( Erlang 的虚拟进程,实际上底层是 Erlang 实现了自己的 CPU 调度算法,并不依赖操作系统的调度,所以可以做到极其低成本的开销去切换进程),每个进程都是独立的内存分配,百万用户的长链接都可以用百万的进程去独立负责通信,所以 Erlang 在游戏领域后台 /电信领域使用的很多,不过 Erlang 的语法有点奇怪,可以用基于 Erlang 的 Elixir 去开发
    zfish
        75
    zfish  
       2020-02-26 14:50:10 +08:00
    @zfish ![]( https://img.bmpi.dev/c5a8569f-42b1-63de-15a5-25d77f29a050.png) Elixir 的 Web 框架 Phoenix 单机两百万 WS 长链接,毫无压力
    noisywolf
        76
    noisywolf  
       2020-02-26 15:27:06 +08:00
    1、用 nginx+lua,就是 OpenResty,每个连接挂个 redis 的 pubsub
    2、用 go,轻松解决
    SjwNo1
        77
    SjwNo1  
       2020-02-26 15:36:01 +08:00
    gogogo
    lfcyme
        78
    lfcyme  
       2020-02-26 15:52:25 +08:00
    建议换 elixir + phoenix channel, 特别香 ( 逃 ~
    lfcyme
        79
    lfcyme  
       2020-02-26 15:52:49 +08:00
    @zfish #75 elixir 握爪
    zjq123
        80
    zjq123  
       2020-02-26 16:07:52 +08:00 via Android
    @zfish 我觉得主要是 socket 肯定涉及到内核 只不过 erl 在伪进程调度方面实现了自己一套 不涉及到操作系统进城管理了 而只涉及到内核 socket 部分
    onion83
        81
    onion83  
       2020-02-26 16:19:55 +08:00
    我觉得沟通是不是有点问题?把 webscoket 当 http 来玩了?一般的使用方法都是建立一次连接,然后不断收发数据就好了,同步响应还是异步响应,这个要看业务,连接是可以复用的。
    wufakeyou
        82
    wufakeyou  
       2020-02-26 16:36:51 +08:00   ❤️ 1
    生产环境,C#+阿里云 4 核 8G,8000 个 socket 在线,资源占用 30%左右。对物联网项目来说,1W 个 socket 规模其实很小了。
    Drinker
        83
    Drinker  
    OP
       2020-02-26 17:15:47 +08:00
    @tairan2006 好呢,有方向就好,我们先去看看。
    @pinews 如果说频道的话不太准确,大概就是如果 type=1 那么对面服务会把对应的 1 的数据传过来,如果是 2 那么对应的数据就是 2,但是不能说传 type=1,2 这种,他们会认为 type 是非法的。
    @zfish 好的,谢谢提供思路,我们去看看。
    @no1xsyzy 谢谢提供思路。
    @SjwNo1 哈哈,好呢,我们去看看相关的资料。
    @lfcyme 好的,谢谢提供思路。
    @onion83 大概就是如果 type=1 那么对面服务会把对应的 1 的数据传过来,如果是 2 那么对应的数据就是 2,但是不能说传 type=1,2 这种,他们会认为 type 是非法的。所以每一个 type 的值,都对应一个 ws 连接。每个 ws 连接自行接收数据。
    @wufakeyou 好的,谢谢提供案例,我们这边做下技术调研。
    cz5424
        84
    cz5424  
       2020-02-26 17:16:13 +08:00
    golang,1w 小意思
    cz5424
        85
    cz5424  
       2020-02-26 17:17:41 +08:00
    @wufakeyou 同物联网,1w+, 低于 30%,golang,tcp
    monkeyWie
        86
    monkeyWie  
       2020-02-26 17:43:12 +08:00
    java 上 netty 轻松搞定好吧
    pythonee
        87
    pythonee  
       2020-02-26 20:25:31 +08:00
    云服务 api gateway ?
    wellsc
        88
    wellsc  
       2020-02-26 20:33:44 +08:00
    扔给 nginx 处理
    laozhang
        89
    laozhang  
       2020-02-27 03:17:01 +08:00 via iPhone
    32g 的机器 100 万 ws 连接应该没问题。对 我说的单机。go 写的。
    barbery
        90
    barbery  
       2020-02-27 09:43:22 +08:00
    换 go
    sicauxeon
        91
    sicauxeon  
       2020-02-27 13:51:02 +08:00
    经典的 C10K 问题。但是看你具体的使用场景,如果不行的话,就负载均衡做吧。
    lixm
        92
    lixm  
       2020-02-27 17:50:48 +08:00
    楼主这个是客户端啊, 单机不够就堆机器呗, 还不至于 C10K
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1450 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 17:18 · PVG 01:18 · LAX 09:18 · JFK 12:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.