内容简介:fsync 和 fdatasync
最近在读微信开源的 paxos 实现 phxpaxos ,读到 localstorage 部分学习到 fdatasync 系统调用。这一部分是非常核心的存储模块,参与者的状态信息、变更日志等都要写入磁盘并且可能要求强制刷入存储磁盘避免系统崩溃等情况下数据丢失,性能的很大一部分因素取决于这一块的实现。
phxpaxos 使用了 LevelDB 做存储,但是做了几个优化:
- LevelDB 存储的 value 只是一个 24 个字节的 fileid 索引(有一个例外 minchosen 值),真正的状态数据存储在他们自己实现的 log_store 里, fileid 存储了在 log_store 里的文件编号、写入 vfile 的offset 和 checksum 这三个字段信息。这样做的原因是由于 leveldb 对于比较大的 value 的存取效率不是最优,通过间接一层存储,利用了 LevelDB 的 Key 的有序性和小 value 存储的性能优势,加上定制的 log_store 的写入优化,达到最优组合。
- log_store 按照文件编号固定增长,比如
1.f
、2.f
、3.f
……以此类推(在日志目录的 vfile 目录下)。并且每个文件都是在创建的时候分配固定大小,默认 100M(还有所谓 large buffer 模式分配的是 500M)。值的写入都是 append 操作,写入完成后,将偏移量、校验和、当前文件 ID 再写入 LevelDB。读取的时候就先从 LevelDB 得到这三个信息,然后去对应的 vfile 读取实际的值。因为文件是固定大小分配,每次强制刷盘就不需要调用fsync
,而是采用fdatasync
,这样就无需做两次刷盘,因为fdatasync
不会去刷入文件的元信息(比如大小、最后访问时间、最后修改时间等),而 fsync 是会的。
一张图来展示大概是这样:
注意到图中还有个 metafile,它存储了 log store 的当前的文件编号这个元信息,写满一个 vfile 就递增下这个计数,并更新到 metafile,为了保证不丢,对它的每次修改都需要强制 fsync。
回到文本的主题 fsync 和 fdatasync,按照 manual 的描述, fsync 同时刷入数据和元信息
fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device ...... It also flushes metadata information associated with the file (see stat(2)).
而 fdatasync 如无必要,只刷入数据:
fdatasync() is similar to fsync(), but does not flush modified metadata unless that metadata is needed in order to allow a subsequent data retrieval to be correctly handled.
log_store 的实现因为提前分配了固定大小的文件,因此无需在刷盘的时候再去写入元信息,就可以使用 fdatasync 来优化刷盘性能,而访问时间和修改时间之类的元信息丢失对业务没有影响。
以上所述就是小编给大家介绍的《fsync 和 fdatasync》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。