IO模型(Netty,Redis,Zookeeper高併發實戰整理)

IO的基本概念

read系統調用,並不是直接從物理設備把數據讀取到內存中;write系統調用,也不是直接把數據寫入到物理設備。上層應用無論是調用操作系統的read,還是調用操作系統的write,都會涉及緩衝區。具體來說,調用操作系統的read,是把數據從內核緩衝區複製到進程緩衝區;而write系統調用,是把數據從進程緩衝區複製到內核緩衝區。

緩衝區意義

外部設備的直接讀寫,設計操作系統的中斷,發生系統中斷時,需要保存之前的進程數據和狀態等信息,而結束中斷之後,還需要恢復之前的進程數據和狀態等信息,爲了減少這種底層系統的時間損耗,性能損耗,於是在上層應用和下層硬件之間有出現了內存緩衝區。

有了內存緩衝區,上層應用使用read系統調用是,僅僅把數據從內核緩衝區去複製到上層應用的緩衝區(進程緩衝區);上層應用使用write系統調用是,僅僅把數據從進程緩衝區複製到內核緩衝區。

底層操作會對內核緩衝去進行監控,等待緩衝去達到一定數量的時候,在進行IO設備的終端處理,集中執行物理設備的實際IO操作,這種機制提升了系統的性能。

Linux系統中,操作系統內核只有一個內核緩衝區,而每個用戶程序(進程),有自己獨立的緩衝區,叫做進程緩衝區。所以,用戶程序的io讀寫程序,在大多數情況下,併爲沒有進行實際的IO操作,二十在進程緩衝區和內核緩衝區之間直接進行數據的交換。

IO模型

同步阻塞IO(Blocking IO)

阻塞與非阻塞

阻塞IO,指的是需要內核io操作徹底完成後,才返回到用戶空間執行用戶的操作。阻塞指的是用戶空間程序的執行狀態。

同步與異步

同步IO,是一種用戶空間與內核空間IO發起方式。同步io是指用戶空間的線程是主動發起io請求的一方,內核空間是被動接受方。異步io,是這系統內核主動發起IO請求的一方,用戶空間的線程是被動接受方。

BIO調用流程

在java應用程序進程中,默認情況下,所有的socketk連接的IO操作都是同步阻塞io,在阻塞式io模型中,java應用程序從io系統調用開始,直到系統調用返回,在這段時間內,java進程是阻塞的。放回成功後,應用進程開始處理用戶空間的緩存區數據。

在java中發起一個socket的reed讀操作的系統調用,流程大致如下:

1.從java啓動io讀的read系統調用開始,用戶線程就進入阻塞狀態
2.當系統內核收到read系統調用,就開始準備數據。一開始,數據可能還沒有到達內核緩衝區,這個時候內核就要等待。
3.內核一直等到完整的數據到達,就會講數據從內核緩衝區複製到用戶緩衝區(用戶空間的內存),讓後內核返回結果(例如返回複製到用戶緩衝區中的字節數)。
4.直到內核返回後,用戶線程纔會解除阻塞的狀態,重新運行起來。

特點

阻塞io在執行的兩個階段,用戶線程都被阻塞了。

優點

應用的程序開發非常簡單;在阻塞等待數據期間,用戶線程掛起。在阻塞期間;用戶線程基本上不會佔用cpu資源

缺點

一般情況下,會爲每個連接配備一個獨立的線程;反過來說,就是一個線程維護一個連接的io操作。在併發量小的情況下,可用。不適合高併發的情況下。

同步非阻塞io(Non-blocking IO)

非阻塞Io,指定的是用戶空間的程序不要等待內核IO操作徹底完成,可以立即返回用戶空間執行用戶的操作,即處於非阻塞狀態,於此同時內核會立即放回給用戶一個狀態值。

阻塞是指用戶空間(調用線程)一直在等待,而不能幹別的事情;非阻塞是指用戶空間(調用線程)拿到內核返回的狀態值就返回自己的空間,IO操作就可以幹就幹,不可以幹,就去幹別的事情。

非阻塞io要求socket被設置成NOBBLOCK

在nio模型中,應用程序一旦開始io系統調用,會出現一下兩種情況:

1.在內核緩衝區中沒有數據的情況下,系統調用會立即放回,返回一個調用失敗的信息。
2.在內核緩衝區中有數據的情況下,是阻塞的,直到數據從內核緩衝區複製到用戶進程緩衝區。複製完成後,系統調用返回成功,應用程序開始處理用戶空間的緩衝數據。

NIO調用流程

在java中發起一個非阻塞socket的reed讀操作的系統調用,流程大致如下:

1.在內核數據沒有準備好的階段,用戶線程發起IO請求時,立即返回。所以爲了讀取到數據,用戶線程需要不斷地發起IO系統調用。查詢是否內核空間有要訪問的數據
2.內核數據到達後,用戶線程發起系統調用,用戶線程阻塞。內核開始複製數據,內核會將數據從內核緩衝區複製到用戶緩衝區(用戶空間的內存),然後內核返回結果(例如返回複製到的用戶緩衝區的字節數)。
3.用戶線程讀到數據後,纔會接觸阻塞狀態,重新運行起來。用戶線程需要經過多次的調用io才能保證最終正確讀到數據,進而繼續執行。

特點

