一个 Java 项目如果需要启用上万个 websocket,有什么好办法么 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Drinker
V2EX    Java

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

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

    大概是这样,对方有个 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
      &nsp;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  
    PRO
       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  
    PRO
       2020-02-26 11:20:15 +08:00
    我这里有个类似的东西。
    也是客户端 开 4400 个 TCP 连接到远程,然后保存下推流,解码,入库。
    用了 12 台垃圾 1U 服务器,服务器总成本一万五千元……
    realpg
        39
    realpg  
    PRO
       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  
    PRO
       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 来玩了?一般的使用方法都是建立一次连接,然后不断收发数据就好了,同步响应还是异步响应,这个要看业务,连接是可以复用的。
    /td>
    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     Solana     2940 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 83ms UTC 13:38 PVG 21:38 LAX 05:38 JFK 08:38
    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