1. 程式人生 > >linux 同步IO: sync、fsync與fdatasync

linux 同步IO: sync、fsync與fdatasync

傳統的UNIX實現在核心中設有緩衝區快取記憶體或頁面快取記憶體,大多數磁碟I/O都通過緩衝進行。當將資料寫入檔案時,核心通常先將該資料複製到其中一個緩衝區中,如果該緩衝區尚未寫滿,則並不將其排入輸出佇列,而是等待其寫滿或者當核心需要重用該緩衝區以便存放其他磁碟塊資料時,再將該緩衝排入輸出佇列,然後待其到達隊首時,才進行實際的I/O操作。這種輸出方式被稱為延遲寫(delayed write)(Bach [1986]第3章詳細討論了緩衝區快取記憶體)。
延遲寫減少了磁碟讀寫次數,但是卻降低了檔案內容的更新速度,使得欲寫到檔案中的資料在一段時間內並沒有寫到磁碟上。當系統發生故障時,這種延遲可能造成檔案更新內容的丟失。為了保證磁碟上實際檔案系統與緩衝區快取記憶體中內容的一致性,UNIX系統提供了sync、fsync和fdatasync三個函式。
sync函式只是將所有修改過的塊緩衝區排入寫佇列,然後就返回,它並不等待實際寫磁碟操作結束。
通常稱為update的系統守護程序會週期性地(一般每隔30秒)呼叫sync函式。這就保證了定期沖洗核心的塊緩衝區。命令sync(1)也呼叫sync函式。
fsync函式只對由檔案描述符filedes指定的單一檔案起作用,並且等待寫磁碟操作結束,然後返回。fsync可用於資料庫這樣的應用程式,這種應用程式需要確保將修改過的塊立即寫到磁碟上。
fdatasync函式類似於fsync,但它隻影響檔案的資料部分。而除資料外,fsync還會同步更新檔案的屬性。

於提供事務支援的資料庫,在事務提交時,都要確保事務日誌(包含該事務所有的修改操作以及一個提交記錄)完全寫到硬碟上,才認定事務提交成功並返回給應用層。

一個簡單的問題:在*nix作業系統上,怎樣保證對檔案的更新內容成功持久化到硬碟?

1. write不夠,需要fsync

一般情況下,對硬碟(或者其他持久儲存裝置)檔案的write操作,更新的只是記憶體中的頁快取(page cache),而髒頁面不會立即更新到硬碟中,而是由作業系統統一排程,如由專門的flusher核心執行緒在滿足一定條件時(如一定時間間隔、記憶體中的髒頁達到一定比例)內將髒頁面同步到硬碟上(放入裝置的IO請求佇列)。 因為write呼叫不會等到硬碟IO完成之後才返回,因此如果OS在write呼叫之後、硬碟同步之前崩潰,則資料可能丟失。雖然這樣的時間視窗很小,但是對於需要保證事務的持久化(durability)和一致性(consistency)的資料庫程式來說,write()所提供的“鬆散的非同步語義”
是不夠的,通常需要OS提供的同步IO(synchronized-IO)原語來保證:
1 #include <unistd.h>
2 int fsync(int fd);
fsync的功能是確保檔案fd所有已修改的內容已經正確同步到硬碟上,該呼叫會阻塞等待直到裝置報告IO完成。 PS:如果採用記憶體對映檔案的方式進行檔案IO(使用mmap,將檔案的page cache直接對映到程序的地址空間,通過寫記憶體的方式修改檔案),也有類似的系統呼叫來確保修改的內容完全同步到硬碟之上:
1 #incude <sys/mman.h>
2 int msync(void *addr, size_t length, int
flags)

msync需要指定同步的地址區間,如此細粒度的控制似乎比fsync更加高效(因為應用程式通常知道自己的髒頁位置),但實際上(Linux)kernel中有著十分高效的資料結構,能夠很快地找出檔案的髒頁,使得fsync只會同步檔案的修改內容。

2. fsync的效能問題,與fdatasync

除了同步檔案的修改內容(髒頁),fsync還會同步檔案的描述資訊(metadata,包括size、訪問時間st_atime & st_mtime等等),因為檔案的資料和metadata通常存在硬碟的不同地方,因此fsync至少需要兩次IO寫操作,fsync的man page這樣說:

"Unfortunately fsync() will always initialize two write operations : one for the newly written data and another one in order to update the modification time stored in the inode. If the modification time is not a part of the transaction concept fdatasync()can be used to avoid unnecessary inode disk write operations."

多餘的一次IO操作,有多麼昂貴呢?根據Wikipedia的資料,當前硬碟驅動的平均尋道時間(Average seek time)大約是3~15ms,7200RPM硬碟的平均旋轉延遲(Average rotational latency)大約為4ms,因此一次IO操作的耗時大約為10ms左右。這個數字意味著什麼?下文還會提到。

Posix同樣定義了fdatasync,放寬了同步的語義以提高效能:

