Kafka文件存儲機制那些事

Kafak採用內存映射文件、硬盤順序寫入技術提示性能。即使是順序寫入硬盤,硬盤的訪問速度仍是不可能追上內存。因此Kafka的數據並不是實時的寫入硬盤html

它充分利用了現代操做系統分頁存儲來利用內存提升I/O效率。java

1、順序寫入ios

機械硬盤上寫仍是在 固態硬盤上寫。儘管結論都是順序寫比隨機寫快,可是緣由倒是不同的。

1. 機械硬盤app

機械硬盤的結構你能夠想象成一個唱片機,它有一個旋轉的盤片和一個能沿半徑方向移動的磁頭。處理讀取和寫入請求時,性能

首先能夠根據請求的開始地址算出要處理的數據在磁盤上的位置,以後要進行如下幾步工做:
 
一、磁頭沿半徑方向移動,直至移動到數據所在的 柱面(相同半徑的磁道組成的環面)

二、盤片高速旋轉,使磁頭到達數據的起始位置

三、磁頭沿磁道從磁盤讀取或寫入數據
 
當一次讀取的數據量不多的時候,一、2步驟帶來的開銷是沒法忽略的,這使得隨機寫相對於順序寫會有巨大的性能劣勢。
 
由於在順序寫的時候,一、2步驟只須要執行一次,剩下的全是數據傳輸所須要的固有開銷;
 
而每次隨機寫的時候,前兩個步驟都須要執行,帶來了極大的額外開銷。

 

2. 固態硬盤
理論上來講,它不該該存在明顯的隨機寫與順序寫的速度差別,由於它就是一塊支持隨機尋址的存儲芯片,沒有尋道和旋轉盤片的開銷,可是隨機寫實際
 
上仍是比順序寫要慢。這是因爲其存儲介質 閃存的一些特性致使的,簡單來講:

一、閃存不支持in-place update:你更新一個數據,不能夠直接在原有數據上改,而要寫到新的空白的地方,並把原有數據標記爲失效。

二、標記失效的數據不是浪費空間麼?能夠將其清除。可是閃存上清除操做的最小單位是一個大塊,大約128K-256K的大小。
 
一次清除會影響到還未標記失效的有用的數據,要先把它們移走。
 
2、內存映射文件

java io操做中一般採用BufferedReader,BufferedInputStream等帶緩衝的IO類處理大文件,不過java nio中引入MappedByteBuffer操做大文件的方式,其讀寫性能極高。this

File.read()將文件從硬盤拷貝到內核空間的一個緩衝區,再將這些數據拷貝到用戶空間,實際上進行了兩次數據拷貝。spa

FileChannal.map()直接將文件從硬盤拷貝到用戶空間,只進行了一次數據拷貝。操作系統

1.code

public class MapMemeryBuffer {
    public static void main(String[] args) throws Exception {
        ByteBuffer byteBuf = ByteBuffer.allocate(14 * 1024 * 1024);
        byte[] bytes = new byte[14 * 1024 * 1024];
        FileInputStream fis = new FileInputStream("d:\\java_transactions_book.pdf");
        FileOutputStream fos = new FileOutputStream("d:\\java_transactions_book_copy.pdf");
        FileChannel fileChannel = fis.getChannel();

        long timeStar = System.currentTimeMillis();
        // 讀取
        //fileChannel.read(byteBuf);
        MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
        long timeEnd = System.currentTimeMillis();
        System.out.println("Read time :" + (timeEnd - timeStar) + "ms");

        timeStar = System.currentTimeMillis();
        // 寫入
        //fos.write(bytes);
        // After a sequence of channel-read or put operations,
        // invoke this method to prepare for a sequence of channel-write or relative get operations.
        mbb.flip();
        timeEnd = System.currentTimeMillis();
        System.out.println("Write time :" + (timeEnd - timeStar) + "ms");

        fos.flush();
        fileChannel.close();
        fis.close();
    }
}

 

2.注意htm

A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.

The content of a mapped byte buffer can change at any time, for example if the content of the corresponding region of the mapped file

is changed by this program or another. Whether or not such changes occur, and when they occur, is operating-system dependent and

therefore unspecified.

All or part of a mapped byte buffer may become inaccessible at any time, for example if the mapped file is truncated. An attempt to access an

inaccessible region of a mapped byte buffer will not change the buffer's content and will cause an unspecified exception to be thrown either at

the time of the access or at some later time. It is therefore strongly recommended that appropriate precautions be taken to avoid the manipulation

of a mapped file by this program, or by a concurrently running program, except to read or write the file's content.

 

Mapped byte buffers otherwise behave no differently than ordinary direct byte buffers.

解決:

AccessController.doPrivileged(newPrivilegedAction() {   
  publicObject run() {   
    try{   
       Method getCleanerMethod = buffer.getClass().getMethod("cleaner",newClass[0]);   
       getCleanerMethod.setAccessible(true);   
       sun.misc.Cleaner cleaner = (sun.misc.Cleaner)   
       getCleanerMethod.invoke(byteBuffer,newObject[0]);   
       cleaner.clean();   
     } catch(Exception e) {   
       e.printStackTrace();   
     }   
    returnnull;   
   }   
});  

 

 

參考:

美團:Kafka文件存儲機制那些事

iostat命令

相關文章
相關標籤/搜索