1
araaaa 2019-11-17 11:29:57 +08:00 via iPhone
少量线程处理大量连接
|
3
lu5je0 2019-11-17 11:32:26 +08:00 via Android
netty 是同步 IO
|
5
Infernalzero 2019-11-17 11:38:13 +08:00
并不是异步 IO,同步非阻塞
|
7
iXingo OP @Infernalzero 谢谢指正
|
9
sandrew1945 2019-11-17 12:06:34 +08:00 via iPhone
0 拷贝
|
10
javapythongo 2019-11-17 12:09:18 +08:00 via iPhone
没有提高计算能力,只是能接收更多的请求来处理,如果事 cpu 计算为主,效率就很高
|
11
hhx 2019-11-17 12:11:24 +08:00 via Android 1
Netty 应该是非阻塞 IO,和异步 IO 不是一回事。首先你要搞清楚所谓用户态 IO 到底是在干什么,其实很简单,就是在内核缓冲区与用户进程空间之间传送数据。举个例子,调用 BufferedReader 的 readLine 方法,该方法试图读取一行,但问题是该行数据很可能没有准备好,那怎么办呢?阻塞式 IO 的做法是阻塞当前进程,进程进入阻塞态,由 OS 负责在数据准备好时唤醒该进程,然后继续执行 IO。而非阻塞 IO 的做法是跳过执行该 IO 操作,执行后续代码,典型的做法是,不断轮训以检查数据是否准备好。有人会说了,那阻塞式 IO 岂不是更好,因为阻塞时没有占用 CPU,而非阻塞花费了 CPU 时间去轮训。我的观点是,阻塞尽管没有占用 CPU,但是整个程序依然是止步不前的,当处理较多用户连接时,很明显非阻塞方式的交互式更好,响应时间更低,吞吐量也更大。另一方面,阻塞式 IO 占用更多的线程,而非阻塞 IO 可以利用 OS 的 epoll 等系统调用,实现单一线程处理多个连接,明显更适合服务器。至于异步 IO,效率可能更高,但实却非常复杂。
|
12
RicardoY 2019-11-17 12:11:39 +08:00 via Android
IO 不占用 cpu 的计算时间
|
13
RicardoY 2019-11-17 12:19:53 +08:00 via Android
@hhx 异步 io 也不是很麻烦吧 写的只需要把数据先给出去 等到可以写的时候内核写 读则是给出缓冲区 能读了内核帮你拷贝过来
|
14
liuminghao233 2019-11-17 12:42:31 +08:00
高不高效跟你 Netty 没关系
你用 epoll || kqueue 写出来的东西都是差不多的 相比于一个线程阻塞 n 个连接或者一个线程一个连接来说,io 复用肯定快啊 |
15
zmxnv123 2019-11-17 12:45:35 +08:00
本地 io 是 dma 方式的,不占用 cpu 时间,而网络 io 可以认为是网卡操作的,也不占用 cpu 时间。
|
16
liumyao 2019-11-17 12:50:44 +08:00 via Android
你没搞清楚同步 异步 阻塞 非阻塞
|
17
iXingo OP @hhx 好的,谢谢。还有 Netty 的 IO 线程主要做的什么操作,是不是不能在 IO 线程中做一些阻塞的操作,而是要把这些操作放在额外的业务线程池中。您能详细讲一下这方面的操作吗
|
19
iXingo OP @liuminghao233 那您的意思是说其实 Netty 底层也只是调用和封装了操作系统的 select/poll/epoll
|
20
opengps 2019-11-17 12:59:17 +08:00 via Android
一楼回答跟链接直接,处理大量链接,java 里 netty,c#里 iocp,能实现返利十万以上链接,然而线程只有几个,十几个这样的比例
|
21
lhx2008 2019-11-17 13:03:25 +08:00 via Android
其实说实在的,netty 快的原因不是接入网络这边( tomcat 也是同步非阻塞接入)
而是网络 IO 完之后的全异步的调度,就是通过流水线,异步回调这种方法,这样可以缩短线程的阻塞时间,从而减少线程的数量和切换。特别是后端再作为客户端调用别的 API 的时候。如果你用 tomcat 做一个 HTTP 请求出去,就基本只能阻塞线程慢慢等了。 |
22
lhx2008 2019-11-17 13:07:59 +08:00 via Android
也就是说,服务器作为客户端的时候,tomcat 是同步阻塞,而 netty 是同步非阻塞,我认为差距在这里。至于接入客户请求都是同步非阻塞。
|
23
lhx2008 2019-11-17 13:10:42 +08:00 via Android
当然我说的是 servlet 的旧标准,新标准也是可以异步返回的,那么和 netty 的差距就是在代码块的粒度上了,netty 更小,可以接入更多的连接。
|
24
lhx2008 2019-11-17 13:11:50 +08:00 via Android
至于跑分其实没有差距那么大。因为处理还是要用 cpu 时间的,netty 那种虽然接入了,但是几分钟才返回,百万 QPS 不挂,也没有意义的。
|
27
zmxnv123 2019-11-17 14:36:00 +08:00
主要是网络 io,netty 也可以用来优化本地 io
|
28
joooooker21 2019-11-17 15:57:26 +08:00
可以先了解 NIO 的线程模型与 IO 线程模型的差异
|
29
iXingo OP 谢谢各位老铁
|
31
mifly 2019-11-17 18:03:00 +08:00 via Android
netty 是网络 io 框架,vertx 是开发框架,网络层用的还是 netty,不是同一个功能的东西,没有可比性
|
33
dosmlp 2019-11-17 20:09:55 +08:00
就是你不用等 io 操作,操作系统帮你做了,至于操作系统怎么做的,可能是硬中断吧
|
34
micean 2019-11-17 22:09:18 +08:00
#11 +1
不是异步 IO,而是 NIO,所以不是不会阻塞,而是不能阻塞! 让每个线程不用浪费时间等待 IO 而去执行别的任务,所以 NIO 可以减少线程数量,减少上下文切换造成的性能损失 |
35
luozic 2019-11-17 22:21:18 +08:00
curd 应用,性能问题大部分在重量级的切换和轮询。
|
36
beidounanxizi 2019-11-17 22:23:13 +08:00
去学学更底层的书把 。netty 只是 恨 JAVA NIO 不成钢,另起灶台重新搭的。底层还是 linux io 哪套 不过 给你装备了好多工具, 方便你处理 IO
|
37
xuanbg 2019-11-17 22:55:28 +08:00
提升的原理就是快的连接不用等慢的连接处理完。就像地铁的安检,不带包的可以走快速通道不用在带包的队伍里面慢慢排队。
|
38
iXingo OP @beidounanxizi 好的
|
41
outoftimeerror 2019-11-18 01:06:32 +08:00
业务操作阻塞了,netty 用了也没什么意义,比如你每个请求过来再用 jdbc 操作数据库,那效率依然不高。
除非你全部非阻塞,就像 vert.x 用了异步的方式 vertx-jdbc-client 操作数据库。 全部异步的难点在于,很多业务其实是需要同步的,而且代码写起来反人类,当然函数式编程倒是提供了优雅的解决方案:future monad。 纯异步反人类,java 的线程太重,所以我觉得更实用的解决方案是 goroutine+channel。 |
42
by73 2019-11-18 01:17:54 +08:00
我所知道的(碍于知识水平可能有误),阻塞与非阻塞是针对 I/O 传输到内存这部分而言,阻塞 I/O 在传输时全程需要 CPU 干预;非阻塞 I/O 在传输时 CPU 可以干别的事,直到像 DMA 这样的控制器给 CPU 发个完成的中断,再调用到操作系统的中断处理程序。
而同步和异步则是针对进程 /线程而言的,假如调用 Files.readAllLines(),那么当前线程就会处于挂起状态,直到上面的阻塞 /非阻塞 I/O 把数据传递到内存之后才被恢复,这个过程其实对 CPU 没有影响,只是对你的线程有影响;异步就是当前线程不再等待 I/O 传输的完成,只是发起一个 I/O 请求和请求完之后要做的事情,然后交给另一个线程去负责(这样阻塞也就只会阻塞另外那个线程,不会影响当前线程的执行)。异步本质上可以理解为多线程。 所以综上,回答题主的问题,非阻塞 I/O 提升的时间主要是数据传输到内存的这段 CPU 时间,这样 CPU 就能处理其他的进程;另外,异步 I/O 的价值在于“小而多”的请求,典型例子就是 HTTP,因为 I/O 特别多,如果每个线程都要去等待这些 I/O 完成,肯定会浪费其他非 I/O 的时间,将这些 I/O 交给另一个线程,自己就“解放了”;而对于 I/O 密集的任务来说,异步 I/O 没啥大优势,当 I/O 占很大一部分时,非 I/O 部分的运行时间就可以忽略了,基本上都是在排队阻塞、传输、调回调函数,整个系统的并发度也就降到了跟同步差不多的水平(大家都是在等 I/O )。 (注意这里的所有解释都是针对 I/O 传输的过程,因为等待 I/O 到来这件事必须要等待,像 Socket.accept() 或者 listen() 都是要强行阻塞的) (熬夜过程可能脑子不太清醒,见谅,也希望能指出错误) |
43
by73 2019-11-18 01:45:21 +08:00 via Android
@by73 噢对了,Java/Netty 的 NIO 指的是 New I/O,具体而言指的是异步 I/O,而不是 Non-blocking,因为 I/O 阻塞的话语权不在它们那。
|
44
des 2019-11-18 08:36:07 +08:00 via Android 3
打个比方,好比如双十一代购
同步阻塞就是,你买了东西,等快递到了再去做其他事情,等待的时候啥也不做 非阻塞就是,你买了东西,你自己过一会去看一下到了没,过一会看一下 异步就是,买了东西,人家短信通知你,你可以做其他事情去。其中还有水平和边缘触发的区别,也很简单,一个是你有快递了通知你一下,另一个是你有快递了一直通知你 至于省出来的时间当然是,你在那里瞎等的时间或者自己去查状态的时间。 什么,你说自己查状态也不费时间?那假如你有 1w 个呢,每一个都要查一遍呢? 另外这是建立在,你的工作本身就是处理这些快递的前提下的,也就是 io 密集,类似 curd (怎么感觉像是在黑 curd 如果是 cpu 密集,那就完全不一样了。 你需要花很多时间去处理相关的东西(与 io 无关的),比方说,快递到了要组装好才能再给代购的人,这期间你是没法处理其他快递的 所以问题就很明显了,省下来时间就是在那里干等白白流逝的时间,本来你还能接更多单的。 至于说人家快递发的慢,那你也没办法是不是(指 io 本身慢以及 io 处理对方慢),但是你还是能服务到更多人是不是? 同步阻塞的另一种方案是,开多个线程去等,就好比限购,你只能找多个人一起买,然后每个人还是慢慢等 这个好像在客户端程序开发多见一点,毕竟异步写起来还是比较复杂的 |
45
des 2019-11-18 08:40:32 +08:00 via Android
|
47
w0000 2019-11-18 10:28:17 +08:00
对于这种优化应该从两种情况来看,第一种是少量连接,每次请求的数据多,第二种是大量连接,每次请求的数据量小。
netty 对第二种情况的优化是比较大的,用少量线程去轮训处理连接,但是对第一种情况是没有优化的,甚至会有轮训的性能损失。 |
48
qiyuey 2019-11-18 10:53:14 +08:00
配合 Kotlin Coroutines 或者 Reactive 效果更佳
|
49
iXingo OP @by73 感谢您的回答, 还有其实异步回调函数就是把原本主线程等待 I/O 连接 /传输过程之后的操作放在其他线程上, 其实本质上就是多线程的一种操作,是否可以这么理解
|
50
iXingo OP @w0000 请问 netty 对于大量连接和数据量也大的情况,其实是可以并发处理连接,但是数据量受限于操作系统和物理限制,也是没法做更大的优化,是否可以这么理解
|
51
iXingo OP @des 如果按照您这样说的, Netty 做的就是包装了 JDK 的 NIO 方法, 相当于一个菜鸟驿站的快递接收窗口(可能不恰当), 原先你要需要对每个快递进行等待, 现在你每次只要和这个窗口进行对接, 你每次让他帮你查询一下(底层调用一下 select()方法), 你知道有哪些快递已经到了, 你就只要对已经到达的快递进行处理. 可以这么理解吗
|
52
by73 2019-11-18 13:18:27 +08:00
@iXingo 对,本质上就是让另一个线程去处理。至少 java.nio.channels 是这样做的,如果你带了一个回调函数,那么
> The completion handler for an I/O operation initiated on a channel bound to a group is guaranteed to be invoked by one of the pooled threads in the group. (摘自 JavaDoc ),就是说你的回调函数会在 I/O 结束之后被异步处理的线程调用。 |
53
a570295535 2019-11-18 13:35:19 +08:00
@des 写的很不错👍
|
55
iIli1iIliIllLiL 2019-11-22 14:05:49 +08:00
需要了解下异步与同步非阻塞的区别
|
56
mazai 2019-12-02 19:03:24 +08:00
可以去看下 Reactor 模式,看完以后你就会明白了,且 netty 对 NIO 进行了改进和增强,以及封装了一些协议,实现了 zero-copy 等,这就是他强大的地方。吊打其他同类型框架。
|