搞一遍,优雅的文章 netty Reactor模式(源码死磕
源码比较简单移动,回顾一下结果。
单线程模式的缺点:
1、 当其中某个 handler 阻塞时, 会导致其他所有的 client 的 handler 都得不到执行, 并且更严重的是, handler 的阻塞也会导致整个服务不能接收新的 client 请求(因为 acceptor 也被阻塞了)。 因为有这么多的缺陷, 因此单线程Reactor 模型用的比较少。这种单线程模型不能充分利用多核资源,所以实际使用的不多。
Reactor线程是个多面手,负责多路分离套接字,Accept新连接,并分派请求到Handler处理器中。
单线程模型适用场景
单线程模型 仅仅适用于handler 中业务处理组件能快速完成的场景。
多线程的Reactor
5.1. 基于线程池的改进
在线程Reactor模式基础上,做如下改进: (1)将Handler处理器的执行放入线程池,多线程进行业务处理。 (2)而对于Reactor而言,可以仍为单个线程。如果服务器为多核的CPU,为充分利用系统资源,可以将Reactor拆分为两个线程。
Netty的默认启动线程
Netty的默认启动了电脑可用线程数的两倍,在调用了bind方法的时候执行。
Reactor编程的优点和缺点
6.1. 优点
1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;
2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;
4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;
6.2. 缺点
1)相比传统的简单模型,Reactor增加了一定的复杂性,因而有一定的门槛,并且不易于调试。
2)Reactor模式需要底层的Synchronous Event Demultiplexer支持,比如Java中的Selector支持,操作系统的select系统调用支持,如果要自己实现Synchronous Event Demultiplexer可能不会有那么高效。
3) Reactor模式在IO读写数据时还是在同一个线程中实现的,即使使用多个Reactor机制的情况下,那些共享一个Reactor的Channel如果出现一个长时间的数据读写,会影响这个Reactor中其他Channel的相应时间,比如在大文件传输时,IO操作就会影响其他Client的相应时间,因而对这种操作,使用传统的Thread-Per-Connection或许是一个更好的选择,或则此时使用改进版的Reactor模式如Proactor模式。
技术背景:网关升级
1.原本的zuul网关已经不使用业务的快速扩张了。
2.原本业务支持:两个品牌 + 两个子品牌
技术选型:
- gateway -》 servlet3.0 ->还是没有解决根本问题
- webFlux
- vert.x
- 使用go语言来重写
go方面的好文章,关于 reactor go方面的好文章
[事件驱动模型]
vert.x
1.基于netty,单线程事件驱动的异步工作模式。Vert.x的核心运行机制是事件循环,当Vert.x实例启动后,Vert.x框架在每个CPU的内核创建一个事件循环线程。此事件循环线程永不结束,它不断监听出现的各种事件,如事件总线的事件到达WebSocket上的数据接收,HTTP上的请求到达HTTP响应结束,定时器触发等等,并把事件分发到注册了监听此事件的Verticle,再继续监听其他的事件,如此反复直到Vert.x实例停止。
2.Vert.x采用单一组件结构设计,即Verticle,解耦合,通过事件总线来间接调用
3.监听订阅模式。Vert. x通过提供一整套的异步编程API实现异步编程模型,在Vert. x中所有的请求处理都是通过注册事件监听处理器机制完成的。编程TCP处理服务器Verticle,通过注册TCPSocket的数据到达事件监听器,实现数据到达后的回调处理,而不是采用一直等待数据读取的阻塞模式,实现的是非阻塞的异步工作模式。
2. webFlux
在搜索webFlux资料的时候,思维跳跃到 反应式编程
对于后端开发,响应式编程真的是大势所趋吗?
在此处,引用个人我觉得非常好的回答
作者:dreamlike-ocean
链接:www.zhihu.com/question/37…
以下回答均基于java生态而言
rust怎么这么难从我个人角度来说:是也不是。由于我是个java程序员 我从java角度阐述我的看法 我自己平常写响应式代码都是基于Vert.x来写,同时配合kt的协程来做代码风格的同步化 就上面这一句来讲就已经解释了为什么我认为对于后端开发,响应式编程是大势所趋也不是了
为什么不是大势所趋?
随着Go,node.js之类的的兴起,让更多的开发者发现我们其实只需要少量的内核线程就可以支撑起原来上百线程的并发(指Sping内嵌的Tomcat这种 默认给你开200线程的servlet容器),再加之Jakarta EE标准的延后性,其实Java这边落后了很多了(当然也有servlet历史包袱的原因)。大量的内核线程带来了什么结果?内存占用高,大量的上下文切换导致的性能下降(cache miss之类的),高昂的锁代价,浪费的CPU时钟资源。当我们把一个内核线程当作并发处理中的最小单元,但是业务中最小的单元可能是一个事务,一个连接,以socket连接举例子 当我们处理一个连接时是使用一个线程处理一个连接,一台服务器可能有数千个连接但我们不能开数千个线程去处理 这种数量级的不匹配会导致硬件可以支持的服务规模急剧减少,此时我们就可能去利用nio(netty mina这种框架)去改造,进而提高性能,这种情况就是响应式极好的用武之地。
从C10K角度来看,nio确实是一个很好的解决方案,Tomcat底层也是基于nio,但是为什么到业务处理层我们还是同步的呢?或者说为什么业务层不也使用异步响应式思想呢?
首先响应式是基于事件的,在api的表现上就是write(buffer,callbcak),一旦业务复杂起来回调地狱势必会出现,哪怕我们将其用promise/future改造也只是将回调打平了而已其实没有解决实际问题,同时回调还存在一个问题——会丢失大量堆栈信息,仅仅保留那些被捕获进来的状态(无栈协程也有这个问题)
...以下省略上千字,引用作者观点。
所以我认为java在网络IO的未来在于利用loom提供的虚拟线程无缝升级,把IO层面的响应式交给运行时环境去做,至于业务层面的响应式则是仁者见仁智者见智了,如果你需要可以去做,对于普通的crud其实现在已经Spring这套同步servlet做的足够好了,只不过从更好的性能和开发体验来讲基于内置式的响应式IO实现的同步socket api肯定是大势所趋
作者:dreamlike-ocean
链接:www.zhihu.com/question/37…
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- webFlux 转 webFlux入门
3.go 的 gev
reference
最终技术选型:待定.........................
小游戏,抽奖,节假日,疫情后的门店快速扩张,都会造成流量的激增。