如何使用socket进行java网络编程(六)

     时间过得很快,一转眼已是3年后。个人的修炼不能停,接下来准备讨论一下课题:nio, nio2, apr, 符合servlet标准的基于tomcat等底层服务器的框架、如spring mvc, 基于netty底层服务器的异步非阻塞框架webflux。把对io的理解再提升一个层次。

服务器能连多少个连接,和实际能并发处理多少是两回事儿,现在的服务器如果配置过关、系统参数优化得当,是能同时连大量的连接的,比如上百万个。但连上来之后,如何处理就是大问题了。传统的bio采用的策略是一个连接就得分配一个线程去处理这个连接的read() wirte(),有1万个连接连上来就得分1万个线程,这显然扯淡。

nio可以实现各种不同的服务器,不能一概而论的认为使用nio实现的服务器就是如何如何的(比如异步的、比如非阻塞的)。以tomcat为例,1万连接使用200个线程处理,1万个连接连上来后,都注册到selector上,然后监听到来自这些个连接上的read、write事件,由poller线程(tomcat里一般是两个)轮询感知并把有事件发生的连接发给身后的工作线程池处理(比如1万个连接此时有100个连接发生了read事件,那将会有100个工作线程从池里出来去处理read),这样就实现了少量线程处理大量连接这样一个目的。但是我们发现,在工作线程接收了来自poller分过来的连接后,还是要自己去从连接里read(),wirte()的,这个过程是阻塞的。

tomcat在这里并没有利用接收过来的连接的socket.setBlocking(false)这个特性(指注册到selector的做法),而是当前工作线程不断的去循环调用read、write方法,直到读写完,这样整体来看,工作线程是阻塞的。(待确认) https://my.oschina.net/wangxindong/blog/1562957

解决办法是来使用select的方法,在读写事件未就绪(中途没数据可读或咱无法向连接写入)的时候让工作线程能够解放出来去搞别的,让工作线程一直不停跑,不阻塞、保持“繁忙”。

这样工作线程就从work thread变成了work loop 。(找到了netty的影子)

2020-9-22  接下来的计划是这样的,第一阶段先得把这个老外的demo吃透:https://github.com/jjenkov/java-nio-server   一个异步非阻塞的小服务器

                  为此,基本的大的结构是能理解的,细节部分比如buffer、消息的读写还没完全搞清楚,所以先得看这哥们的另一篇文章,

                  《Java resizable Array》http://tutorials.jenkov.com/java-performance/resizable-array.html

                 第二阶段可以使用基于以上思想的现成的*改造一个已有的应用,提高其性能,io密集型应用:应用网关、日志收集应用。

这篇文档是讲如何用reactive技术栈开发web应用的,这些应用可以跑在诸如netty、undertow和servlet3.1+容器等非阻塞的服务器上。
文档分章节介绍了spring webflux框架、reactive客户端工具webcliet、测试支持、以及reactive库。 
这个文档是介绍reactive技术栈的,如果想了解如何用servlet技术栈开发web应用,请参考https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#spring-web这篇文档。
 
 
译者注:这个官方的基于reactive技术栈的web开发reference,一共分为Spring WebFlux, WebClient, WebSockets, Testing, RSocket, Reactive Libraries等6个章节。其中第1个章节Spring WebFlux内容最多,占了大部分篇幅,有必要先总览一下:
1.1  overview  概述
1.2 Reactive Core 
          反应式的核心,spring-web 这个模块提供了开发反应式web应用的基础支撑:
  • 对于服务端的request处理提供了两个级别的支持:
          1、HttpHandler:基本的用来处理http请求的contract,使用非阻塞io和反应流背压,以及Reactor Netty, Undertow, Tomcat,
                                    Jetty, and any Servlet 3.1+ 容器的适配器。
          2、WebHandler API:  稍高一级的用于请求处理的通用web API,用来构建注解controller和函数式endpoint这类具体的编程模型。
 
  • 对于客户端,有一个基本的ClientHttpConnector contract 执行具有非阻塞I/O和反应流背压的HTTP请求,以及Reactor Netty 和Reactive Jetty HttpClient的适配器。 而应用层真正使用的上层封装库WebClient 构建在这个基本的contract之上。
 
  • 在客户端和服务端,由codecs 负责request和response的序列化和反序列化     
 
1.3 DispatcherHandler  
          介绍一下webflux框架的一个核心类DispatcherHandler,它的作用是请求的总控制器相当于spring mvc里的DispatcherServlet
1.4 Annotated Controllers   
          webflux的基于注解controller的开发模式
1.5 Functional Endpoints
          另一种基于函数式endpoint的开发模式, java8的lambda表达式编程风格
1.6 URI Links
          用于准备uri的各种方法和选项
1.7 CORS
          如何处理跨源资源共享(Cross-Origin Resource Sharing)
1.8 Web Security
          Spring Security项目保护web应用免受恶意攻击的威胁
1.9 View Technologies
          视图层相关技术,比如Thymeleaf, FreeMarker这些模版引擎
1.10 Http Caching
          讨论WebFlux中可用的http缓存相关的选项、正确使用HTTP缓存可以显著提高web应用的性能:
          (1)Cache-Control response header,控制浏览器或代理如何缓存以及重用response
          (2)条件request header,比如Last-Modified和ETag,  ETag可以认为是升级版的Last-Modified,
                  可以发起一个带条件的request:如果请求的内容没有修改的话,那么会直接返回304 (NOT_MODIFIED)、
                  而不用返回response body。
               (译者注:这样减少了网络上传输的字节,客户端知道本次请求的内容在服务端没有修改,可以直接读本地缓存的内容)
1.11  WebFlux Config
          WebFlux提供了一组Configuration API来声明用于处理请求的注解controller或函数式endpoint,
          开发者不需要去理解这些自动配置的底层的bean。但是如果想深入了解,你可以在 WebFluxConfigurationSupport 这个类里边
          看到这些bean,或者去读Special Bean Types了解更多关于这些bean的原理。另外,Configuration API里没提供的
          更高级的自定义配置选项,可以通过高级配置模式 Advanced Configuration Mode 来获得对配置项的完全控制。
1.12 HTTP/2 
          Reactor Netty, Tomcat, Jetty, 以及Undertow都支持 HTTP/2。 但是,还是有一些服务器相关的配置的注意事项的。
          有关更多详细信息,请参阅 HTTP/2 wiki page.