<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          美團(tuán)面試:說(shuō)說(shuō)Netty的零拷貝技術(shù)?

          共 6198字,需瀏覽 13分鐘

           ·

          2024-06-07 08:08

          面試題大全:www.javacn.site

          零拷貝技術(shù)(Zero-Copy)是一個(gè)大家耳熟能詳?shù)募夹g(shù)名詞了,它主要用于提升 IO(Input & Output)的傳輸性能。

          那么問(wèn)題來(lái)了,為什么零拷貝技術(shù)能提升 IO 性能?

          1.零拷貝技術(shù)和性能

          在傳統(tǒng)的 IO 操作中,當(dāng)我們需要讀取并傳輸數(shù)據(jù)時(shí),我們需要在用戶(hù)態(tài)(用戶(hù)空間)和內(nèi)核態(tài)(內(nèi)核空間)中進(jìn)行數(shù)據(jù)拷貝,它的執(zhí)行流程如下:從上述流程我們可以看出,在傳統(tǒng)的 IO 操作中,我們是需要 4 次拷貝和 4 次上下文切換(用戶(hù)態(tài)和內(nèi)核態(tài)的切換)的。

          而每次數(shù)據(jù)拷貝和上下文切換都有時(shí)間成本,會(huì)讓程序的執(zhí)行時(shí)間變成,所以零拷貝技術(shù)的出現(xiàn)就是為了減少數(shù)據(jù)的拷貝次數(shù)以及上下文的切換次數(shù)的。

          1.1 什么是用戶(hù)態(tài)和內(nèi)核態(tài)?

          操作系統(tǒng)有用戶(hù)態(tài)和內(nèi)核態(tài)之分,這是因?yàn)橛?jì)算機(jī)體系結(jié)構(gòu)中的操作系統(tǒng)設(shè)計(jì)了兩個(gè)不同的執(zhí)行環(huán)境,以提供不同的功能和特權(quán)級(jí)別。

          • 用戶(hù)態(tài)(User Mode)是指應(yīng)用程序運(yùn)行時(shí)的執(zhí)行環(huán)境。在用戶(hù)態(tài)下,應(yīng)用程序只能訪問(wèn)受限資源,如應(yīng)用程序自身的內(nèi)存空間、CPU 寄存器等,并且不能直接訪問(wèn)操作系統(tǒng)的底層資源和硬件設(shè)備。
          • 內(nèi)核態(tài)(Kernel Mode)是指操作系統(tǒng)內(nèi)核運(yùn)行時(shí)的執(zhí)行環(huán)境。在內(nèi)核態(tài)下,操作系統(tǒng)具有更高的權(quán)限,可以直接訪問(wèn)系統(tǒng)的硬件和底層資源,如 CPU、內(nèi)存、設(shè)備驅(qū)動(dòng)程序等。

          1.2 什么是DMA?

          DMA(Direct Memory Access,直接內(nèi)存訪問(wèn))技術(shù),繞過(guò) CPU,直接在內(nèi)存和外設(shè)之間進(jìn)行數(shù)據(jù)傳輸。這樣可以減少 CPU 的參與,提高數(shù)據(jù)傳輸?shù)男省?/p>

          2.Linux零拷貝技術(shù)

          Linux 下實(shí)現(xiàn)零拷貝的主要實(shí)現(xiàn)技術(shù)是 MMap、sendFile,它們的具體介紹如下。

          2.1 MMap

          MMap(Memory Map)是 Linux 操作系統(tǒng)中提供的一種將文件映射到進(jìn)程地址空間的一種機(jī)制,通過(guò) MMap 進(jìn)程可以像訪問(wèn)內(nèi)存一樣訪問(wèn)文件,而無(wú)需顯式的復(fù)制操作。

          使用 MMap 可以把 IO 執(zhí)行流程優(yōu)化成以下執(zhí)行步驟:傳統(tǒng)的 IO 需要四次拷貝和四次上下文(用戶(hù)態(tài)和內(nèi)核態(tài))切換,而 MMap 只需要三次拷貝和四次上下文切換,從而能夠提升程序整體的執(zhí)行效率,并且節(jié)省了程序的內(nèi)存空間。

          2.2 senFile 方法

          在 Linux 操作系統(tǒng)中 sendFile() 是一個(gè)系統(tǒng)調(diào)用函數(shù),用于高效地將文件數(shù)據(jù)從內(nèi)核空間直接傳輸?shù)骄W(wǎng)絡(luò)套接字(Socket)上,從而實(shí)現(xiàn)零拷貝技術(shù)。這個(gè)函數(shù)的主要目的是減少 CPU 上下文切換以及內(nèi)存復(fù)制操作,提高文件傳輸性能。

          使用 sendFile() 可以把 IO 執(zhí)行流程優(yōu)化成以下執(zhí)行步驟:

          3.Netty零拷貝技術(shù)

          Netty 中的零拷貝和傳統(tǒng) Linux 的零拷貝技術(shù)的實(shí)現(xiàn)不太一樣,Netty 中的零拷貝技術(shù)主要是通過(guò)優(yōu)化用戶(hù)態(tài)的操作來(lái)提升 IO 的執(zhí)行速度,從而實(shí)現(xiàn)零拷貝的。

          PS:所有可以提升 IO 執(zhí)行效率的操作或手段都可以稱(chēng)之為零拷貝技術(shù)。

          Netty 中的零拷貝技術(shù)主要有以下 5 種實(shí)現(xiàn):

          1. 使用堆外內(nèi)存:避免 JVM 堆內(nèi)存到堆外內(nèi)存的數(shù)據(jù)拷貝,從而提升了 IO 的操作性能。
          2. 使用 CompositeByteBuf 合并對(duì)象:可以組合多個(gè) Buffer 對(duì)象合并成一個(gè)邏輯上的對(duì)象,避免通過(guò)傳統(tǒng)內(nèi)存拷貝的方式將幾個(gè) Buffer 合并成一個(gè)大的 Buffer。
          3. 通過(guò) Unpooled.wrappedBuffer 合并數(shù)據(jù):可以將 byte 數(shù)組包裝成 ByteBuf 對(duì)象,包裝過(guò)程中不會(huì)產(chǎn)生內(nèi)存拷貝。
          4. 使用 ByteBuf.slice 共享對(duì)象:操作與 Unpooled.wrappedBuffer 相反,slice 操作可以將一個(gè) ByteBuf 對(duì)象切分成多個(gè) ByteBuf 對(duì)象,切分過(guò)程中不會(huì)產(chǎn)生內(nèi)存拷貝,底層共享一個(gè) byte 數(shù)組的存儲(chǔ)空間。
          5. 使用 FileRegion 實(shí)現(xiàn)零拷貝:FileRegion 底層封裝了 FileChannel#transferTo() 方法,可以將文件緩沖區(qū)的數(shù)據(jù)直接傳輸?shù)侥繕?biāo) Channel,避免內(nèi)核緩沖區(qū)和用戶(hù)態(tài)緩沖區(qū)之間的數(shù)據(jù)拷貝,這屬于操作系統(tǒng)級(jí)別的零拷貝。

          它們的具體實(shí)現(xiàn)如下。

          3.1 使用堆外內(nèi)存

          正常情況下,JVM 需要將數(shù)據(jù)從 JVM 堆內(nèi)存拷貝到堆外內(nèi)存進(jìn)行業(yè)務(wù)執(zhí)行的,這是因?yàn)椋?/p>

          1. 操作系統(tǒng)并不感知 JVM 的堆內(nèi)存,而且 JVM 的內(nèi)存布局與操作系統(tǒng)所分配的是不一樣的,操作系統(tǒng)并不會(huì)按照 JVM 的行為來(lái)讀寫(xiě)數(shù)據(jù)。
          2. 同一個(gè)對(duì)象的內(nèi)存地址隨著 JVM GC 的執(zhí)行可能會(huì)隨時(shí)發(fā)生變化,例如 JVM GC 的過(guò)程中會(huì)通過(guò)壓縮來(lái)減少內(nèi)存碎片,這就涉及對(duì)象移動(dòng)的問(wèn)題了。

          而 Netty 在進(jìn)行 I/O 操作時(shí)都是使用的堆外內(nèi)存,可以避免數(shù)據(jù)從 JVM 堆內(nèi)存到堆外內(nèi)存的拷貝。

          3.2 使用CompositeByteBuf合并對(duì)象

          CompositeByteBuf 可以理解為一個(gè)虛擬的 Buffer 對(duì)象,它是由多個(gè) ByteBuf 組合而成,但是在 CompositeByteBuf 內(nèi)部保存著每個(gè) ByteBuf 的引用關(guān)系,從邏輯上構(gòu)成一個(gè)整體。使用 CompositeByteBuf 我們可以合并兩個(gè) ByteBuf 對(duì)象,從而避免兩個(gè)對(duì)象合并時(shí)需要兩次 CPU 拷貝操作的問(wèn)題,在沒(méi)有使用 CompositeByteBuf 時(shí),我們的操作是這樣的:

          ByteBuf httpBuf = Unpooled.buffer(header.readableBytes() + body.readableBytes());
          httpBuf.writeBytes(header);
          httpBuf.writeBytes(body);

          而實(shí)現(xiàn) header 和 body 這兩個(gè) ByteBuf 的合并,需要先初始化一個(gè)新的 httpBuf,然后再將 header 和 body 分別拷貝到新的 httpBuf。合并過(guò)程中涉及兩次 CPU 拷貝,這非常浪費(fèi)性能,所以我們就可以使用 CompositeByteBuf 了,它的使用如下:

          CompositeByteBuf httpBuf = Unpooled.compositeBuffer();
          httpBuf.addComponents(true, header, body);

          CompositeByteBuf 通過(guò)調(diào)用 addComponents() 方法來(lái)添加多個(gè) ByteBuf,但是底層的 byte 數(shù)組是復(fù)用的,不會(huì)發(fā)生內(nèi)存拷貝。

          3.3 通過(guò)Unpooled.wrappedBuffer合并數(shù)據(jù)

          Unpooled.wrappedBuffer 的操作類(lèi)似,使用它可以將不同的數(shù)據(jù)源的一個(gè)或者多個(gè)數(shù)據(jù)包裝成一個(gè)大的 ByteBuf 對(duì)象,其中數(shù)據(jù)源的類(lèi)型包括 byte[]、ByteBuf、ByteBuffer。包裝的過(guò)程中不會(huì)發(fā)生數(shù)據(jù)拷貝操作,包裝后生成的 ByteBuf 對(duì)象和原始 ByteBuf 對(duì)象是共享底層的 byte 數(shù)組。

          3.4 使用 ByteBuf.slice 共享對(duì)象

          ByteBuf.slice 和 Unpooled.wrappedBuffer 的邏輯正好相反,ByteBuf.slice 是將一個(gè) ByteBuf 對(duì)象切分成多個(gè)共享同一個(gè)底層存儲(chǔ)的 ByteBuf 對(duì)象,從而避免對(duì)象分割時(shí)的數(shù)據(jù)拷貝,它的使用如下:

          ByteBuf httpBuf = ...
          ByteBuf header = httpBuf.slice(06);
          ByteBuf body = httpBuf.slice(64);

          3.5 使用 FileRegion 實(shí)現(xiàn)文件零拷貝

          FileRegion 底層封裝了 FileChannel#transferTo() 方法,可以將文件緩沖區(qū)的數(shù)據(jù)直接傳輸?shù)侥繕?biāo) Channel,避免內(nèi)核緩沖區(qū)和用戶(hù)態(tài)緩沖區(qū)之間的數(shù)據(jù)拷貝,這屬于操作系統(tǒng)級(jí)別的零拷貝。

          以下是 FileRegion 的默認(rèn)實(shí)現(xiàn)類(lèi) DefaultFileRegion 的使用案例:

          @Override
          public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
              RandomAccessFile raf = null;
              long length = -1;
              try {
                  raf = new RandomAccessFile(msg, "r");
                  length = raf.length();
              } catch (Exception e) {
                  ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n');
                  return;
              } finally {
                  if (length < 0 && raf != null) {
                      raf.close();
                  }
              }
              ctx.write("OK: " + raf.length() + '\n');
              if (ctx.pipeline().get(SslHandler.class== null) {
                  // SSL not enabled - can use zero-copy file transfer.
                  ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));
              } else {
                  // SSL enabled - cannot use zero-copy file transfer.
                  ctx.write(new ChunkedFile(raf));
              }
              ctx.writeAndFlush("\n");
          }

          從上述代碼可以看出,可以通過(guò) DefaultFileRegion 將文件內(nèi)容直接寫(xiě)入到 NioSocketChannel 中,從而避免了內(nèi)核緩沖區(qū)和用戶(hù)態(tài)緩沖區(qū)之間的數(shù)據(jù)拷貝。

          課后思考

          那么問(wèn)題來(lái)了,F(xiàn)ileRegion 是如何實(shí)現(xiàn)零拷貝的呢?

          特殊說(shuō)明

          以上內(nèi)容來(lái)自我的《Java 面試突擊訓(xùn)練營(yíng)》,這門(mén)課程是有著 14 年工作經(jīng)驗(yàn)(前 360 開(kāi)發(fā)工程師),9 年面試官經(jīng)驗(yàn)的我,花費(fèi) 4 年時(shí)間打磨完成的一門(mén)視頻面試課。

          整個(gè)課程從 Java 基礎(chǔ)到微服務(wù) Spring Cloud、從實(shí)際開(kāi)發(fā)問(wèn)題到場(chǎng)景題應(yīng)有盡有,包含模塊如下:訓(xùn)練營(yíng)系統(tǒng)的帶領(lǐng)大家把 Java 常見(jiàn)的面試題過(guò)一遍,遇到一個(gè)問(wèn)題,把這個(gè)問(wèn)題相關(guān)的內(nèi)容都給大家講明白,并且視頻支持永久觀看和一直更新。并且面試訓(xùn)練營(yíng)還提供 9 大就業(yè)服務(wù)。

          上完訓(xùn)練營(yíng)的課程之后,基本可以應(yīng)對(duì)目前市面上絕大部分公司的面試了,幫你快速找到高薪工作,加我微信咨詢(xún):GG_Stone【備注:訓(xùn)練營(yíng)】


          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久系列 | 蜜臀久久精品久久久久 | 欧美91在线 | 久久久77777 | 偷拍区图片1区 |