关于 Java 和 go 高并发的话题

2021-07-22 22:45:05 +08:00
 MakHoCheung
go 因为有协程,所以高并发是它的一大优势,但是我看博客,别人说 groutine 的底层也是线程池,这样跟 Java 也一样,为什么 go 在高并发这块就很厉害呢(我不知道 Java 在高并发这块是不是比 go 弱,我没做过什么高并发项目)。发散一下就是 Java 的 NIO +线程池(现实例子就是 netty )跟 go 在高并发这块差距是不是巨大?
6980 次点击
所在节点    问与答
93 条回复
btnokami
2021-07-23 02:01:29 +08:00
@MakHoCheung
并没有线程上下文切换,这几个协程还是跑在同一个 os thread 上。线程上下文切换是指 cpu 上的实体线程里 os thread 切换的过程,这个过程是在会有 user space 到 kernel space 的切换同时 kernel space 里也会做 os thread 的切换,而协程的切换全发生在 user space 里且没有 os thread 的切换
sagaxu
2021-07-23 02:46:17 +08:00
http 怎么就不能用 nio 了? jcbc 怎么就不能了?楼主你太想当然了。
MakHoCheung
2021-07-23 08:59:18 +08:00
@sagaxu 我学的 NIO 是 Java 的 IO 多路复用,register 和 select 的 socket,现在 urlconnection 和 jdbc 怎么做到让 selector select 呢?
MakHoCheung
2021-07-23 09:12:18 +08:00
@btnokami 这个说得跟官方文档说得一样,但要追究到底层原理,协程遇到了阻塞的 IO 被阻塞了,运行当前代码的线程( os 只有线程)怎么办,很明显为了非阻塞被调度到其他线程去等待 io 吧。当然有某些操作完全可以由线程内部调度,不需要切换线程
securityCoding
2021-07-23 09:21:17 +08:00
一个用户态,一个内核态
cheng6563
2021-07-23 09:27:05 +08:00
只要你能一个线程同时处理多个连接,那么性能就是一个级别的。

区别就是 Java 要用 aio 甚至 nio,写起来麻烦的要死
用 go 的话直接无脑用类似 bio 的写法就行了。
slipper
2021-07-23 09:58:59 +08:00
底层也是线程,只不过在上层封装了一个 goroutine,这个 goroutine 能让你用同步的逻辑写出异步的代码。

这个封装层就是 runtime,他还帮你做了 goroutine 调度,也就是上面说的:当线程在 epoll wait 时,让这个线程处理另一个 goroutine 。如果没有这一层,java 中是要你手动实现调度的。调度还是比较麻烦的一件事。

runtime 同时要帮你进行 goroutine 注册回收挂起等待等一系列帮你减轻编码难度的逻辑。

goroutine 严格来说是在用户态保存了执行上下文的数据结构。而线程是内核态保存上下文的结构,所以更加轻量。所以线程是进程的执行路径,goroutine 是线程的执行路径。
sagaxu
2021-07-23 10:08:28 +08:00
@MakHoCheung
https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html#sendAsync(java.net.http.HttpRequest,java.net.http.HttpResponse.BodyHandler)

