精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java I/O體系從原理到應用,這一篇說清楚了

運維 系統運維 前端
本文介紹操作系統I/O工作原理,Java I/O設計,基本使用,開源項目中實現高性能I/O常見方法和實現,徹底搞懂高性能I/O之道。

本文介紹操作系統I/O工作原理,Java I/O設計,基本使用,開源項目中實現高性能I/O常見方法和實現,徹底搞懂高性能I/O之道。

[[283378]]

一、基礎概念

在介紹I/O原理之前,先重溫幾個基礎概念:

1. 操作系統與內核

操作系統:管理計算機硬件與軟件資源的系統軟件

內核:操作系統的核心軟件,負責管理系統的進程、內存、設備驅動程序、文件和網絡系統等等,為應用程序提供對計算機硬件的安全訪問服務

2. 內核空間和用戶空間

為了避免用戶進程直接操作內核,保證內核安全,操作系統將內存尋址空間劃分為兩部分:內核空間(Kernel-space),供內核程序使用用戶空間(User-space),供用戶進程使用 為了安全,內核空間和用戶空間是隔離的,即使用戶的程序崩潰了,內核也不受影響。

3. 數據流

計算機中的數據是基于隨著時間變換高低電壓信號傳輸的,這些數據信號連續不斷,有著固定的傳輸方向,類似水管中水的流動,因此抽象數據流(I/O流)的概念:指一組有順序的、有起點和終點的字節集合,抽象出數據流的作用:實現程序邏輯與底層硬件解耦,通過引入數據流作為程序與硬件設備之間的抽象層,面向通用的數據流輸入輸出接口編程,而不是具體硬件特性,程序和底層硬件可以獨立靈活替換和擴展。

二、I/O 工作原理

1. 磁盤I/O

典型I/O讀寫磁盤工作原理如下:

tips: DMA:全稱叫直接內存存取(Direct Memory Access),是一種允許外圍設備(硬件子系統)直接訪問系統主內存的機制。基于 DMA 訪問方式,系統主內存與硬件設備的數據傳輸可以省去CPU 的全程調度。

值得注意的是:

  • 讀寫操作基于系統調用實現
  • 讀寫操作經過用戶緩沖區,內核緩沖區,應用進程并不能直接操作磁盤
  • 應用進程讀操作時需阻塞直到讀取到數據

2. 網絡I/O

這里先以最經典的阻塞式I/O模型介紹:

tips:recvfrom,經socket接收數據的函數

值得注意的是:

  • 網絡I/O讀寫操作經過用戶緩沖區,Sokcet緩沖區
  • 服務端線程在從調用recvfrom開始到它返回有數據報準備好這段時間是阻塞的,recvfrom返回成功后,線程開始處理數據報

三、Java I/O設計

1. I/O分類

Java中對數據流進行具體化和實現,關于Java數據流一般關注以下幾個點:

  • 流的方向從外部到程序,稱為輸入流;從程序到外部,稱為輸出流
  • 流的數據單位程序以字節作為最小讀寫數據單元,稱為字節流,以字符作為最小讀寫數據單元,稱為字符流
  • 流的功能角色

從/向一個特定的IO設備(如磁盤,網絡)或者存儲對象(如內存數組)讀/寫數據的流,稱為節點流;

對一個已有流進行連接和封裝,通過封裝后的流來實現數據的讀/寫功能,稱為處理流(或稱為過濾流)。

2. I/O操作接口

java.io包下有一堆I/O操作類,初學時看了容易搞不懂,其實仔細觀察其中還是有規律:這些I/O操作類都是在繼承4個基本抽象流的基礎上,要么是節點流,要么是處理流。

(1) 四個基本抽象流

java.io包中包含了流式I/O所需要的所有類,java.io包中有四個基本抽象流,分別處理字節流和字符流:

  • InputStream
  • OutputStream
  • Reader
  • Writer

(2) 節點流

節點流I/O類名由節點流類型 + 抽象流類型組成,常見節點類型有:

  • File文件
  • Piped 進程內線程通信管道
  • ByteArray / CharArray (字節數組 / 字符數組)
  • StringBuffer / String (字符串緩沖區 / 字符串)

節點流的創建通常是在構造函數傳入數據源,例如:

  1. FileReader reader = new FileReader(new File("file.txt")); 
  2. FileWriter writer = new FileWriter(new File("file.txt")); 

(3) 處理流

處理流I/O類名由對已有流封裝的功能 + 抽象流類型組成,常見功能有:

  • 緩沖:對節點流讀寫的數據提供了緩沖的功能,數據可以基于緩沖批量讀寫,提高效率。常見有BufferedInputStream、BufferedOutputStream
  • 字節流轉換為字符流:由InputStreamReader、OutputStreamWriter實現
  • 字節流與基本類型數據相互轉換:這里基本數據類型數據如int、long、short,由DataInputStream、DataOutputStream實現
  • 字節流與對象實例相互轉換:用于實現對象序列化,由ObjectInputStream、ObjectOutputStream實現

