sync(意指Synchronize,即“同步”)为UNIX操作系统的标准系统调用,功能为将内核文件系统缓冲区的所有数据(也即预定将通过低级I/O系统调用[注 1]写入存储介质的数据)写入存储介质(如硬盘)。

作为C语言的函数之一,sync()一般以void sync(void)的形式在unistd.h内声明。该函数也可以从命令行执行sync命令的方式调用,同时在其他程序语言(如Perl)中也有名字与之相似的函数。

相关调用

UNIX中还有一些与sync相似的系统调用,如fsyncfdatasync。其中fsync负责写入所有与特定文件描述符相关的缓冲区数据[1]fdatasync功能与fsync相似,但只负责写入文件中被变更的数据,而不会修改文件的元数据(如文件属性)[2]

在系统中的应用

UNIX内核常会运行一些诸如flush或update之类的守护进程以将缓冲区数据写入目标,而这些进程都要调用sync函数;在其他某些操作系统上这类任务由cron完成,而在Linux上负责者则为守护进程pdflush[3]。在卸载或以只读权限重载文件系统时,系统也会将缓冲区内容写入存储介质。

数据库中的应用

在对数据进行修改操作(包括增、删、改)时,被修改的数据一般仅是暂存于基于内存的写入缓存,而当掉电时这些修改便会丢失;而为保证数据的持久性,数据库必须使用某些形式的sync,以确保修改的内容切实写入非易失性存储器,如PostgreSQL就使用了多种sync类调用(包括fsyncfdatasync)来达到这一目的[4]

但是,对于旋转寻道的硬盘来说,每次旋转只能完成一项“提交”操作以将客户端的修改写入,因此每秒最多只能完成几百次的“提交”操作[5];而若关闭fsync的限定来放宽要求,则可大幅提升性能,但同时也会带来系统崩溃后数据库损毁英语Data corruption的潜在危险。有鉴于此,数据库也使用囊括最近修改信息的日志文件英语Transaction log(一般比主题数据文件小得多)来保障可靠性:根据日志文件,系统管理员可以在系统崩溃后准确地重做修改操作,以此即可减少对主要数据文件的sync操作。

相关争议

在默认情况下,硬盘一般使用自有的易失性写入缓存以缓存要写入的数据。这一做法可以大幅提升性能,但同时也会带来写入操作丢失的潜在风险[6],不过开/关缓存的性能落差的确相当巨大,甚至连素来保守的FreeBSD社群为此也否决了在FreeBSD 4.3内默认关闭写入缓存(即是说,修改后直接调用sync写入硬盘)的提案[7]

另外,在Firefox引入fsync调用的目的以保证其内嵌的SQLite数据库的完整性后,便有人指出fsync降低了Firefox 3.0的性能[8];而Linux基金会技术总监西奥多·周则在“Don't fear the fsync!”一文中讨论了fsync的性能表现,并表示“没有必要害怕fsync”[9]

注释

  1. ^ 在此需要注意的是,高级I/O层(如stdio)可能使用自行维护的缓冲区。

参考资料

  1. ^ fsync specification. [2012-12-28]. (原始内容存档于2010-10-31). 
  2. ^ fdatasync specification. [2012-12-28]. (原始内容存档于2009-08-28). 
  3. ^ The Linux Page Cache and pdflush. [2012-12-28]. (原始内容存档于2009-11-24). 
  4. ^ PostgreSQL Reliability and the Write-Ahead Log. [2012-12-28]. (原始内容存档于2012-12-29). 
  5. ^ Tuning PostgreSQL WAL Synchronization. [2012-12-28]. (原始内容存档于2009-11-25). 
  6. ^ Write-Cache Enabled?. [2012-12-28]. (原始内容存档于2012-12-17). 
  7. ^ FreeBSD Handbook — Tuning Disks. [2012-12-28]. (原始内容存档于2012-12-24). 
  8. ^ Mike Shaver. fsyncers and curveballs. [2012-12-28]. (原始内容存档于2012-12-09). 
  9. ^ Ts'o, Theodore. Don't fear the fsync!. 2009-03-16 [2017-09-06]. (原始内容存档于2016-04-03).