Mycat 網絡通信模塊源碼

Mycat 用戶手冊:
系統I/O 可分爲阻塞型, 非阻塞同步型以及非阻塞異步型.
阻塞型I/O意味着控制權直到調用操作結束了纔會回到調用者手裏. 結果調用者被阻塞了, 這段時間了做不了任何其它事情. 更鬱悶的是,在等待IO結果的時間裏,調用者所在線程此時無法騰出手來去響應其它的請求,這真是太浪費資源了。拿read()操作來說吧, 調用此函數的代碼會一直僵在此處直至它所讀的socket緩存中有數據到來.
相比之下,非阻塞同步是會立即返回控制權給調用者的。調用者不需要等等,它從調用的函數獲取兩種結果:要麼此次調用成功進行了;要麼系統返回錯誤標識告訴調用者當前資源不可用,你再等等或者再試度看吧。比如read()操作, 如果當前socket無數據可讀,則立即返回EWOULBLOCK/EAGAIN,告訴調用read()者“數據還沒準備好,你稍後再試”。
在非阻塞異步調用中,稍有不同。調用函數在立即返回時,還告訴調用者,這次請求已經開始了。系統會使用另外的資源或者線程來完成這次調用操作,並在完成的時候知會調用者(比如通過回調函數)。拿Windows的ReadFile()或者POSIX的aio_read()來說,調用它之後,函數立即返回,操作系統在後臺同時開始讀操作。
在以上三種IO形式中,理論上,非阻塞異步是性能最高、伸縮性最好的。
同步和異步是相對於應用和內核的交互方式而言的,同步需要主動去詢問,而異步的時候內核在IO事件發生的時候通知應用程序,而阻塞和非阻塞僅僅是系統在調用系統調用的時候函數的實現方式而已。
對於JAVA的API來說:

  • java.net.Socket就是典型的阻塞型IO
  • java NIO非阻塞同步
  • java AIO非阻塞異步
    MyCAT起源於Cobar,Cobar前端爲NIO後端爲BIO,後端就是通過java.net.Socket進行讀寫,所以Cobar後端每次進行讀寫都會造成線程阻塞,後端能支持的連接總數就成爲瓶頸所在。
    MyCAT在基於Cobar改版時,直接採用了Java 7的AIO,前後端都實現了非阻塞異步。由於Linux並沒有真正實現AIO,實際測試下來,AIO並不比NIO快,反而性能上比NIO還要慢。所以MyCAT在2014年下半年,做了一次網絡通信框架的大調整,改爲同時支持AIO和NIO,通過啓動參數讓用戶來選擇哪種方式。雖然現在AIO比NIO慢,但是MyCAT仍然保留了AIO實現,就是爲了等Linux真正實現AIO後,可以直接支持。
    Reactor和Proactor
    MyCAT同時實現了NIO和AIO,爲了便於讀者更清楚理解代碼實現,先介紹NIO和AIO分佈對應的兩種設計模式:Reactor和Proactor
    一般情況下,I/O 複用機制需要事件分享器(event demultBossiplexor). 事件分享器的作用,即將那些讀寫事件源分發給各讀寫事件的處理者,就像送快遞的在樓下喊: 誰的什麼東西送了, 快來拿吧。開發人員在開始的時候需要在分享器那裏註冊感興趣的事件,並提供相應的處理者(event handlers),或者是回調函數; 事件分享器在適當的時候會將請求的事件分發給這些handler或者回調函數。
    涉及到事件分享器的兩種模式稱爲:Reactor和Proactor. Reactor模式是基於同步I/O的,而Proactor模式是和異步I/O相關的. 在Reactor模式中,事件分離者等待某個事件或者應用或操作的狀態發生(比如文件描述符可讀寫,或者是socket可讀寫),事件分離者就把這個事件傳給事先註冊的事件處理函數或者回調函數,由後者來做實際的讀寫操作。
    而在Proactor模式中,事件處理者(或者代由事件分離者發起)直接發起一個異步讀寫操作(相當於請求),而實際的工作是由操作系統來完成的。發起時,需要提供的參數包括用於存放讀到數據的緩存區,讀的數據大小,或者用於存放外發數據的緩存區,以及這個請求完後的回調函數等信息。事件分離者得知了這個請求,它默默等待這個請求的完成,然後轉發完成事件給相應的事件處理者或者回調。舉例來說,在Windows上事件處理者投遞了一個異步IO操作(稱有overlapped的技術),事件分離者等IOCompletion事件完成. 這種異步模式的典型實現是基於操作系統底層異步API的,所以我們可稱之爲“系統級別”的或者“真正意義上”的異步,因爲具體的讀寫是由操作系統代勞的。
    Reactor與Proactor兩種模式的場景區別:
    下面是Reactor的做法:
    1. 等待事件響應 (Reactor job)
    2. 分發 “Ready-to-Read” 事件給用戶句柄 ( Reactor job)
    3. 讀數據 (user handler job)
    4. 處理數據( user handler job)
      下面再來看看真正意義的異步模式Proactor是如何做的:
    5. 等待事件響應 (Proactor job)
    6. 讀數據 (Proactor job)
    7. 分發 “Read-Completed” 事件給用戶句柄 (Proactor job)
    8. 處理數據(user handler job)
      從上面可以看出,Reactor和Proactor模式的主要區別就是真正的讀取和寫入操作是有誰來完成的,Reactor中需要應用程序自己讀取或者寫入數據,而Proactor模式中,應用程序不需要進行實際的讀寫過程,它只需要從緩存區讀取或者寫入即可,操作系統會讀取緩存區或者寫入緩存區到真正的IO設備.
      最後結合下面的兩張圖更容易理解(這是別人的圖,非原創):\

Mycat 網絡通信模塊源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章