1 #include <unistd.h>
2 int fdatasync(int fd);
fdatasync的功能與fsync類似,但是僅僅在必要的情況下才會同步metadata,因此可以減少一次IO寫操作。那麼,什麼是“必要的情況”呢?根據man page中的解釋:
"fdatasync does not flush modified metadata unless that metadata is needed in order to allow a subsequent data retrieval to be corretly handled."
舉例來說,檔案的尺寸(st_size)如果變化,是需要立即同步的,否則OS一旦崩潰,即使檔案的資料部分已同步,由於metadata沒有同步,依然讀不到修改的內容。而最後訪問時間(atime)/修改時間(mtime)是不需要每次都同步的,只要應用程式對這兩個時間戳沒有苛刻的要求,基本無傷大雅。 PS:open時的引數O_SYNC/O_DSYNC有著和fsync/fdatasync類似的語義:使每次write都會阻塞等待硬碟IO完成。(實際上,Linux對O_SYNC/O_DSYNC做了相同處理,沒有滿足Posix的要求,而是都實現了fdatasync的語義)相對於fsync/fdatasync,這樣的設定不夠靈活,應該很少使用。

3. 使用fdatasync優化日誌同步

文章開頭時已提到,為了滿足事務要求,資料庫的日誌檔案是常常需要同步IO的。由於需要同步等待硬碟IO完成,所以事務的提交操作常常十分耗時,成為效能的瓶頸。
在Berkeley DB下,如果開啟了AUTO_COMMIT(所有獨立的寫操作自動具有事務語義)並使用預設的同步級別(日誌完全同步到硬碟才返回),寫一條記錄的耗時大約為5~10ms級別,基本和一次IO操作(10ms)的耗時相同。
我們已經知道,在同步上fsync是低效的。但是如果需要使用fdatasync減少對metadata的更新,則需要確保檔案的尺寸在write前後沒有發生變化。日誌檔案天生是追加型(append-only)的,總是在不斷增大,似乎很難利用好fdatasync。 且看Berkeley DB是怎樣處理日誌檔案的:
1.每個log檔案固定為10MB大小,從1開始編號,名稱格式為“log.%010d" 2.每次log檔案建立時,先寫檔案的最後1個page,將log檔案擴充套件為10MB大小 3.向log檔案中追加記錄時,由於檔案的尺寸不發生變化,使用fdatasync可以大大優化寫log的效率 4.如果一個log檔案寫滿了,則新建一個log檔案,也只有一次同步metadata的開銷

相關推薦

linux 同步IO: syncfsyncfdatasync

傳統的UNIX實現在核心中設有緩衝區快取記憶體或頁面快取記憶體,大多數磁碟I/O都通過緩衝進行。當將資料寫入檔案時,核心通常先將該資料複製到其中一個緩衝區中,如果該緩衝區尚未寫滿,則並不將其排入輸出佇列,而是等待其寫滿或者當核心需要重用該緩衝區以便存放其他磁碟塊資料時,再

Linuxsyncfsyncfdatasync函式使用介紹

三個函式的特點 sync、fsync與fdatasync都是磁碟同步函式,分別有以下特點。 sync函式只是將所有修改過的塊緩衝區排入寫佇列,然後就返回,它並不等待實際寫磁碟操作結束。通常稱為update的系統守護程序會週期性地(一般每隔30秒)呼叫sync函式

Linux】檔案IO --- syncfsyncfdatesync

在使用write函式向檔案中寫入資料的時候,並不是在呼叫了函式以後就直接把資料寫入磁碟;作業系統在核心中設定了一塊專門的緩衝區,資料會先被寫入到核心的緩衝區中,等到緩衝區滿了或者系統需要重新利用緩衝區的時候才會將緩衝區的資料排入到寫佇列中去,待到達對首的時候,就將資料寫入到磁碟中。這就是延遲寫,因為不是馬上將

linux 下檔案同步函式(fflushsyncfsyncfdatasync)之間差異

遇到機器異常關機時,寫log檔案資訊丟失問題,所以記錄下。   Linux實現中在核心設有緩衝區快取記憶體或頁面快取記憶體,大多數磁碟I/O都通過緩衝區進行。當我們向檔案寫資料時,核心通常先將資料複製到一個緩衝區中,如果該緩衝區尚未寫滿,則並不將其排入輸出佇列,而是等待寫滿或者核心需要重用該

linux命令的排列替換別名

data- 定義 div nbsp 命令 空格 con 接下來 是否 命令的排列; 1、使用“;” 命令語法: 命令1;命令2 當運行該命令時,無論命令1是否出錯。接下來就運行命令2 2、使用“&&” 命令語法:命令1&&命令2 當運行該

鳥哥的Linux私房菜-----16程序資源管理

blog dsm alt 技術 article ack src mar data 鳥哥的Linux私房菜-----16、程序與資源管理

