自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

RPC設(shè)計(jì)應(yīng)該使用哪種網(wǎng)絡(luò)IO模型?

網(wǎng)絡(luò) 通信技術(shù)
零拷貝帶來的好處就是避免沒必要的CPU拷貝,讓CPU解脫出來去做其他的事,同時(shí)也減少了CPU在用戶空間與內(nèi)核空間之間的上下文切換,從而提升了網(wǎng)絡(luò)通信效率與應(yīng)用程序的整體性能。

網(wǎng)絡(luò)通信在RPC調(diào)用中起到什么作用呢?RPC是解決進(jìn)程間通信的一種方式。一次RPC調(diào)用,本質(zhì)就是服務(wù)消費(fèi)者與服務(wù)提供者間的一次網(wǎng)絡(luò)信息交換的過程。服務(wù)調(diào)用者通過網(wǎng)絡(luò)IO發(fā)送一條請(qǐng)求消息,服務(wù)提供者接收并解析,處理完相關(guān)的業(yè)務(wù)邏輯之后,再發(fā)送一條響應(yīng)消息給服務(wù)調(diào)用者,服務(wù)調(diào)用者接收并解析響應(yīng)消息,處理完相關(guān)的響應(yīng)邏輯,一次RPC調(diào)用便結(jié)束了??梢哉f,網(wǎng)絡(luò)通信是整個(gè)RPC調(diào)用流程的基礎(chǔ)。

1 常見網(wǎng)絡(luò)I/O模型

兩臺(tái)PC機(jī)之間網(wǎng)絡(luò)通信,就是兩臺(tái)PC機(jī)對(duì)網(wǎng)絡(luò)IO的操作。

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

1.1 同步阻塞I/O(BIO)

Linux默認(rèn)所有socket都是blocking。

應(yīng)用進(jìn)程發(fā)起IO系統(tǒng)調(diào)用后,應(yīng)用進(jìn)程被阻塞,轉(zhuǎn)到內(nèi)核空間處理。之后,內(nèi)核開始等待數(shù)據(jù),等待到數(shù)據(jù)后,再將內(nèi)核中的數(shù)據(jù)拷貝到用戶內(nèi)存中,整個(gè)IO處理完畢后返回進(jìn)程。最后應(yīng)用的進(jìn)程解除阻塞狀態(tài),運(yùn)行業(yè)務(wù)邏輯。

系統(tǒng)內(nèi)核處理IO操作分為兩階段:

  • ? 等待數(shù)據(jù)系統(tǒng)內(nèi)核在等待網(wǎng)卡接收到數(shù)據(jù)后,把數(shù)據(jù)寫到內(nèi)核中
  • ? 拷貝數(shù)據(jù)系統(tǒng)內(nèi)核在獲取到數(shù)據(jù)后,將數(shù)據(jù)拷貝到用戶進(jìn)程的空間

在這兩個(gè)階段,應(yīng)用進(jìn)程中IO操作的線程會(huì)一直都處于阻塞狀態(tài),若基于Java多線程開發(fā),每個(gè)IO操作都要占用線程,直至IO操作結(jié)束。

用戶線程發(fā)起read調(diào)用后就阻塞了,讓出CPU。內(nèi)核等待網(wǎng)卡數(shù)據(jù)到來,把數(shù)據(jù)從網(wǎng)卡拷貝到內(nèi)核空間,接著把數(shù)據(jù)拷貝到用戶空間,再把用戶線程叫醒。

圖片

1.2 IO多路復(fù)用(IO multiplexing)

高并發(fā)場(chǎng)景中使用最為廣泛的一種IO模型,如Java的NIO、Redis、Nginx的底層實(shí)現(xiàn)就是此類IO模型的應(yīng)用:

  • ? 多路,即多個(gè)通道,即多個(gè)網(wǎng)絡(luò)連接的IO
  • ? 復(fù)用,多個(gè)通道復(fù)用在一個(gè)復(fù)用器

多個(gè)網(wǎng)絡(luò)連接的IO可注冊(cè)到一個(gè)復(fù)用器(select),當(dāng)用戶進(jìn)程調(diào)用select,整個(gè)進(jìn)程會(huì)被阻塞。同時(shí),內(nèi)核會(huì)“監(jiān)視”所有select負(fù)責(zé)的socket,當(dāng)任一socket中的數(shù)據(jù)準(zhǔn)備好了,select就會(huì)返回。這個(gè)時(shí)候用戶進(jìn)程再調(diào)用read操作,將數(shù)據(jù)從內(nèi)核中拷貝到用戶進(jìn)程。

