Caching 写文件:实践中的数据一致性

Caching 写文件:实践中的数据一致性,caching,storage,consistency,acid,Caching,Storage,Consistency,Acid,我正在现实世界中开发一个多用户文件存储系统 该系统必须面对系统崩溃或断电事件 失败,所以我正在研究一致性和耐用性 许多数据库系统支持ACID和现代计算机系统 支持的日志文件系统。我注意到一个记录系统 对于这样的系统来说非常重要,我们可以使用日志系统 找出坠机前发生了什么和没有发生什么, 所以,当系统重新启动时,我们可以做一个合适的恢复工作 典型的测井系统工作步骤: 写入日志(数据或元数据) 写入实际数据 提交日志 因此,当系统崩溃事件发生时,只有几种可能性: 日志不完整:所以忽略它 日志未提交:

我正在现实世界中开发一个多用户文件存储系统 该系统必须面对系统崩溃或断电事件 失败,所以我正在研究一致性和耐用性

许多数据库系统支持ACID和现代计算机系统 支持的日志文件系统。我注意到一个记录系统 对于这样的系统来说非常重要,我们可以使用日志系统 找出坠机前发生了什么和没有发生什么, 所以,当系统重新启动时,我们可以做一个合适的恢复工作

典型的测井系统工作步骤:

  • 写入日志(数据或元数据)
  • 写入实际数据
  • 提交日志
  • 因此,当系统崩溃事件发生时,只有几种可能性:

  • 日志不完整:所以忽略它
  • 日志未提交:因此数据不完整-执行回滚
  • 日志已提交:操作已完成
  • 有些日志文件系统就是这样工作的

    我不知道数据库系统是如何工作的,一般来说 数据库系统是一个运行在用户空间的软件,正如我所知, 在文件写入功能和磁盘之间有几个方面 表面:

  • 进程缓存
  • 系统缓存
  • 磁盘缓存
  • 因此,当函数返回时,数据可能不在磁盘上,而是在磁盘上 在这些储藏室里

    在Windows系统上,可以通过文件\u标志\u无\u缓冲来禁用缓存 标志CreateFile时,MSDN表示“当缓存被禁用时,所有文件都将被读取 和写操作直接访问物理磁盘”,我的第一个 问题是,磁盘缓存上的文件\u标记\u否\u缓冲是否会关闭 好?或者如何确保数据已到达磁盘表面 ?

    还有一个问题:SATA和SCSI磁盘正在使用“命令” “排队”技术,队列中的命令可以重新排序 可以更有效地进行处理,但日志记录系统取决于 时间顺序,命令队列对日志系统(在用户空间中)有害吗?
    或者如何确保A在B之前写入?

    以安全碰撞方式覆盖数据的基本方法是:

  • 首先将数据写入新的存储位置。(您实际上还没有覆盖任何内容。)
  • 告诉操作系统使用POSIX
    fsync
    函数将上述内容刷新到稳定的存储中。这意味着刷新缓存和所有内容,以便当函数返回时,数据实际上在磁盘上
  • 在某个地方写一个“日志”条目,表明此更新的所有新数据都已写入并准备提交
  • 将日志条目刷新到磁盘
  • 读取在步骤1中写入的数据,并将其写入“真实”存储位置。(这是进行实际覆盖的地方。)
  • 写另一个日记条目,说明变更已提交
  • 删除在步骤1中创建的临时文件
  • 刷新的作用是:它们确保刷新之前的所有内容都安全地存储在磁盘上,然后才能写入刷新之后的任何内容。在一对屏障之间,写入的重新排序(例如,由于具有命令队列的磁盘)不是问题,因为屏障确保在重要位置的顺序是正确的。在步骤1中,您不关心磁盘是否在写入文件的前半部分之前先物理写入文件的后半部分;您只需要注意整个文件在日志条目证明新文件已完成之前已写入

    崩溃后,您将浏览日志并处理每个条目:

    • 如果您发现步骤1中的文件没有步骤3中相应的条目,请将该文件视为不完整文件并将其丢弃。这是对未完成更改的回滚
    • 如果存在步骤3中的条目,但不存在步骤6中的条目,则重复步骤5。有可能是第5步在撞车前部分完成了,但这并不重要;这只是意味着您可能正在用相同的字节覆盖某些数据,这是无害的
    • 如果存在步骤6中的条目,则重复步骤7,如果文件仍然存在,则删除该文件

    您可能会发现阅读它很有用(这是PostgreSQL对上述日志记录机制的术语)。它包含了额外的安全措施,例如对WAL(日志)条目进行校验和,以防止损坏,并且磁盘刷新被延迟并成批处理,以便在正常操作期间获得更好的性能(以可能需要更长时间的碰撞恢复为代价)


    说到数据库,使用它的健壮性和测试性的一致性和持久性机制可能比你自己尝试更容易和更安全。如果像PostgreSQL这样的完整数据库服务器对你的应用程序来说太重了,考虑使用像(这是一个低级键值存储,而不是SQL关系数据库).support.

    是的,SQL的东西太重了。我已经阅读了Berkeley DB和UnQLite关于事务的文档,为了隔离,在给定的时间内只允许一个写操作,这对我们的项目不太合适,我们需要并发运行事务,并且每个事务都是一批文件——要么全部,要么什么都没有。所以我仍然是s搜索和学习。Q1:FILE_FLAG_WRITE_THROUGH标志关闭系统缓存,数据将缓存在磁盘缓存中,但仍写入磁盘。FILE_FLAG_NO_缓冲消除了所有预读文件缓冲和磁盘缓存。Q2:这不再重要。