- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
TL;DR:如果 Linux 内核丢失了缓冲的 I/O 写入,应用程序有什么方法可以发现吗?
我知道您必须对文件(及其父目录)进行 fsync()
以确保持久性。问题是如果内核由于 I/O 错误而丢失了等待写入的脏缓冲区,应用程序如何检测到这一点并恢复或中止?
想想数据库应用程序等,其中写入顺序和写入持久性至关重要。
Linux内核的 block 层在某些情况下会丢失缓冲的已经被write()
、pwrite()
成功提交的I/O请求code> 等,错误如下:
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(参见 end_buffer_write_sync(...)
and end_buffer_async_write(...)
in fs/buffer.c
)。
On newer kernels the error will instead contain "lost async page write" ,比如:
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
由于应用程序的 write()
已经返回且没有错误,似乎没有办法将错误报告回应用程序。
我对内核源代码不太熟悉,但我认为它将 AS_EIO
设置在缓冲区上,如果它正在执行异步则无法被写出写:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
但我不清楚应用程序是否或如何在稍后 fsync()
s 文件以确认它在磁盘上时发现它。
看起来像 wait_on_page_writeback_range(...)
in mm/filemap.c
可能来自 do_sync_mapping_range(...)
in fs/sync.c
由sys_sync_file_range(...)
轮流调用.如果无法写入一个或多个缓冲区,则返回 -EIO
。
如果,正如我所猜测的那样,这会传播到 fsync()
的结果,那么如果应用程序在从 fsync( )
并且知道重新启动时如何重新工作,这应该是足够的保障吗?
应用程序可能无法知道文件中的哪些字节偏移对应于丢失的页面,因此如果它知道如何重写它们,但如果应用程序重复所有待处理的工作,因为文件的最后一个成功的 fsync()
,并重写与文件丢失写入相对应的任何脏内核缓冲区,这应该清除丢失页面上的任何 I/O 错误标志并允许下一个 fsync()
来完成 - 对吧?
还有其他无害的情况,fsync()
可能会返回 -EIO
,在这种情况下,救助和重做工作会过于激烈?
当然这样的错误不应该发生。在这种情况下,错误是由 dm-multipath
驱动程序的默认值与 SAN 用来报告分配精简配置存储失败的检测代码之间的不幸交互引起的。但这并不是它们可能发生的唯一情况——我还看到了来自精简配置 LVM 的报告,例如 libvirt、Docker 等使用的。像数据库这样的关键应用程序应该尝试处理此类错误,而不是一味地装作万事大吉。
如果内核认为在不因内核 panic 而死的情况下丢失写入是可以的,则应用程序必须找到应对方法。
实际影响是,我发现了一个案例,即 SAN 的多路径问题导致写入丢失,导致数据库损坏,因为 DBMS 不知道其写入已失败。不好玩。
最佳答案
fsync()
如果内核丢失写入,则返回 -EIO
(注意:早期部分引用了旧内核;下面更新以反射(reflect)现代内核)
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
然后由 wait_on_page_writeback_range(...)
检测到,由 do_sync_mapping_range(...)
调用,由 sys_sync_file_range(...)
由 sys_sync_file_range2(...)
调用以实现 C 库调用 fsync()
。
This comment on sys_sync_file_range
168 * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
169 * I/O errors or ENOSPC conditions and will return those to the caller, after
170 * clearing the EIO and ENOSPC flags in the address_space.
建议当 fsync()
返回 -EIO
或(手册页中未记录)-ENOSPC
时,它会清除错误状态,因此即使页面从未被写入,后续 fsync()
也会报告成功。
果然wait_on_page_writeback_range(...)
clears the error bits when it tests them :
301 /* Check for outstanding write errors */
302 if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
303 ret = -ENOSPC;
304 if (test_and_clear_bit(AS_EIO, &mapping->flags))
305 ret = -EIO;
所以如果应用程序期望它可以重试 fsync()
直到它成功并相信数据在磁盘上,那就大错特错了。
我很确定这是我在 DBMS 中发现的数据损坏的根源。它重试 fsync()
并认为成功后一切都会好起来的。
POSIX/SuS docs on fsync()
无论哪种方式都不要真正指定:
If the fsync() function fails, outstanding I/O operations are not guaranteed to have been completed.
Linux's man-page for fsync()
只是没有说明失败时会发生什么。
所以看来 fsync()
错误的意思是“我不知道你写的东西发生了什么,可能有效与否,最好再试一次确定”。
4.9 end_buffer_async_write
在页面上设置 -EIO
,只是通过 mapping_set_error
。
buffer_io_error(bh, ", lost async page write");
mapping_set_error(page->mapping, -EIO);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
在同步方面,我认为它是相似的,尽管结构现在非常复杂。 mm/filemap.c
中的 filemap_check_errors
现在可以:
if (test_bit(AS_EIO, &mapping->flags) &&
test_and_clear_bit(AS_EIO, &mapping->flags))
ret = -EIO;
效果差不多。错误检查似乎都经过filemap_check_errors
进行测试和清除:
if (test_bit(AS_EIO, &mapping->flags) &&
test_and_clear_bit(AS_EIO, &mapping->flags))
ret = -EIO;
return ret;
我在笔记本电脑上使用 btrfs
,但是当我创建 ext4
环回以在 /mnt/tmp
上进行测试并设置对其进行性能探测:
sudo dd if=/dev/zero of=/tmp/ext bs=1M count=100
sudo mke2fs -j -T ext4 /tmp/ext
sudo mount -o loop /tmp/ext /mnt/tmp
sudo perf probe filemap_check_errors
sudo perf record -g -e probe:end_buffer_async_write -e probe:filemap_check_errors dd if=/dev/zero of=/mnt/tmp/test bs=4k count=1 conv=fsync
我在 perf report -T
中找到以下调用堆栈:
---__GI___libc_fsync
entry_SYSCALL_64_fastpath
sys_fsync
do_fsync
vfs_fsync_range
ext4_sync_file
filemap_write_and_wait_range
filemap_check_errors
通读表明,是的,现代内核的行为相同。
这似乎意味着如果 fsync()
(或者可能是 write()
或 close()
)返回 -EIO
,文件在你上次成功 fsync()
d 或 close()
d 和最近一次 write( )
十个状态。
I've implemented a test case to demonstrate this behaviour .
DBMS 可以通过进入崩溃恢复来解决这个问题。一个普通的用户应用程序到底应该如何处理这个问题? fsync()
手册页没有警告它意味着“fsync-if-you-feel-like-it”,我预计很多应用程序无法处理这种行为很好。
lwn.net touched on this in the article "Improved block-layer error handling" .
关于c - 编写程序以处理导致 Linux 上丢失写入的 I/O 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42434872/
对于 Metal ,如果对主纹理进行 mipmap 处理,是否还需要对多采样纹理进行 mipmap 处理?我阅读了苹果文档,但没有得到任何相关信息。 最佳答案 Mipmapping 适用于您将从中
我正在使用的代码在后端 Groovy 代码中具有呈现 GSP(Groovy 服务器页面)的 Controller 。对于前端,我们使用 React-router v4 来处理路由。我遇到的问题是,通过
我们正在 build 一个巨大的网站。我们正在考虑是在服务器端(ASP .Net)还是在客户端进行 HTML 处理。 例如,我们有 HTML 文件,其作用类似于用于生成选项卡的模板。服务器端获取 HT
我正在尝试将图像加载到 void setup() 中的数组中,但是当我这样做时出现此错误:“类型不匹配,'processing .core.PImage' does not匹配“processing.
我正在尝试使用其私有(private)应用程序更新 Shopify 上的客户标签。我用 postman 尝试过,一切正常,但通过 AJAX,它带我成功回调而不是错误,但成功后我得到了身份验证链接,而不
如何更改我的 Processing appIconTest.exe 导出的默认图标在窗口中的应用程序? 默认一个: 最佳答案 经过一些研究,我能找到的最简单的解决方案是: 进入 ...\process
我在 Processing 中做了一个简单的小游戏,但需要一些帮助。我有一个 mp3,想将它添加到我的应用程序中,以便在后台循环运行。 这可能吗?非常感谢。 最佳答案 您可以使用声音库。处理已经自带
我有几个这样创建的按钮: 在 setup() PImage[] imgs1 = {loadImage("AREA1_1.png"),loadImage("AREA1_2.png"),loadImage
我正在尝试使用 Processing 创建一个多人游戏,但无法弄清楚如何将屏幕分成两个以显示玩家的不同情况? 就像在 c# 中一样,我们有Viewport leftViewport,rightView
我一直在尝试使用 Moore 邻域在处理过程中创建元胞自动机,到目前为止非常成功。我已经设法使基本系统正常工作,现在我希望通过添加不同的功能来使用它。现在,我检查细胞是否存活。如果是,我使用 fill
有没有办法用 JavaScript 代码检查资源使用情况?我可以检查脚本的 RAM 使用情况和 CPU 使用情况吗? 由于做某事有多种方法,我可能会使用不同的方法编写代码,并将其保存为两个不同的文件,
我想弄清楚如何处理这样的列表: [ [[4,6,7], [1,2,4,6]] , [[10,4,2,4], [1]] ] 这是一个整数列表的列表 我希望我的函数将此列表作为输入并返回列表中没有重复的整
有没有办法在不需要时处理 MethodChannel/EventChannel ?我问是因为我想为对象创建多个方法/事件 channel 。 例子: class Call { ... fields
我有一个关于在 Python3 中处理 ConnectionResetError 的问题。这通常发生在我使用 urllib.request.Request 函数时。我想知道如果我们遇到这样的错误是否可
我一直在努力解决这个问题几个小时,但无济于事。代码很简单,一个弹跳球(粒子)。将粒子的速度初始化为 (0, 0) 将使其保持上下弹跳。将粒子的初始化速度更改为 (0, 0.01) 或任何十进制浮点数都
我把自己弄得一团糟。 我想在我的系统中添加 python3.6 所以我决定在我的 Ubuntu 19.10 中卸载现有的。但是现在每次我想安装一些东西我都会得到这样的错误: dpkg: error w
我正在努力解决 Rpart 包中的 NA 功能。我得到了以下数据框(下面的代码) Outcome VarA VarB 1 1 1 0 2 1 1 1
我将 Java 与 JSF 一起使用,这是 Glassfish 3 容器。 在我的 Web 应用程序中,我试图实现一个文件(图像)管理系统。 我有一个 config.properties我从中读取上传
所以我一直在Processing工作几个星期以来,虽然我没有编程经验,但我已经转向更复杂的项目。我正在编写一个进化模拟器,它会产生具有随机属性的生物。 最终,我将添加复制,但现在这些生物只是在屏幕上漂
有人知道 Delphi 2009 对“with”的处理有什么不同吗? 我昨天解决了一个问题,只是将“with”解构为完整引用,如“with Datamodule、Dataset、MainForm”。
我是一名优秀的程序员,十分优秀!