當(dāng)用戶進(jìn)程發(fā)起select調(diào)用,進(jìn)程會(huì)被阻塞,當(dāng)發(fā)現(xiàn)該select負(fù)責(zé)的socket有準(zhǔn)備好的數(shù)據(jù)時(shí)才返回,之后才發(fā)起一次read,整個(gè)流程比阻塞IO要復(fù)雜,似乎更浪費(fèi)性能。但最大優(yōu)勢(shì)在于,用戶可在一個(gè)線程內(nèi)同時(shí)處理多個(gè)socket的IO請(qǐng)求。用戶可注冊(cè)多個(gè)socket,然后不斷調(diào)用select讀取被激活的socket,即可達(dá)到在同一個(gè)線程內(nèi)同時(shí)處理多個(gè)IO請(qǐng)求的目的。而在同步阻塞模型中,必須通過多線程實(shí)現(xiàn)。

好比我們?nèi)ゲ蛷d吃飯,這次我們是幾個(gè)人一起去的,我們專門留了一個(gè)人在餐廳排號(hào)等位,其他人就去逛街了,等排號(hào)的朋友通知我們可以吃飯了,我們就直接去享用。

本質(zhì)上多路復(fù)用還是同步阻塞。

1.3 為何阻塞IO,IO多路復(fù)用最常用?

網(wǎng)絡(luò)IO的應(yīng)用上,需要的是系統(tǒng)內(nèi)核的支持及編程語言的支持。

大多系統(tǒng)內(nèi)核都支持阻塞IO、非阻塞IO和IO多路復(fù)用,但像信號(hào)驅(qū)動(dòng)IO、異步IO,只有高版本Linux系統(tǒng)內(nèi)核支持。

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

應(yīng)用最多的、系統(tǒng)內(nèi)核與編程語言支持最為完善的,便是阻塞IO和IO多路復(fù)用,滿足絕大多數(shù)網(wǎng)絡(luò)IO應(yīng)用場(chǎng)景。

1.4 RPC框架選擇哪種網(wǎng)絡(luò)IO模型?

IO多路復(fù)用適合高并發(fā),用較少進(jìn)程(線程)處理較多socket的IO請(qǐng)求,但使用難度較高。

阻塞IO每處理一個(gè)socket的IO請(qǐng)求都會(huì)阻塞進(jìn)程(線程),但使用難度較低。在并發(fā)量較低、業(yè)務(wù)邏輯只需要同步進(jìn)行IO操作的場(chǎng)景下,阻塞IO已滿足需求,并且不需要發(fā)起select調(diào)用,開銷比IO多路復(fù)用低。

RPC調(diào)用大多數(shù)是高并發(fā)調(diào)用,綜合考慮,RPC選擇IO多路復(fù)用。最優(yōu)框架選擇即基于Reactor模式實(shí)現(xiàn)的框架Netty。Linux下,也要開啟epoll提升系統(tǒng)性能。

2 零拷貝(Zero-copy)

2.1 網(wǎng)絡(luò)IO讀寫流程

圖片

應(yīng)用進(jìn)程的每次寫操作,都把數(shù)據(jù)寫到用戶空間的緩沖區(qū),CPU再將數(shù)據(jù)拷貝到系統(tǒng)內(nèi)核緩沖區(qū),再由DMA將這份數(shù)據(jù)拷貝到網(wǎng)卡,由網(wǎng)卡發(fā)出去。一次寫操作數(shù)據(jù)要拷貝兩次才能通過網(wǎng)卡發(fā)送出去,而用戶進(jìn)程讀操作則是反過來,數(shù)據(jù)同樣會(huì)拷貝兩次才能讓應(yīng)用程序讀到數(shù)據(jù)。

應(yīng)用進(jìn)程一次完整讀寫操作,都要在用戶空間與內(nèi)核空間中來回拷貝,每次拷貝,都要CPU進(jìn)行一次上下文切換(由用戶進(jìn)程切換到系統(tǒng)內(nèi)核,或由系統(tǒng)內(nèi)核切換到用戶進(jìn)程),這樣是不是很浪費(fèi)CPU和性能呢?那有沒有什么方式,可以減少進(jìn)程間的數(shù)據(jù)拷貝,提高數(shù)據(jù)傳輸?shù)男誓兀?/p>

