在线乱码卡一卡二卡新HD,最近韩国免费观看视频,国产色无码精品视频国产,亚洲男人的天堂久久香蕉

RPC設計應該使用哪種網絡IO模型?|全球熱頭條
來源:JavaEdge    時間:2023-02-27 08:03:38

網絡通信在RPC調用中起到什么作用呢?RPC是解決進程間通信的一種方式。一次RPC調用,本質就是服務消費者與服務提供者間的一次網絡信息交換的過程。服務調用者通過網絡IO發送一條請求消息,服務提供者接收并解析,處理完相關的業務邏輯之后,再發送一條響應消息給服務調用者,服務調用者接收并解析響應消息,處理完相關的響應邏輯,一次RPC調用便結束了??梢哉f,網絡通信是整個RPC調用流程的基礎。


(資料圖片)

1 常見網絡I/O模型

兩臺PC機之間網絡通信,就是兩臺PC機對網絡IO的操作。

同步阻塞IO、同步非阻塞IO(NIO)、IO多路復用和異步非阻塞IO(AIO)。只有AIO為異步IO,其他都是同步IO。

1.1 同步阻塞I/O(BIO)

Linux默認所有socket都是blocking。

應用進程發起IO系統調用后,應用進程被阻塞,轉到內核空間處理。之后,內核開始等待數據,等待到數據后,再將內核中的數據拷貝到用戶內存中,整個IO處理完畢后返回進程。最后應用的進程解除阻塞狀態,運行業務邏輯。

系統內核處理IO操作分為兩階段:

?等待數據系統內核在等待網卡接收到數據后,把數據寫到內核中?拷貝數據系統內核在獲取到數據后,將數據拷貝到用戶進程的空間

在這兩個階段,應用進程中IO操作的線程會一直都處于阻塞狀態,若基于Java多線程開發,每個IO操作都要占用線程,直至IO操作結束。

用戶線程發起read調用后就阻塞了,讓出CPU。內核等待網卡數據到來,把數據從網卡拷貝到內核空間,接著把數據拷貝到用戶空間,再把用戶線程叫醒。

1.2 IO多路復用(IO multiplexing)

高并發場景中使用最為廣泛的一種IO模型,如Java的NIO、Redis、Nginx的底層實現就是此類IO模型的應用:

?多路,即多個通道,即多個網絡連接的IO?復用,多個通道復用在一個復用器

多個網絡連接的IO可注冊到一個復用器(select),當用戶進程調用select,整個進程會被阻塞。同時,內核會“監視”所有select負責的socket,當任一socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從內核中拷貝到用戶進程。

當用戶進程發起select調用,進程會被阻塞,當發現該select負責的socket有準備好的數據時才返回,之后才發起一次read,整個流程比阻塞IO要復雜,似乎更浪費性能。但最大優勢在于,用戶可在一個線程內同時處理多個socket的IO請求。用戶可注冊多個socket,然后不斷調用select讀取被激活的socket,即可達到在同一個線程內同時處理多個IO請求的目的。而在同步阻塞模型中,必須通過多線程實現。

好比我們去餐廳吃飯,這次我們是幾個人一起去的,我們專門留了一個人在餐廳排號等位,其他人就去逛街了,等排號的朋友通知我們可以吃飯了,我們就直接去享用。

本質上多路復用還是同步阻塞。

1.3 為何阻塞IO,IO多路復用最常用?

網絡IO的應用上,需要的是系統內核的支持及編程語言的支持。

大多系統內核都支持阻塞IO、非阻塞IO和IO多路復用,但像信號驅動IO、異步IO,只有高版本Linux系統內核支持。

無論C++還是Java,在高性能的網絡編程框架都是基于Reactor模式,如Netty,Reactor模式基于IO多路復用。非高并發場景,同步阻塞IO最常見。

應用最多的、系統內核與編程語言支持最為完善的,便是阻塞IO和IO多路復用,滿足絕大多數網絡IO應用場景。

1.4 RPC框架選擇哪種網絡IO模型?

IO多路復用適合高并發,用較少進程(線程)處理較多socket的IO請求,但使用難度較高。

阻塞IO每處理一個socket的IO請求都會阻塞進程(線程),但使用難度較低。在并發量較低、業務邏輯只需要同步進行IO操作的場景下,阻塞IO已滿足需求,并且不需要發起select調用,開銷比IO多路復用低。

RPC調用大多數是高并發調用,綜合考慮,RPC選擇IO多路復用。最優框架選擇即基于Reactor模式實現的框架Netty。Linux下,也要開啟epoll提升系統性能。

