作为文件损坏的常见原因,文档通常引用“NFS 未正确实现文件级锁定”或类似内容,例如对于 SQLite:
如何损坏 SQLite 数据库文件,第 2.1 段
2.1 文件系统锁实现损坏或缺失
SQLite 依赖于底层文件系统来执行锁定,正如文档所述。但有些文件系统的锁定逻辑存在错误,因此锁定并不总是按照宣传的方式运行。网络文件系统和 NFS 尤其如此。如果在锁定原语包含错误的文件系统上使用 SQLite,并且如果两个或多个线程或进程尝试同时访问同一个数据库,则可能会导致数据库损坏。
十多年来,人们经常提到这一点或类似的东西,通常是在混合 Windows/Unix 环境中。然而,我从未发现任何迹象哪个网络文件系统(或客户端/服务器组合)实际上存在风险。
我能告诉我的客户什么?
答案1
哪些网络文件系统没有正确实现锁定?
我认为正确答案简而言之就是“全部”。
这应该适用于多台计算机上的多个进程通过网络访问同一数据库的上下文。如果数据库引擎 (SQLite) 使用信号量或互斥量等排除工具(并正确使用它们...),那么当所有访问数据库的进程都在同一台计算机上运行时,应该不会出现问题。
这样做的原因是,锁定的信息通常保存在“进程 X 锁定 Y”的上下文中。当所有进程都在同一台计算机上执行时,这种方法可能非常有效,但当它们位于不同的计算机上时,这种方法就不太有效了。
当一台计算机上的进程访问另一台计算机上的文件时,本地操作系统会代替远程进程,实际上是充当它一无所知的进程的代理。它甚至可能难以区分在同一台远程计算机上执行的两个不同进程,并会将其中一个进程误认为另一个进程。
为了正确锁定文件(整个文件或其中的一部分),实际上需要一个在所有相关计算机上执行的操作系统,并具有用于文件锁定的集中数据存储库。不幸的是,Linux 和 Windows 都无法在一般情况下做到这一点。
你可以在旧文章的“如何破坏你的数据库文件”部分找到关于 SQLite 主题的更好的论述 SQLite 版本 3 中的文件锁定和并发。本文详细介绍了 SQLite 用于确保 Windows 和 Linux 上的并发性的系统调用,包括锁定文件部分和将更新的数据从计算机刷新到数据库。所有列出的函数仅在一台计算机的环境中才能正常工作。恰当地说,本文包含这样一句话:“最好的防御措施是不要将 SQLite 用于网络文件系统上的文件”。
请注意,将数据刷新到数据库的问题尤其令人担忧,因为操作系统通常会延迟写入,因此您可能会遇到这样的情况:更新过程已刷新数据并释放其锁,但当另一个进程尝试读取新数据时,新数据可能尚未到达数据库,因此很容易导致数据库损坏。
SQLite 文章中提供了更多信息 SQLite 中的原子提交, 部分 可能出错的事情. 它增加了不同进程和计算机可能使用不同锁定机制的情况,其中一个不会阻止另一个。
在解决此问题的数据库管理系统(如 Oracle 或 SQL Server)中,解决方案是指定一台特定的计算机作为唯一可以更新数据库的计算机,因此锁定大大简化。其他计算机网络系统,如 Apache Hadoop 提供自己的锁定机制来解决这些问题。
另一篇您可能感兴趣的文章是 论文件锁定的破坏性。