這就要零拷貝:取消用戶空間與內(nèi)核空間之間的數(shù)據(jù)拷貝操作,應(yīng)用進(jìn)程每一次的讀寫操作,都讓應(yīng)用進(jìn)程向用戶空間寫入或讀取數(shù)據(jù),就如同直接向內(nèi)核空間寫或讀數(shù)據(jù)一樣,再通過DMA將內(nèi)核中的數(shù)據(jù)拷貝到網(wǎng)卡,或?qū)⒕W(wǎng)卡中的數(shù)據(jù)copy到內(nèi)核。

2.2 實(shí)現(xiàn)

是不是用戶空間與內(nèi)核空間都將數(shù)據(jù)寫到一個(gè)地方,就不需要拷貝了?想到虛擬內(nèi)存嗎?

圖片

虛擬內(nèi)存

零拷貝有兩種實(shí)現(xiàn):

mmap+write

通過虛擬內(nèi)存來解決。

sendfile

Nginx sendfile

3 Netty零拷貝

RPC框架在網(wǎng)絡(luò)通信框架的選型基于Reactor模式實(shí)現(xiàn)的框架,如Java首選Netty。那Netty有零拷貝機(jī)制嗎?Netty框架中的零拷貝和我之前講的零拷貝又有什么不同呢?

上節(jié)的零拷貝是os層的零拷貝,為避免用戶空間與內(nèi)核空間之間的數(shù)據(jù)拷貝操作,可提升CPU利用率。

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

Netty這么做的意義

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

那收到消息后,對(duì)數(shù)據(jù)包的分割和合并,是在用戶空間完成,還是在內(nèi)核空間完成的呢?

當(dāng)然是在用戶空間,因?yàn)閷?duì)數(shù)據(jù)包的處理工作都是由應(yīng)用程序來處理的,那么這里有沒有可能存在數(shù)據(jù)的拷貝操作?可能會(huì)存在,當(dāng)然不是在用戶空間與內(nèi)核空間之間的拷貝,是用戶空間內(nèi)部?jī)?nèi)存中的拷貝處理操作。Netty的零拷貝就是為了解決這個(gè)問題,在用戶空間對(duì)數(shù)據(jù)操作進(jìn)行優(yōu)化。

那么Netty是怎么對(duì)數(shù)據(jù)操作進(jìn)行優(yōu)化的呢?

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

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

Netty解決用戶空間與內(nèi)核空間之間的數(shù)據(jù)拷貝

Netty 的 ByteBuffer 采用 Direct Buffers,使用堆外直接內(nèi)存進(jìn)行Socket的讀寫操作,最終的效果與我剛才講解的虛擬內(nèi)存所實(shí)現(xiàn)的效果一樣。

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

4 總結(jié)

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

Netty零拷貝與os的零拷貝有別,Netty零拷貝偏向于用戶空間中對(duì)數(shù)據(jù)操作的優(yōu)化,這對(duì)處理TCP傳輸中的拆包粘包問題有重要意義,對(duì)應(yīng)用程序處理請(qǐng)求數(shù)據(jù)與返回?cái)?shù)據(jù)也有重要意義。

責(zé)任編輯:武曉燕 來源: JavaEdge
相關(guān)推薦

2021-09-02 07:04:38

JWT簽名算法

2023-03-17 11:33:18

數(shù)據(jù)中心

2022-02-21 10:21:17

網(wǎng)絡(luò)IO模型

2022-04-12 08:00:17

socket 編程網(wǎng)絡(luò)編程網(wǎng)絡(luò) IO 模型

2019-04-24 08:34:46

編程語言PythonJava

2020-05-12 11:06:47

服務(wù)器RAID陣列硬盤

2019-03-12 18:33:57

樹莓派Linux

2021-09-18 14:59:58

語言PythonC語言

2020-09-23 12:32:18

網(wǎng)絡(luò)IOMySQL

2016-10-28 16:18:25

數(shù)據(jù)中心制冷冷熱通道隔離

2015-07-16 11:14:32

云服務(wù)DRaaSAWS

2022-06-28 10:20:58

微服務(wù)架構(gòu)RPC

2016-08-04 15:10:12

服務(wù)器虛擬化網(wǎng)絡(luò)

2024-08-12 09:38:33

2017-07-07 16:36:28

BIOIO模型 NIO

2020-10-14 10:45:15

神經(jīng)網(wǎng)絡(luò)數(shù)據(jù)算法

2013-09-30 09:49:06

存儲(chǔ)網(wǎng)絡(luò)FCoE存儲(chǔ)

2016-11-04 12:51:46

Unix網(wǎng)絡(luò)IO 模型

2021-09-30 07:26:15

磁盤IO網(wǎng)絡(luò)

2023-05-10 08:26:33

IO模型API
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)