r2dbc 和 vertx-sql-client 都提供了异步版的 db 访问。但个人觉得异步 db 目前意义不大,并发稍高 db 服务端就挂了,瓶颈并不在 client 这里。db 的瓶颈是 CPU 和磁盘 IO,这两个都害怕高并发。
MakHoCheung
2021-07-23 10:30:18 +08:00
@sagaxu r2dbc 这些我知道,但是人家并不是基于 jdbc,我说的是应该最广泛的 jdbc 。然后就是 java11 的 httpclient 的异步请求底层就是基于 completableFuture,实际基于线程池,跟我说的 NIO 或者 eventloop 不是一回事。我说的 NIO 是 IO 多路复用,希望(注意只是我臆想)可以把整个 web 应用的所有(注意是所有)数据库请求等待放到 eventloop 里面,一条线程进行 IO 轮询,另外一条线程处理到来的数据库数据
btnokami
2021-07-23 10:33:47 +08:00
@MakHoCheung
并不是,如果当前线程运行遇到了 IO 阻塞,runtime 让当前协成 yield 然后把另一个协成安排到当前线程上跑,线程本身并没有切换。协成的切换不是 pre-emptive 的,而是 cooperative 的。
MakHoCheung
2021-07-23 10:35:41 +08:00
@sagaxu 其实我猜想的是目前服务接受可以用 netty 的 reactor 模式处理收到请求,能不能也用 netty 的 reactor 模式处理服务对外发送的请求呢( rpc ),这种 eventloop 跟 connection per thread 对比又会不会高效呢?这都是我的猜想
MakHoCheung
2021-07-23 10:40:47 +08:00
@btnokami go 遇到 io 阻塞居然不需要线程切换,我有空好好研究研究
dqzcwxb
2021-07-23 10:44:39 +08:00
![3KG0M0234Q(~WJMW$E241@G.png]( )
btnokami
2021-07-23 10:51:52 +08:00
@MakHoCheung
也不是完全不需要,go runtime 会首先试着讲 blocking syscall 换成 non-blocking 的版本然后 yield,如果实在不行,go runtime 会建新的 thread 然后讲 blocking call 移过去
但是大体上来说协程切换并不需要线程切换
sagaxu
2021-07-23 11:03:34 +08:00
@MakHoCheung 那你可以看看 vertx,发起 http 请求也是走 netty eventloop 。我有个项目之前用多线程阻塞(每台 server 1000 或 2000 个线程),后来重构成 vertx(每台 4 个 eventloop 线程),日均十几亿来自 app 的 http 请求,两种模型都扛住了,但非阻塞版的上限更高,至少能扛住 50 亿请求。

也有使用 Go 开发的服务,并发性能跟 Java 没多少区别,用协程就是写起来简单一点,没有回调地狱。
3dwelcome
2021-07-23 11:28:50 +08:00
@sagaxu 那你改成 UDP 服务器,请求上限更高。

脱离实际场景,单纯对比数据没意义,33 楼就说了,代码不是不可以改,而是费了那么大功夫,这精力花的值不值。

具体还是要看服务器上,CPU 瓶颈,还是内存瓶颈,还是网络瓶颈。具体案例具体分析。
jingslunt
2021-07-23 11:53:40 +08:00
@iyaozhen
1. 协程不过是用户态的线程。
2.在 CPU 密集型任务下,多进程更快,或者说效果更好;而 IO 密集型,多线程能有效提高效率。
lesismal
2021-07-23 12:48:36 +08:00
普通并发量 go 还是有优势,写起来简单,不容易写出瓶颈,java 如果不异步性能太差,netty 了又 callback hell

go 标准库方案面对海量并发时协程数量、内存消耗、调度和 GC 等开销太狠,干不过 netty

我写了份异步库,应该可以干得过 netty:
https://github.com/lesismal/nbio

日几十亿这种提法应该是业务、运营数据这样吹牛比较好。对于技术,最好落到 qps/tps 之类的,这种才能算是性能指标。不信你算一下,10 亿请求每日,相当于多少请求每秒:
>>> print(1000000000/24/3600)
11574.074074074073

才 1 w多,二八原则,我算你峰值 10-20w 每秒。这种瓶颈在于数据层的承载力,不在于框架层,比如我上面自己的框架,4c8t 的单节点几十万连接数,echo 压测照样能跑十几、几十万 qps
aguesuka
2021-07-23 13:14:13 +08:00
使用到 jdbc 的场景, 请求的绝大部分的性能开销是在数据库, 也就没有必要通过异步来优化性能. 反之使用异步中间件的场景都是 eventloop + epoll, 性能绝不会比等价的 c 语言低太多
x940727
2021-07-23 14:11:22 +08:00
@lesismal 不是 Java 不异步性能太差,而是 Servlet 性能太差,Netty 实现的 Web Server 性能就很明显强过 Servlet,甚至不会比那些 Go 的 Web Server 性能差。说白了还是框架设计上的问题,如果单论语言性能,Java 是要强于 Go 的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/791169

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX