配置springcloud的gateway的時候,需要用到webflux,所以需要學習一下。以下是目前我的理解,可能不正確,但是會持續修正。
什么是webflux?目前的認知是異步非阻塞IO的webMVC,因為之前的Springmvc是基於同步阻塞IO模型的Servlet實現的,包括tomcat,jetty等傳統的servlet容器,因為他們的servlet不支持異步非阻塞,所以,每個請求在獲取資源的時候,系統資源都在該請求的名下,顯而易見,這是會浪費很多資源的,因為在進行資源IO的時候,如果資源阻塞,線程等資源需要等待被請求資源的IO喚醒。所以傳統的tomcat,jetty在性能方面有很大的限制,這也是springmvc面臨的問題。所以springwebflux伴隨spring5出現了。
以及下圖sringboot2.0中webflux和mvc技術棧的對比:


可以看出響應式Reactive技術棧是其新的技術要點。
外部條件有限制,所以 Buffer 需要有上限;
Buffer 達到上限這個現象,有一個簡化的等價詞叫做 Backpressure;
Backpressure 的出現其實是一種危險邊界,唯一的選擇是丟棄新事件。
Reactor:
Reactor模式也叫反應器模式,大多數IO組件如reids,netty都在使用的IO模式,以此來解決高性能並發。Reactor被分為handler和reactor兩個部分,前者負責業務處理,后者負責io接受分發。
回顧一下IO歷史:
連軸轉:一個while處理全部請求(單線程)。一個請求阻塞全部阻塞。
connection per thread:一個請求一個線程。一個線程只能處理一個請求,即使語法上允許一個線程處理多個請求,但是一個線程上的一個請求被阻塞,其他也會阻塞;每個線程都是系統的資源,耗費資源巨大,創建銷毀線程也需要消耗資源。
Java.NIO: (NIO的Selector網絡通訊就是一個單線程版的Reactor)。一個典型的NIO代碼:
1 static class Server 2 { 3 4 public static void testServer() throws IOException 5 { 6 7 // 1、獲取Selector選擇器 8 Selector selector = Selector.open(); 9 10 // 2、獲取通道 11 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 12 // 3.設置為非阻塞 13 serverSocketChannel.configureBlocking(false); 14 // 4、綁定連接 15 serverSocketChannel.bind(new InetSocketAddress(SystemConfig.SOCKET_SERVER_PORT)); 16 17 // 5、將通道注冊到選擇器上,並注冊的操作為:“接收”操作 18 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 19 20 // 6、采用輪詢的方式,查詢獲取“准備就緒”的注冊過的操作 21 while (selector.select() > 0) 22 { 23 // 7、獲取當前選擇器中所有注冊的選擇鍵(“已經准備就緒的操作”) 24 Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator(); 25 while (selectedKeys.hasNext()) 26 { 27 // 8、獲取“准備就緒”的時間 28 SelectionKey selectedKey = selectedKeys.next(); 29 30 // 9、判斷key是具體的什么事件 31 if (selectedKey.isAcceptable()) 32 { 33 // 10、若接受的事件是“接收就緒” 操作,就獲取客戶端連接 34 SocketChannel socketChannel = serverSocketChannel.accept(); 35 // 11、切換為非阻塞模式 36 socketChannel.configureBlocking(false); 37 // 12、將該通道注冊到selector選擇器上 38 socketChannel.register(selector, SelectionKey.OP_READ); 39 } 40 else if (selectedKey.isReadable()) 41 { 42 // 13、獲取該選擇器上的“讀就緒”狀態的通道 43 SocketChannel socketChannel = (SocketChannel) selectedKey.channel(); 44 45 // 14、讀取數據 46 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 47 int length = 0; 48 while ((length = socketChannel.read(byteBuffer)) != -1) 49 { 50 byteBuffer.flip(); 51 System.out.println(new String(byteBuffer.array(), 0, length)); 52 byteBuffer.clear(); 53 } 54 socketChannel.close(); 55 } 56 57 // 15、移除選擇鍵 58 selectedKeys.remove(); 59 } 60 } 61 62 // 7、關閉連接 63 serverSocketChannel.close(); 64 } 65 66 public static void main(String[] args) throws IOException 67 { 68 testServer(); 69 } 70 }
從上面代碼可知,NIO通過一個線程就完成了傳統IO需要大量資源提供的IO操作,且效率極高。但是缺點也很明顯,任何IO資源的操作都有可能導致阻塞,進而導致這個NIO系統阻塞。這在web項目中是不能容忍的。所以也就沒有單線程的Reactor。
多線程的Reactor:
1. Handler資源處理器的執行被放入線程池中進行,以多線程的方式進行資源處理。(主要)
2. 而對於Reactor而言,可以仍為單個線程。如果服務器為多核的CPU,為充分利用系統資源,可以將Reactor拆分為兩個線程。(升級)
Reactor模式的優點:
1)響應快,不必為單個同步時間所阻塞,雖然Reactor本身依然是同步的;
2)編程相對簡單,可以最大程度的避免復雜的多線程及同步問題,並且避免了多線程/進程的切換開銷;
3)可擴展性,可以方便的通過增加Reactor實例個數來充分利用CPU資源;
4)可復用性,reactor框架本身與具體事件處理邏輯無關,具有很高的復用性;