處理流的應用了適配器/裝飾模式,轉換/擴展已有流,處理流的創建通常是在構造函數傳入已有的節點流或處理流:

  1. FileOutputStream fileOutputStream = new FileOutputStream("file.txt"); 
  2. // 擴展提供緩沖寫 
  3. BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); 
  4.  // 擴展提供提供基本數據類型寫 
  5. DataOutputStream out = new DataOutputStream(bufferedOutputStream); 

3. Java NIO

(1) 標準I/O存在問題

Java NIO(New I/O)是一個可以替代標準Java I/O API的IO API(從Java 1.4開始),Java NIO提供了與標準I/O不同的I/O工作方式,目的是為了解決標準 I/O存在的以下問題:

A.  數據多次拷貝

標準I/O處理,完成一次完整的數據讀寫,至少需要從底層硬件讀到內核空間,再讀到用戶文件,又從用戶空間寫入內核空間,再寫入底層硬件。

此外,底層通過write、read等函數進行I/O系統調用時,需要傳入數據所在緩沖區起始地址和長度由于JVM GC的存在,導致對象在堆中的位置往往會發生移動,移動后傳入系統函數的地址參數就不是真正的緩沖區地址了。

可能導致讀寫出錯,為了解決上面的問題,使用標準I/O進行系統調用時,還會額外導致一次數據拷貝:把數據從JVM的堆內拷貝到堆外的連續空間內存(堆外內存)。

所以總共經歷6次數據拷貝,執行效率較低。

B. 操作阻塞