應用程序的線程需要不斷地進行IO系統調用,輪詢數據是否已經準備好;如果沒有準備好,就繼續輪詢,知道io系統調用爲止。

優點

每次發起IO系統調用,在內核等待數據過程中可以立即返回,用戶線程不會阻塞,實用性較好

缺點

不斷地輪詢內核,這將佔用大量的cpu時間,效率低下

特別聲明:

同步非阻塞io,可以簡稱NIO,但是不是Java中的NIO,雖然他們的縮寫一樣。但Java的NIO對應的是IO多路複用器模型。

IO多路複用器(IO Muliplexing)

即經典的Reactor反應器設計模式,又是又稱異步阻塞IO,java中的Selector選擇器和linux中的epoll都是這種模型。

在IO多路複用器模型中,引用了一種新的系統調用,查詢IO的就緒狀態。在Linux系統中,對應的系統調用爲select/epoll系統調用,一個進程可以監視多個文件描述符,一旦某個文件描述符就緒(一般是內核緩衝區可讀/可寫),內核能夠將就緒的狀態返回給應用程序。隨後,應用程序根據就緒狀態,進行相應的IO系統調用。

在IO多路複用器模型中通過select/epoll系統調用,單個應用程序的線程,可以不斷輪詢成百上千的socket連接,當某個或者某些socket網絡連接有IO就緒的狀態,就返回對應的可以執行的讀寫操作。、

IO多路複用器調用流程

發起一個多路複用IO的read讀操作的系統調用,流程如下:

1,選擇器註冊,這種模式中,首先,講需要read操作的目標socket網絡連接,提前註冊到select/epoll選擇器中,Java的選擇器類是Selector類,然後纔可以開啓整個IO多路複用模型的輪詢流程。
2.就緒狀態的輪詢。通過選擇器的查詢方法,查詢註冊過的所有socket連接的就緒狀態。通過查詢的系統調用,內核會返回一個就緒的socket列表。當任何一個註冊過的socket中的數據準備好了,內核緩衝區有數據(就緒)了,內核就講socket加入就緒的列表中。當用戶進程調用了select查詢方法,那麼整個線程會被阻塞掉。
3.用戶線程獲得到了就緒狀態的列表後,根據其中的socket連接,發起read系統調用,用戶線程阻塞。內核開始複製數據,將數據從內核緩衝區複製到用戶緩衝區。
4.複製完成後,內核返回結果,用戶線程纔會解除阻塞的狀態,用戶線程讀取到了數據,繼續執行。

特點

IO多路複用器模型的IO涉及兩種系統調用,一種是IO操作,另一種是select/epoll(查詢數據的狀態)。IO多路複用模型建立在操作系統的基礎設施之上,即操作系統的內核必須能夠提供多路複用的系統調用select/epoll.

優點

與一個線程維護一個連接的阻塞IO模式相比,使用select/epoll的最大優勢是:一個選擇器查詢線程可以同時處理成千上萬個連接.系統不必創建大量的線程,也不必維護這些線程,從而大大減少了系統的開銷。

缺點

本質上,select/epoll系統調用是阻塞式的,屬於同步IO。都需要在讀寫事件就緒後,由系統本身負責進行讀寫,這個過程是阻塞的。

異步IO(Asychronous IO)

異步io,指的是用戶空間與內核空間的調用方式反過來。用戶空間的線程變成被動接受者,而內核空間變成了主動調用這。這有點類似與java中比較典型的回調模式,用戶空間的線程想內核空間註冊了各種IO事件的回調函數,有內核去主動調用。

異步IO(Asychronous IO). AIO的基本流程是:用戶線程通過系統調用,鄉內核註冊某個IO操作。內核在整個IO操作(數據準備,數據複製)完成後,通知用戶程序執行後續的業務操作。

在AIO模型中,在整個內核的數據處理過程中,包括內核將數據從網絡物理設備讀取都內核緩衝區,將內核緩衝區的數據複製到用戶緩衝區,用戶程序都不要阻塞。

AIO調用流程

發起一個異步IO的read讀操作的系統調用,流程如下:

1.當用戶線程發起了read系統調用,立刻就可以區開始區做其他的事了,用戶線程不阻塞。
2.內核就開始IO的第一個階段:準別數據。等數據準備好了,內核就會將數據從內核緩衝區複製到用戶緩衝區。
3.內核會給用戶線程發送一個信號,或者回調用戶線程註冊的回調接口,告訴用戶線程read操作完成了。
4.用戶線程讀取用戶緩衝區的數據,完成後續的業務操作。

特點

在內核準備數據和複製數據的兩個階段,用戶線程都不是阻塞的。用戶線程需要接收內核的IO操作完成的事件,或者用戶線程需要註冊一個IO操作完成的回調函數。正應爲如此,異步IO也被稱爲信號驅動IO。

缺點

應用程序僅需要進行事件的註冊與接受,其餘工作都留給了操作系統,需要底層內核提供支持。異步IO事真正的異步IO輸入輸出,吞吐量高於IO多路複用器的吞吐量。Windows系統下通過IOCP實現了真正的異步IO。而在Linux系統下,異步IO模型不完善,底層實現還是epoll,與IO多路複用相同。

參考書籍:
《Netty,Redis,Zookeeper高併發實戰》

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