2 零拷貝(Zero-copy)2.1 網絡IO讀寫流程

應用進程的每次寫操作,都把數據寫到用戶空間的緩沖區,CPU再將數據拷貝到系統內核緩沖區,再由DMA將這份數據拷貝到網卡,由網卡發出去。一次寫操作數據要拷貝兩次才能通過網卡發送出去,而用戶進程讀操作則是反過來,數據同樣會拷貝兩次才能讓應用程序讀到數據。

應用進程一次完整讀寫操作,都要在用戶空間與內核空間中來回拷貝,每次拷貝,都要CPU進行一次上下文切換(由用戶進程切換到系統內核,或由系統內核切換到用戶進程),這樣是不是很浪費CPU和性能呢?那有沒有什么方式,可以減少進程間的數據拷貝,提高數據傳輸的效率呢?

這就要零拷貝:取消用戶空間與內核空間之間的數據拷貝操作,應用進程每一次的讀寫操作,都讓應用進程向用戶空間寫入或讀取數據,就如同直接向內核空間寫或讀數據一樣,再通過DMA將內核中的數據拷貝到網卡,或將網卡中的數據copy到內核。

2.2 實現

是不是用戶空間與內核空間都將數據寫到一個地方,就不需要拷貝了?想到虛擬內存嗎?

虛擬內存

零拷貝有兩種實現:

mmap+write

通過虛擬內存來解決。

sendfile

Nginx sendfile

3 Netty零拷貝

RPC框架在網絡通信框架的選型基于Reactor模式實現的框架,如Java首選Netty。那Netty有零拷貝機制嗎?Netty框架中的零拷貝和我之前講的零拷貝又有什么不同呢?

上節的零拷貝是os層的零拷貝,為避免用戶空間與內核空間之間的數據拷貝操作,可提升CPU利用率。

而Netty零拷貝不大一樣,他完全站在用戶空間,即JVM上,偏向于數據操作的優化。

Netty這么做的意義

傳輸過程中,RPC不會把請求參數的所有二進制數據整體一下子發送到對端機器,中間可能拆分成好幾個數據包,也可能合并其他請求的數據包,所以消息要有邊界。一端的機器收到消息后,就要對數據包處理,根據邊界對數據包進行分割和合并,最終獲得一條完整消息。

那收到消息后,對數據包的分割和合并,是在用戶空間完成,還是在內核空間完成的呢?

當然是在用戶空間,因為對數據包的處理工作都是由應用程序來處理的,那么這里有沒有可能存在數據的拷貝操作?可能會存在,當然不是在用戶空間與內核空間之間的拷貝,是用戶空間內部內存中的拷貝處理操作。Netty的零拷貝就是為了解決這個問題,在用戶空間對數據操作進行優化。

那么Netty是怎么對數據操作進行優化的呢?

?Netty 提供了 CompositeByteBuf 類,它可以將多個 ByteBuf 合并為一個邏輯上的 ByteBuf,避免了各個 ByteBuf 之間的拷貝。?ByteBuf 支持 slice 操作,因此可以將 ByteBuf 分解為多個共享同一個存儲區域的 ByteBuf,避免了內存的拷貝。?通過 wrap 操作,我們可以將 byte[] 數組、ByteBuf、ByteBuffer 等包裝成一個 Netty ByteBuf 對象, 進而避免拷貝操作。

Netty框架中很多內部的ChannelHandler實現類,都是通過CompositeByteBuf、slice、wrap操作來處理TCP傳輸中的拆包與粘包問題的。

Netty解決用戶空間與內核空間之間的數據拷貝

Netty 的 ByteBuffer 采用 Direct Buffers,使用堆外直接內存進行Socket的讀寫操作,最終的效果與我剛才講解的虛擬內存所實現的效果一樣。

Netty 還提供 FileRegion 中包裝 NIO 的 FileChannel.transferTo() 方法實現了零拷貝,這與Linux 中的 sendfile 方式在原理一樣。

4 總結

零拷貝帶來的好處就是避免沒必要的CPU拷貝,讓CPU解脫出來去做其他的事,同時也減少了CPU在用戶空間與內核空間之間的上下文切換,從而提升了網絡通信效率與應用程序的整體性能。

Netty零拷貝與os的零拷貝有別,Netty零拷貝偏向于用戶空間中對數據操作的優化,這對處理TCP傳輸中的拆包粘包問題有重要意義,對應用程序處理請求數據與返回數據也有重要意義。

關鍵詞: 系統內核 多路復用 用戶進程 應用進程 網絡通信

上一篇:

下一篇:

X 關閉

X 關閉

<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>