傳統的網絡I/O處理中,由于請求建立連接(connect),讀取網絡I/O數據(read),發送數據(send)等操作是線程阻塞的。

  1. // 等待連接 
  2. Socket socket = serverSocket.accept(); 
  3.  
  4. // 連接已建立,讀取請求消息 
  5. StringBuilder req = new StringBuilder(); 
  6. byte[] recvByteBuf = new byte[1024]; 
  7. int len; 
  8. while ((len = socket.getInputStream().read(recvByteBuf)) != -1) { 
  9.     req.append(new String(recvByteBuf, 0, len, StandardCharsets.UTF_8)); 
  10.  
  11. // 寫入返回消息 
  12. socket.getOutputStream().write(("server response msg".getBytes())); 
  13. socket.shutdownOutput(); 

以上面服務端程序為例,當請求連接已建立,讀取請求消息,服務端調用read方法時,客戶端數據可能還沒就緒(例如客戶端數據還在寫入中或者傳輸中),線程需要在read方法阻塞等待直到數據就緒。

為了實現服務端并發響應,每個連接需要獨立的線程單獨處理,當并發請求量大時為了維護連接,內存、線程切換開銷過大。

(2) Buffer

Java NIO核心三大核心組件是Buffer(緩沖區)、Channel(通道)、Selector。

Buffer提供了常用于I/O操作的字節緩沖區,常見的緩存區有ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分別對應基本數據類型: byte, char, double, float, int, long, short,下面介紹主要以最常用的ByteBuffer為例,Buffer底層支持Java堆外內存和堆內內存。

堆外內存是指與堆內存相對應的,把內存對象分配在JVM堆以外的內存,這些內存直接受操作系統管理(而不是虛擬機,相比堆內內存,I/O操作中使用堆外內存的優勢在于:

  • 不用被JVM GC線回收,減少GC線程資源占有
  • 在I/O系統調用時,直接操作堆外內存,可以節省一次堆外內存和堆內內存的復制

ByteBuffer底層基于堆外內存的分配和釋放基于malloc和free函數,對外allocateDirect方法可以申請分配堆外內存,并返回繼承ByteBuffer類的DirectByteBuffer對象:

  1. public static ByteBuffer allocateDirect(int capacity) { 
  2.     return new DirectByteBuffer(capacity); 

堆外內存的回收基于DirectByteBuffer的成員變量Cleaner類,提供clean方法可以用于主動回收,Netty中大部分堆外內存通過記錄定位Cleaner的存在,主動調用clean方法來回收;另外,當DirectByteBuffer對象被GC時,關聯的堆外內存也會被回收。

tips:JVM參數不建議設置-XX:+DisableExplicitGC,因為部分依賴Java NIO的框架(例如Netty)在內存異常耗盡時,會主動調用System.gc(),觸發Full GC,回收DirectByteBuffer對象,作為回收堆外內存的最后保障機制,設置該參數之后會導致在該情況下堆外內存得不到清理。

堆外內存基于基礎ByteBuffer類的DirectByteBuffer類成員變量:Cleaner對象,這個Cleaner對象會在合適的時候執行unsafe.freeMemory(address),從而回收這塊堆外內存。

Buffer可以見到理解為一組基本數據類型,存儲地址連續的的數組,支持讀寫操作,對應讀模式和寫模式,通過幾個變量來保存這個數據的當前位置狀態:capacity、 position、 limit:

  • capacity 緩沖區數組的總長度
  • position 下一個要操作的數據元素的位置
  • limit 緩沖區數組中不可操作的下一個元素的位置:limit <= capacity

(3) Channel

Channel(通道)的概念可以類比I/O流對象,NIO中I/O操作主要基于Channel:從Channel進行數據讀取 :創建一個緩沖區,然后請求Channel讀取數據 從Channel進行數據寫入 :創建一個緩沖區,填充數據,請求Channel寫入數據。

Channel和流非常相似,主要有以下幾點區別:

  • Channel可以讀和寫,而標準I/O流是單向的
  • Channel可以異步讀寫,標準I/O流需要線程阻塞等待直到讀寫操作完成
  • Channel總是基于緩沖區Buffer讀寫

Java NIO中最重要的幾個Channel的實現:

  • FileChannel:用于文件的數據讀寫,基于FileChannel提供的方法能減少讀寫文件數據拷貝次數,后面會介紹
  • DatagramChannel:用于UDP的數據讀寫
  • SocketChannel:用于TCP的數據讀寫,代表客戶端連接
  • ServerSocketChannel:監聽TCP連接請求,每個請求會創建會一個SocketChannel,一般用于服務端

基于標準I/O中,我們第一步可能要像下面這樣獲取輸入流,按字節把磁盤上的數據讀取到程序中,再進行下一步操作,而在NIO編程中,需要先獲取Channel,再進行讀寫。

  1. FileInputStream fileInputStream = new FileInputStream("test.txt"); 
  2. FileChannel channel = fileInputStream.channel(); 

tips: FileChannel僅能運行在阻塞模式下,文件異步處理的 I/O 是在JDK 1.7 才被加入的 java.nio.channels.AsynchronousFileChannel。

  1. // server socket channel: 
  2. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 
  3. serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9091)); 
  4.  
  5. while (true) { 
  6.     SocketChannel socketChannel = serverSocketChannel.accept(); 
  7.     ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 
  8.     int readBytes = socketChannel.read(buffer); 
  9.     if (readBytes > 0) { 
  10.         // 從寫數據到buffer翻轉為從buffer讀數據 
  11.         buffer.flip(); 
  12.         byte[] bytes = new byte[buffer.remaining()]; 
  13.         buffer.get(bytes); 
  14.         String body = new String(bytes, StandardCharsets.UTF_8); 
  15.         System.out.println("server 收到:" + body); 
  16.     } 

(4) Selector

Selector(選擇器) ,它是Java NIO核心組件中的一個,用于檢查一個或多個NIO Channel(通道)的狀態是否處于可讀、可寫。實現單線程管理多個Channel,也就是可以管理多個網絡連接。

Selector核心在于基于操作系統提供的I/O復用功能,單個線程可以同時監視多個連接描述符,一旦某個連接就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作,常見有select、poll、epoll等不同實現。

Java NIO Selector基本工作原理如下:

  • 初始化Selector對象,服務端ServerSocketChannel對象
  • 向Selector注冊ServerSocketChannel的socket-accept事件
  • 線程阻塞于selector.select(),當有客戶端請求服務端,線程退出阻塞
  • 基于selector獲取所有就緒事件,此時先獲取到socket-accept事件,向Selector注冊客戶端SocketChannel的數據就緒可讀事件事件
  • 線程再次阻塞于selector.select(),當有客戶端連接數據就緒,可讀
  • 基于ByteBuffer讀取客戶端請求數據,然后寫入響應數據,關閉channel

示例如下,完整可運行代碼已經上傳github(https://github.com/caison/caison-blog-demo):

  1. Selector selector = Selector.open(); 
  2. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 
  3. serverSocketChannel.bind(new InetSocketAddress(9091)); 
  4. // 配置通道為非阻塞模式 
  5. serverSocketChannel.configureBlocking(false); 
  6. // 注冊服務端的socket-accept事件 
  7. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 
  8.  
  9. while (true) { 
  10.     // selector.select()會一直阻塞,直到有channel相關操作就緒 
  11.     selector.select(); 
  12.     // SelectionKey關聯的channel都有就緒事件 
  13.     Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); 
  14.  
  15.     while (keyIterator.hasNext()) { 
  16.         SelectionKey key = keyIterator.next(); 
  17.         // 服務端socket-accept 
  18.         if (key.isAcceptable()) { 
  19.             // 獲取客戶端連接的channel 
  20.             SocketChannel clientSocketChannel = serverSocketChannel.accept(); 
  21.             // 設置為非阻塞模式 
  22.             clientSocketChannel.configureBlocking(false); 
  23.             // 注冊監聽該客戶端channel可讀事件,并為channel關聯新分配的buffer 
  24.             clientSocketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocateDirect(1024)); 
  25.         } 
  26.  
  27.         // channel可讀 
  28.         if (key.isReadable()) { 
  29.             SocketChannel socketChannel = (SocketChannel) key.channel(); 
  30.             ByteBuffer buf = (ByteBuffer) key.attachment(); 
  31.  
  32.             int bytesRead; 
  33.             StringBuilder reqMsg = new StringBuilder(); 
  34.             while ((bytesRead = socketChannel.read(buf)) > 0) { 
  35.                 // 從buf寫模式切換為讀模式 
  36.                 buf.flip(); 
  37.                 int bufbufRemain = buf.remaining(); 
  38.                 byte[] bytes = new byte[bufRemain]; 
  39.                 buf.get(bytes, 0, bytesRead); 
  40.                 // 這里當數據包大于byteBuffer長度,有可能有粘包/拆包問題 
  41.                 reqMsg.append(new String(bytes, StandardCharsets.UTF_8)); 
  42.                 buf.clear(); 
  43.             } 
  44.             System.out.println("服務端收到報文:" + reqMsg.toString()); 
  45.             if (bytesRead == -1) { 
  46.                 byte[] bytes = "[這是服務回的報文的報文]".getBytes(StandardCharsets.UTF_8); 
  47.  
  48.                 int length; 
  49.                 for (int offset = 0; offset < bytes.length; offset += length) { 
  50.                     length = Math.min(buf.capacity(), bytes.length - offset); 
  51.                     buf.clear(); 
  52.                     buf.put(bytes, offset, length); 
  53.                     buf.flip(); 
  54.                     socketChannel.write(buf); 
  55.                 } 
  56.                 socketChannel.close(); 
  57.             } 
  58.         } 
  59.         // Selector不會自己從已selectedKeys中移除SelectionKey實例 
  60.         // 必須在處理完通道時自己移除 下次該channel變成就緒時,Selector會再次將其放入selectedKeys中 
  61.         keyIterator.remove(); 
  62.     } 

tips: Java NIO基于Selector實現高性能網絡I/O這塊使用起來比較繁瑣,使用不友好,一般業界使用基于Java NIO進行封裝優化,擴展豐富功能的Netty框架來優雅實現。

四、高性能I/O優化

下面結合業界熱門開源項目介紹高性能I/O的優化。

1. 零拷貝

零拷貝(zero copy)技術,用于在數據讀寫中減少甚至完全避免不必要的CPU拷貝,減少內存帶寬的占用,提高執行效率,零拷貝有幾種不同的實現原理,下面介紹常見開源項目中零拷貝實現。

(1) Kafka零拷貝

Kafka基于Linux 2.1內核提供,并在2.4 內核改進的的sendfile函數 + 硬件提供的DMA Gather Copy實現零拷貝,將文件通過socket傳送。

函數通過一次系統調用完成了文件的傳送,減少了原來read/write方式的模式切換。同時減少了數據的copy, sendfile的詳細過程如下:

基本流程如下:

  • 用戶進程發起sendfile系統調用
  • 內核基于DMA Copy將文件數據從磁盤拷貝到內核緩沖區
  • 內核將內核緩沖區中的文件描述信息(文件描述符,數據長度)拷貝到Socket緩沖區
  • 內核基于Socket緩沖區中的文件描述信息和DMA硬件提供的Gather Copy功能將內核緩沖區數據復制到網卡
  • 用戶進程sendfile系統調用完成并返回

相比傳統的I/O方式,sendfile + DMA Gather Copy方式實現的零拷貝,數據拷貝次數從4次降為2次,系統調用從2次降為1次,用戶進程上下文切換次數從4次變成2次DMA Copy,大大提高處理效率。

Kafka底層基于java.nio包下的FileChannel的transferTo:

  1. public abstract long transferTo(long position, long count, WritableByteChannel target) 

transferTo將FileChannel關聯的文件發送到指定channel,當Comsumer消費數據,Kafka Server基于FileChannel將文件中的消息數據發送到SocketChannel。

A. RocketMQ零拷貝

RocketMQ基于mmap + write的方式實現零拷貝:mmap() 可以將內核中緩沖區的地址與用戶空間的緩沖區進行映射,實現數據共享,省去了將數據從內核緩沖區拷貝到用戶緩沖區。

  1. tmp_buf = mmap(file, len); 
  2. write(socket, tmp_buf, len); 

mmap + write 實現零拷貝的基本流程如下:

  • 用戶進程向內核發起系統mmap調用
  • 將用戶進程的內核空間的讀緩沖區與用戶空間的緩存區進行內存地址映射
  • 內核基于DMA Copy將文件數據從磁盤復制到內核緩沖區
  • 用戶進程mmap系統調用完成并返回
  • 用戶進程向內核發起write系統調用
  • 內核基于CPU Copy將數據從內核緩沖區拷貝到Socket緩沖區
  • 內核基于DMA Copy將數據從Socket緩沖區拷貝到網卡
  • 用戶進程write系統調用完成并返回

RocketMQ中消息基于mmap實現存儲和加載的邏輯寫在org.apache.rocketmq.store.MappedFile中,內部實現基于nio提供的java.nio.MappedByteBuffer,基于FileChannel的map方法得到mmap的緩沖區:

  1. // 初始化 
  2. this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel(); 
  3. thisthis.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize); 

查詢CommitLog的消息時,基于mappedByteBuffer偏移量pos,數據大小size查詢:

  1. public SelectMappedBufferResult selectMappedBuffer(int pos, int size) { 
  2.     int readPosition = getReadPosition(); 
  3.     // ...各種安全校驗 
  4.      
  5.     // 返回mappedByteBuffer視圖 
  6.     ByteBuffer byteBuffer = this.mappedByteBuffer.slice(); 
  7.     byteBuffer.position(pos); 
  8.     ByteBuffer byteBufferbyteBufferNew = byteBuffer.slice(); 
  9.     byteBufferNew.limit(size); 
  10.     return new SelectMappedBufferResult(this.fileFromOffset + pos, byteBufferNew, size, this); 

tips: transientStorePoolEnable機制Java NIO mmap的部分內存并不是常駐內存,可以被置換到交換內存(虛擬內存),RocketMQ為了提高消息發送的性能,引入了內存鎖定機制,即將最近需要操作的CommitLog文件映射到內存,并提供內存鎖定功能,確保這些文件始終存在內存中,該機制的控制參數就是transientStorePoolEnable。

因此,MappedFile數據保存CommitLog刷盤有2種方式:

  • 開啟transientStorePoolEnable:寫入內存字節緩沖區(writeBuffer) -> 從內存字節緩沖區(writeBuffer)提交(commit)到文件通道(fileChannel) -> 文件通道(fileChannel) -> flush到磁盤
  • 未開啟transientStorePoolEnable:寫入映射文件字節緩沖區(mappedByteBuffer) -> 映射文件字節緩沖區(mappedByteBuffer) -> flush到磁盤

RocketMQ 基于 mmap+write 實現零拷貝,適用于業務級消息這種小塊文件的數據持久化和傳輸 Kafka 基于 sendfile 這種零拷貝方式,適用于系統日志消息這種高吞吐量的大塊文件的數據持久化和傳輸。

tips: Kafka 的索引文件使用的是 mmap+write 方式,數據文件發送網絡使用的是 sendfile 方式。

B. Netty零拷貝

Netty 的零拷貝分為兩種:

  • 基于操作系統實現的零拷貝,底層基于FileChannel的transferTo方法
  • 基于Java 層操作優化,對數組緩存對象(ByteBuf )進行封裝優化,通過對ByteBuf數據建立數據視圖,支持ByteBuf 對象合并,切分,當底層僅保留一份數據存儲,減少不必要拷貝

2. 多路復用

Netty中對Java NIO功能封裝優化之后,實現I/O多路復用代碼優雅了很多:

  1. // 創建mainReactor 
  2. NioEventLoopGroup boosGroup = new NioEventLoopGroup(); 
  3. // 創建工作線程組 
  4. NioEventLoopGroup workerGroup = new NioEventLoopGroup(); 
  5.  
  6. final ServerBootstrap serverBootstrap = new ServerBootstrap(); 
  7. serverBootstrap 
  8.      // 組裝NioEventLoopGroup 
  9.     .group(boosGroup, workerGroup) 
  10.      // 設置channel類型為NIO類型 
  11.     .channel(NioServerSocketChannel.class) 
  12.     // 設置連接配置參數 
  13.     .option(ChannelOption.SO_BACKLOG, 1024) 
  14.     .childOption(ChannelOption.SO_KEEPALIVE, true) 
  15.     .childOption(ChannelOption.TCP_NODELAY, true) 
  16.     // 配置入站、出站事件handler 
  17.     .childHandler(new ChannelInitializer<NioSocketChannel>() { 
  18.         @Override 
  19.         protected void initChannel(NioSocketChannel ch) { 
  20.             // 配置入站、出站事件channel 
  21.             ch.pipeline().addLast(...); 
  22.             ch.pipeline().addLast(...); 
  23.         } 
  24.     }); 
  25.  
  26. // 綁定端口 
  27. int port = 8080
  28. serverBootstrap.bind(port).addListener(future -> { 
  29.     if (future.isSuccess()) { 
  30.         System.out.println(new Date() + ": 端口[" + port + "]綁定成功!"); 
  31.     } else { 
  32.         System.err.println("端口[" + port + "]綁定失敗!"); 
  33.     } 
  34. }); 

3. 頁緩存(PageCache)

頁緩存(PageCache)是操作系統對文件的緩存,用來減少對磁盤的 I/O 操作,以頁為單位的,內容就是磁盤上的物理塊,頁緩存能幫助程序對文件進行順序讀寫的速度幾乎接近于內存的讀寫速度,主要原因就是由于OS使用PageCache機制對讀寫訪問操作進行了性能優化:

頁緩存讀取策略:當進程發起一個讀操作 (比如,進程發起一個 read() 系統調用),它首先會檢查需要的數據是否在頁緩存中:

  • 如果在,則放棄訪問磁盤,而直接從頁緩存中讀取
  • 如果不在,則內核調度塊 I/O 操作從磁盤去讀取數據,并讀入緊隨其后的少數幾個頁面(不少于一個頁面,通常是三個頁面),然后將數據放入頁緩存中

頁緩存寫策略:當進程發起write系統調用寫數據到文件中,先寫到頁緩存,然后方法返回。此時數據還沒有真正的保存到文件中去,Linux 僅僅將頁緩存中的這一頁數據標記為“臟”,并且被加入到臟頁鏈表中。

然后,由flusher 回寫線程周期性將臟頁鏈表中的頁寫到磁盤,讓磁盤中的數據和內存中保持一致,最后清理“臟”標識。在以下三種情況下,臟頁會被寫回磁盤:

  • 空閑內存低于一個特定閾值
  • 臟頁在內存中駐留超過一個特定的閾值時
  • 當用戶進程調用 sync() 和 fsync() 系統調用時

RocketMQ中,ConsumeQueue邏輯消費隊列存儲的數據較少,并且是順序讀取,在page cache機制的預讀取作用下,Consume Queue文件的讀性能幾乎接近讀內存,即使在有消息堆積情況下也不會影響性能,提供了2種消息刷盤策略:

  • 同步刷盤:在消息真正持久化至磁盤后RocketMQ的Broker端才會真正返回給Producer端一個成功的ACK響應
  • 異步刷盤,能充分利用操作系統的PageCache的優勢,只要消息寫入PageCache即可將成功的ACK返回給Producer端。消息刷盤采用后臺異步線程提交的方式進行,降低了讀寫延遲,提高了MQ的性能和吞吐量

Kafka實現消息高性能讀寫也利用了頁緩存,這里不再展開。

 

責任編輯:趙寧寧 來源: 分布式系統架構
相關推薦

2022-07-21 21:19:48

元宇宙

2019-12-06 09:16:23

Linux 開源操作系統

2020-04-15 16:34:48

大數據質量標準

2020-03-02 15:17:37

云原生CNCF容器

2019-07-04 09:13:04

中臺百度團隊

2021-02-25 08:21:38

高可用風險故障

2019-02-21 16:24:28

5G火車站設備

2020-10-29 10:35:53

Nginx架構服務器

2018-07-26 09:06:29

Java內存模型

2019-10-21 08:51:41

分布式事務CAPAP

2019-09-26 09:24:01

GC原理調優

2017-12-17 20:17:23

NoSQLSQL數據

2022-11-11 15:49:41

MySQL隔離

2020-01-13 15:34:10

超融合邊緣計算架構

2018-08-13 09:20:21

NoSQLSQL數據

2024-09-23 05:10:00

微服務CORSSpringBoot

2021-02-11 08:08:09

Spring Boot配置架構

2018-11-28 11:08:30

并查集集合數據結構

2019-12-23 14:53:26

IO復用

2025-05-28 02:00:00

AI智能體文本
點贊
收藏

51CTO技術棧公眾號

美女爆乳18禁www久久久久久| 强开小嫩苞一区二区三区网站 | 无吗不卡中文字幕| 欧美激情第六页| 国产精品日韩无码| 亚洲一区网站| 日韩一区二区久久久| 亚洲中文字幕无码一区| 欧美性suv| 亚洲日本丝袜连裤袜办公室| 久久国产精品久久| 91国在线视频| 久久精品五月| 欧美精品videofree1080p| 99久久精品免费视频| 三级欧美日韩| 欧美日韩情趣电影| 国精产品一区一区三区视频| av资源在线观看免费高清| 粉嫩aⅴ一区二区三区四区五区| 国产精品91久久久| 黄色小视频在线免费看| 青青草91久久久久久久久| 亚洲成色777777在线观看影院| 97超碰成人在线| 三级中文字幕在线观看| 亚洲在线免费播放| 欧美aaa在线观看| 国产在线91| 成人av中文字幕| 亚洲精品欧美一区二区三区| 久久久久亚洲视频| 99精品热视频只有精品10| 欧美另类老女人| 乱老熟女一区二区三区| 精品av一区二区| 精品小视频在线| 日韩精品人妻中文字幕有码 | 精品免费国产| 亚洲福利在线观看视频| 国产真实乱对白精彩久久| 国产精品成人一区二区三区吃奶| 国产情侣在线视频| 亚洲天堂偷拍| 久久久久亚洲精品国产| 91精品一区二区三区蜜桃| 日韩在线第七页| 综合久久五月天| 黄大色黄女片18免费| 国产欧美一区二区三区精品观看 | 亚洲精品乱码久久| 爱爱精品视频| 亚洲精品456在线播放狼人| 在线看黄色的网站| 成人线上播放| 亚洲国产古装精品网站| 亚洲精品女人久久久| 亚洲福利网站| 亚洲香蕉成视频在线观看| 在线观看日本中文字幕| 欧美一区2区| zzijzzij亚洲日本成熟少妇| 国内毛片毛片毛片毛片毛片| 图片小说视频色综合| 久久国产加勒比精品无码| 久艹在线观看视频| 欧美精品自拍| 97成人精品视频在线观看| 久久黄色精品视频| 日韩av高清在线观看| 成人激情视频网| 国产丰满美女做爰| 成人av网站在线| 欧美成人免费在线| 91网页在线观看| 亚洲精品少妇30p| 18禁免费观看网站| 蜜桃视频成人m3u8| 678五月天丁香亚洲综合网| 涩视频在线观看| 香蕉视频一区| 精品国偷自产在线| 久久亚洲精品大全| 久久久青草婷婷精品综合日韩| 国产成人精品视频在线| 国产精品无码白浆高潮| 成人av影院在线| 亚洲高清视频在线观看| 欧美极品少妇videossex| 天天av天天翘天天综合网| 美女一区二区三区视频| 日本成人手机在线| 亚洲免费电影在线观看| 黑人狂躁日本娇小| 一区二区三区四区五区在线| 国产精品久久一区| 亚洲伦理在线观看| 国产欧美精品在线观看| 四虎精品欧美一区二区免费| 免费看男女www网站入口在线 | 欧美日韩激情在线一区二区三区| 久久综合国产精品台湾中文娱乐网| 日韩大片免费在线观看| 蜜桃视频在线观看一区| 国产日韩欧美综合精品 | 特黄特色欧美大片| 久久不射热爱视频精品| 久久精品久久久久久久| 国产精品一区二区三区99| 精品视频一区在线| 2024最新电影免费在线观看 | 久久久精品在线视频| 成人自拍视频| 这里只有精品在线观看| 久久久久久久久久久久久久av| 黄色小说综合网站| 日韩av电影免费观看| 69av成人| 精品国产亚洲一区二区三区在线观看| 亚洲综合第一区| 久久精品二区三区| 国产亚洲精品久久飘花| 97超碰资源站在线观看| 欧美日韩精品专区| 国产精品国产三级国产专业不| 日韩亚洲国产精品| 国产伦精品一区二区三区视频黑人| 欧美日韩视频在线播放| 欧美无人高清视频在线观看| 国产精品300页| 99pao成人国产永久免费视频| 999精品视频一区二区三区| 欧美videos极品另类| 欧美亚洲愉拍一区二区| 一区二区精品免费| 久久久久欧美精品| 精选一区二区三区四区五区| 91福利在线尤物| 精品国产麻豆免费人成网站| 免费在线黄色片| 国产激情偷乱视频一区二区三区| 色香蕉在线观看| 国产区一区二| 欧美成人全部免费| 精品人妻伦一区二区三区久久| 最新欧美精品一区二区三区| 亚洲精品第三页| 婷婷综合久久| 91青青草免费在线看| 午夜av在线播放| 日韩一区二区三区免费看 | 你懂的国产精品永久在线| 亚洲一区二区三区香蕉| 天堂av最新在线| 欧美成va人片在线观看| 久久中文字幕无码| caoporn国产一区二区| 日韩免费视频播放| 九色精品91| 国产欧美韩国高清| dy888亚洲精品一区二区三区| 欧美一卡在线观看| 精品一区免费观看| 国产视频911| 午夜精品免费看| 亚洲午夜视频| 久久综合九色99| 日韩久久一区二区三区| 日韩在线中文字幕| 亚洲av无码一区二区三区性色| 亚洲一区二区在线免费看| 李丽珍裸体午夜理伦片| 亚洲激情女人| 无码免费一区二区三区免费播放| 日韩五码电影| 欧美精品久久久久久久免费观看| 亚洲色欧美另类| 欧美性videosxxxxx| 日韩精品123区| 粉嫩一区二区三区在线看| 国产日韩亚洲欧美在线| 一区中文字幕| 国产成人精品久久久| 精品自拍一区| 亚洲黄色在线看| 在线免费观看高清视频| 一区二区三区不卡视频在线观看| 91精品国产自产| 国内精品久久久久影院薰衣草 | 另类激情视频| 久久视频国产精品免费视频在线 | 91色视频在线| 亚洲一二三av| 亚洲欧美日韩国产综合精品二区 | 成人在线资源网址| 日韩电影免费观| 欧美超级乱淫片喷水| 可以在线观看的黄色| 欧美一区二区性放荡片| 波多野结衣激情视频| 亚洲一区二区三区视频在线| 国产91丝袜美女在线播放| 成人一级片在线观看| 天天爽天天爽夜夜爽| 野花国产精品入口| 成人一区二区av| 日韩在线二区| 日本免费高清一区| 黄色免费大全亚洲| 成人啪啪免费看| 亚洲a∨精品一区二区三区导航| 欧美精品福利在线| 米奇精品一区二区三区| 国产亚洲一区二区精品| 污视频在线免费| 日韩欧美不卡一区| 国产乱码精品一区二三区蜜臂 | 超碰免费在线97| 欧美三级欧美一级| 免费看一级视频| 亚洲成av人片一区二区三区| 免费成年人视频在线观看| 日本一二三四高清不卡| 免费成人深夜夜行p站| 岛国精品一区二区| 善良的小姨在线| 紧缚捆绑精品一区二区| 色综合天天色综合| 日韩电影在线一区| 蜜臀av午夜一区二区三区| 一区二区黄色| 91免费黄视频| 国内综合精品午夜久久资源| mm131午夜| 综合日韩在线| 欧美a级黄色大片| 一区二区电影| 蜜臀在线免费观看| 欧美一区二区三区久久精品| 99精品视频网站| 91成人免费| 在线播放 亚洲| 一区二区三区四区日韩| 草草草视频在线观看| 国产精品久久| 欧美乱大交xxxxx潮喷l头像| 一区二区三区精品视频在线观看| 免费看国产曰批40分钟| 国产伦理一区| 青青在线视频观看| 日本中文字幕不卡| 久久久精品麻豆| 久久精品99国产国产精| 欧美又黄又嫩大片a级| 国产一区二区在线影院| 精品人妻人人做人人爽夜夜爽| 国产福利一区在线| 97人妻精品一区二区三区免费 | 免费在线观看黄色小视频| 一区精品在线播放| 久久久国产成人| 激情久久av一区av二区av三区| 亚洲天堂av片| 在线观看国产日韩| 国产一区二区麻豆| 日韩欧美色综合网站| 欧美77777| 亚洲男人天堂视频| 香蕉视频免费在线播放| 久久6精品影院| 成av人片在线观看www| 日本高清不卡的在线| 欧美亚洲福利| 国产精品久久久久久久免费大片| 牛牛影视一区二区三区免费看| 欧美精品人人做人人爱视频| 第一会所sis001亚洲| 无码人妻精品一区二区蜜桃网站| 亚洲免费婷婷| 亚欧激情乱码久久久久久久久| 国产高清在线精品| 色噜噜在线观看| 国产精品夫妻自拍| 国产精品99re| 欧美亚洲国产怡红院影院| 国产99对白在线播放| 国产丝袜精品视频| 大片免费在线观看| 欧美在线影院在线视频| www 久久久| 久久亚洲高清| 欧美一区二区三区久久精品茉莉花| 国模吧无码一区二区三区| 精品中文字幕一区二区| 久久久久久久无码| 亚洲视频一二三| www.com亚洲| 日韩精品在线一区| av大片在线播放| 992tv成人免费视频| 日本午夜免费一区二区| 久久综合精品一区| 狠狠干成人综合网| 午夜精品中文字幕| 久久精品一区二区三区四区| 精品视频一区二区在线观看| 欧美体内she精视频| 婷婷av一区二区三区| 欧美成人激情视频| 91p九色成人| 欧美不卡在线一区二区三区| 亚洲高清不卡| 国产精品熟女一区二区不卡| 日本一区二区成人| 激情网站在线观看| 亚洲精品国产精品国自产在线 | 欧洲成人午夜免费大片| 亚洲一区电影| 亚洲AV无码成人精品一区| 日日摸夜夜添夜夜添国产精品| 国产高清成人久久| 亚洲午夜av在线| av网站在线免费看| 久久精品国产视频| 亚洲国产aⅴ精品一区二区三区| 日日夜夜精品网站| 久久久水蜜桃av免费网站| 在线精品一区二区三区| 亚洲图片欧美一区| 亚洲av色香蕉一区二区三区| 最近2019中文免费高清视频观看www99 | 91精品啪在线观看国产手机| 亚洲免费av网| 国内精品伊人久久久久影院对白| 日韩av毛片在线观看| 欧美日韩卡一卡二| 麻豆网在线观看| 国产欧美在线观看| 久久免费av| 国产成年人视频网站| 亚洲欧洲av色图| 国产精品区在线观看| 成年人精品视频| 国产一区二区三区免费在线| avove在线观看| 国产成人一级电影| 国产无遮挡又黄又爽在线观看| 精品久久久久久最新网址| 青青草原av在线| 国产伦精品一区二区三区在线| 91久久视频| 国产精品无码专区| 日本国产一区二区| 992tv免费直播在线观看| 成人精品网站在线观看| 一区二区三区午夜视频| 国产乱淫av麻豆国产免费| 亚洲国产精品麻豆| 深夜影院在线观看| 国产精品a久久久久久| 国产高清一区| 中文字幕亚洲日本| 黑人精品xxx一区| 成人免费高清在线播放| 成人乱人伦精品视频在线观看| 午夜欧美精品久久久久久久| 国产精品成人99一区无码| 色天天综合色天天久久| 免费av不卡| 国产精品一区视频| 日产国产欧美视频一区精品| 天堂网avav| 亚洲精品国偷自产在线99热| 粉嫩一区二区三区| 国产成人三级视频| 93久久精品日日躁夜夜躁欧美 | 午夜不卡影院| 日韩中文一区| 国产精品一二三四五| 天天操天天干视频| 最近2019中文字幕在线高清| 亚洲码欧美码一区二区三区| 欧美xxxxx在线视频| 亚洲欧洲综合另类| 天天影院图片亚洲| 成人国产精品久久久久久亚洲| 伊人精品成人久久综合软件| 中文字幕在线观看免费高清| 欧美成人国产一区二区| 97成人超碰| 免费观看国产精品视频| 中文字幕一区二区视频| 婷婷综合激情网| 91精品啪aⅴ在线观看国产| 在线午夜精品| 老司机成人免费视频| 亚洲欧美中文日韩在线| 日韩中文字幕一区二区高清99| 啊啊啊国产视频| 欧美日韩国产精品|