Linux虛擬化技術KVMQEMUlibvirt的關系(轉)

實例 -c html cef 處理器 虛擬 處理 不足 lan 說明:個人理解,KVM是內核虛擬化技術,而內核是不能使用在界面上使用的,那麽此時QEMU提供了用戶級別的使用界面,相互輔助。當然,單獨使用QEMU也是可以實現一整套虛擬機,不過QEMU+KVM基本是標配Linu

linux指令(二目錄文件常用指令)

1.對目錄的相關操作 在所有目錄底下都會存在的兩個目錄,分別是『.』與『..』 分別代表此層與上層目錄的意思。 . 代表此層目錄 .. 代表上一層目錄 - 代表前一個工作目錄 ~ 代表『目前使用者身份』所在的家目錄 ~account 代表account 這個使用者的家目錄(acco

linux指令(一目錄檔案)

一、文件與目錄 1.Linux檔案屬性 第一個字元代表這個檔案是『目錄、檔案或連結檔等等』: 當為[ d ]則是目錄; 當為[ - ]則是檔案; 若是[ l ]則表示為連結檔(

Linux下載:wgetyumapt-get用法及區別

一般來說著名的linux系統基本上分兩大類: RedHat系列:Redhat、Centos、Fedora等 Debian系列:Debian、Ubuntu等 RedHat 系列  常見的安裝包格式 rpm包,安裝rpm包的命令是“rpm -引數” 包管

Linux系列八-typealiashistory

一、別名 alias : 展示當前已設定的命令別名 alias ll='ls -alF' : 設定ls -alF命令的別名為ll,此時這兩個命令效果等同 unalias ll :取消ll的別名設定 二、history 歷史命令 history [n] : 列出最近的n條命令 hi

linux下redis安裝啟動停止,redis做成服務

如果的linux可以連結網路,那麼可以直接聯網下載。直接輸入程式碼:wget http://download.redis.io/releases/redis-3.0.2.tar.gztar zxvf redis-3.0.2.tar.gz 我們會看到在該目錄下多了一個檔案,re

linux 程序建立cloneforkvfork

 目錄: 1、clone、fork與vfork介紹 2、fork說明 3、vfork說明 4、clone說明5、fork,vfork,clone的區別 內容: 1、clone、fork與vfork介

java多執行緒:執行緒同步synchronized(不同步的問題佇列鎖),死鎖的產生和解決

# 0、不同步的問題 併發的執行緒不安全問題: 多個執行緒同時操作同一個物件,如果控制不好,就會產生問題,叫做執行緒不安全。 我們來看三個比較經典的案例來說明**執行緒不安全的問題**。 ## 0.1 訂票問題 例如前面說過的黃牛訂票問題,可能出現負數或相同。 [執行緒建立方式&&黃牛訂票

簡述linux同步非同步阻塞非阻塞概念以及五種IO模型

1、概念剖析 相信很多從事linux後臺開發工作的都接觸過同步&非同步、阻塞&非阻塞這樣的概念,也相信都曾經產生過誤解,比如認為同步就是阻塞、非同步就是非阻塞,下面我們先剖析下這幾個概念分別是什麼含義。 同步:所謂同步,就是在發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必

同步IO非同步IO阻塞IO非阻塞IO之間的聯絡區別

POSIX 同步IO、非同步IO、阻塞IO、非阻塞IO,這幾個詞常見於各種各樣的與網路相關的文章之中,往往不同上下文中它們的意思是不一樣的,以致於我在很長一段時間對此感到困惑,所以想寫一篇文章整理一下。 POSIX(可移植作業系統介面)把同步IO操作定義為導致程序阻塞直到

同步IO異步IO阻塞IO非阻塞IO之間的聯系區別

過程 image pre 導致 內核 因此 epo 一段 來看 POSIX 同步IO、異步IO、阻塞IO、非阻塞IO,這幾個詞常見於各種各樣的與網絡相關的文章之中,往往不同上下文中它們的意思是不一樣的,以致於我在很長一段時間對此感到困惑,所以想寫一篇文章整理一下。 POSI

一段話系列-LinuxIO同步非同步阻塞非阻塞

首先我們框定一下背景,我們探討的是Linux系統下的IO模型。 同步和非同步是針對核心操作資料而言的,同步是指核心序列順序操作資

Linux input子系統編程分析模板

linux輸入設備都有共性:中斷驅動+字符IO,基於分層的思想,Linux內核將這些設備的公有的部分提取出來,基於cdev提供接口,設計了輸入子系統,所有使用輸入子系統構建的設備都使用主設備號13,同時輸入子系統也支持自動創建設備文件,這些文件采用阻塞的IO讀寫方式,被創建在"/dev/input/"下。如下

鳥哥的Linux私房菜-----15例行性命令atcrontab

鳥哥 jsb size csdn fonts rontab img -a fontsize 鳥哥的Linux私房菜-----15、例行性命令at與crontab