Java web server http 请求的一个疑惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lbmjsls1
V2EX    Java

Java web server http 请求的一个疑惑

  •  
  •   lbmjsls1 2020-06-19 18:02:38 +08:00 3618 次点击
    这是一个创建于 2020 天前的主题,其中的信息可能已经有所发展或是发生改变。

    事情是这样,我们现在的 web server 遇到了问题,准备用 java 重写一个,现在有一个疑惑想问大家遇到这种情况如何处理

    用户打开连接,进来一个 http 请求,按照我们技术说的,这个 http 请求必须在这个连接内返回。但是有可能这次请求加载的数据很慢,比如要读写数据库,那么问题来了:

    1.一个 htp 请求必须要在这个连接内返回完成吗?不管需要多长时间?是否可以过后再同步数据

    2.如果必须要在一个连接内完成,那么一个 http 请求就对应一个线程?(不管是用线程池还是其他方案实现)

    3.如果一个 http 请求对应一个线程,是不是在 web server 领域没有所谓的数据库线程?每次操作都在当前的线程内完成

    原谅问这么入门级的问题,因为原来不是搞 web server 的,现在突然紧急,硬头皮上

    19 条回复    2020-06-21 10:53:05 +08:00
    lululau
        1
    lululau  
       2020-06-19 18:17:12 +08:00
    1. 可以不在一个连接里完成,这种叫异步接口
    2. web server 的服务端的并发模型可以是多进程、多线程、reative io 、协程、或者两种模型的混合,Java 主流是 Servlet,是多线程的模型,在不讨论线程池这样的细节的情况下,一般一个请求对应一个线程,当然你可以在这个线程里创建出另外一个线程,这也是实现异步接口的一种方式
    3. 一般数据库操作和其他逻辑是在同一个线程里的
    lbmjsls1
        2
    lbmjsls1  
    OP
       2020-06-19 18:29:13 +08:00 via Android
    @lululau 如果在请求的线程内创建新的线程异步操作,当前的请求线程是不是不能退出,要等待异步结果返回才能返回给页面吗
    kevinjaz
        3
    kevinjaz  
       2020-06-19 18:39:36 +08:00
    后台的业务处理用异步处理就行了,用线程池去执行任务也行,响应能立刻返回,那么给前端的提示可能就是正在处理,请稍后查询。
    lululau
        4
    lululau  
       2020-06-19 18:40:06 +08:00 via iPhone
    @lbmjsls1 可以退出
    lbmjsls1
        5
    lbmjsls1  
    OP
       2020-06-19 18:50:04 +08:00
    @kevinjaz
    @lululau

    如果可以退出,那么这次连接就断掉了,怎么知道像谁推送消息呢,还是说每个请求是个长连接,可以先告诉它等待处理,处理完再通知处理后的结果?
    mmdsun
        6
    mmdsun  
       2020-06-19 18:59:30 +08:00 via Android
    @lbmjsls1 消息通知可以另外用 websocket 通知。或者第三方的推送平台 Sdk 等。不用靠之前那个耗时的 http 请求来通知的。
    lululau
        7
    lululau  
       2020-06-19 19:03:10 +08:00 via iPhone
    对,连接断了,后面客户端主动再次发起新的请求来查询处理结果;你说的这种推送方式也可以,可以用 websocket 来保持独立的长连接,你的逻辑处理完了需要查找到使用的 websocket 连接来推送数据,另外一种推送是 comet,基于 http 的长连接,这个本质上其实是同步的,所以连接不能关,但是客户端可以实现异步的流程效果
    wysnylc
        8
    wysnylc  
       2020-06-19 19:05:40 +08:00
    同步异步 bionio 是看业务设计,性能优化可以使用线程池 Completablefuture 等等
    lovelife1994
        9
    lovelife1994  
       2020-06-19 21:07:20 +08:00
    tomcat nio 或者 arp 都是这样的协议,如果你的服务需要处理大量连接,但是每个连接的的负载很小,通过 IO 多路复用的方式,acceptor 线程绑定端口获取新的连接,然后将连接注册到一个或几个 selector 上,selector 通过 poll 或者 epoll 的方式管理多个连接,当 IO 事件到达时,将从连接中拿到实际的请求分配给实际的工作线程处理。这样连接和线程不是绑定。一个 http 请求肯定需要通过一个工作线程去处理,问题在于是在请求到达时分配工作线程还是连接建立时分配。BIO 的方式在连接到达时分配,每个线程管理一个连接,连接不关闭且负载不高时,这部分资源就是浪费的。NIO 是用少量的线程管理大量的连接。负载取决与实际的 http 请求而非连接数。
    kevinjaz
        10
    kevinjaz  
       2020-06-19 21:18:58 +08:00
    @lbmjsls1 正常的 http 请求是无状态的,每个请求进来带了 token 之类的消息知道客户端是谁?请求处理完,返回之后这个连接就断了。除非你是用 websocket 建立长连接,那样客户端与服务端是全双工通信的,看你的描述,是因为处理的业务逻辑时间过长,要不就长时间等待,那样用户体验不好。另一种方案是异步处理,后端找个表记录任务详情,那么有个地方可以查询这个任务结果,如果是类似导入数据的需求,可以给个提示说稍后刷新页面查询。
    lovelife1994
        11
    lovelife1994  
       2020-06-19 21:20:44 +08:00
    @kevinjaz http 现在很多为了避免开销都会用到 keepAlive,会维持连接存活一段时间,这段时间就比较尴尬。
    nicevar
        12
    nicevar  
       2020-06-19 21:22:57 +08:00
    这不是什么代码实现问题,是业务逻辑和产品设计的问题。
    kevinjaz
        13
    kevinjaz  
       2020-06-19 21:32:14 +08:00
    @lovelife1994 看服务承载量,如果用户请求量大,用 keepAlive 反而会增加服务端的压力,毕竟维持一个 tcp 就占了一个坑位,看题主的问题应该是业务处理的时间都超出了 keepAlive 的超时时间了,所以这里应该是如何设计好这个交互问题。
    Aruforce
        14
    Aruforce  
       2020-06-19 22:29:00 +08:00 via Android
    你说这个 web server 不会是 web 容器吧?
    lululau
        15
    lululau  
       2020-06-19 22:41:58 +08:00 via iPhone
    @Aruforce 和 web server 相对的说法应该是 application server, 不过很久没看到这么老土的说法了,抠字眼没意思,何况这个字眼抠的根本就是错误的,tomcat 为什么就不能叫 web server, 不支持 http 还是不能 serve 静态资源
    yyb2yang
        16
    yyb2yang  
       2020-06-19 22:43:05 +08:00 via iPhone
    按照楼主的业务需求,异步通信是一个解决办法:A 、B 两个服务(或者父子线程)的通信,B 的业务处理时长很长的时候,A 通过异步调用 B 以后,让 B 自己去处理复杂的业务,而 A 可以立即反馈给客户端一个结果,而不是阻塞等待 A 的执行结果的反馈。至于后期 B 执行成功或者失败,可以再发起一次查询请求,或者 B 执行完以后,由 B 的业务逻辑发起一个客户端的通知反馈都是可以的。
    mreasonyang
        17
    mreasonyang  
       2020-06-19 23:55:27 +08:00 via iPhone
    这和你的业务逻辑有关啊,如果客户端或前端逻辑就是同步等待响应结果,那必然是等服务端响应了才行,如果能接受异步逻辑,那就建长连或者长轮询搞成异步就可以了,当然靠用户手动刷新获取结果也是个方案。要是怕服务端出现线程和连接耗尽的问题,可以使用 nio 实现的 web 容器替代 bio 的,比如 jetty 之类的,然后调大 backlog,增加业务线程池上限就可以了。
    johnj
        18
    johnj  
       2020-06-20 06:37:10 +08:00
    说个楼上没提到的解决方案:server sent event 。可以做到一次请求长链接多次响应。浏览器端和 spring mvc 服务器端都有标准实现,细节我就不说了。
    realpg
        19
    realpg  
    PRO
       2020-06-21 10:53:05 +08:00
    问题基本是你们的业务研发太菜……
    对于慢返回的连异步请求都不会
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     924 人在线   最高记录 6679     &nbs; Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:23 PVG 06:23 LAX 14:23 JFK 17:23
    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