如何有效检测rust中的磁盘不足错误(sync_all非常慢)

问题描述 投票:0回答:1

我有一个用 Rust 编写的云服务,它对 NFS 进行大量写入。我们注意到,在 NFS 暂存磁盘已满的[可怕]情况下,服务器没有收到此错误的通知。

阅读 Rust 文档,这似乎是预料之中的,答案是调用

sync_all
,这将返回磁盘错误:https://doc.rust-lang.org/std/fs/struct.File.html

他们说“文件超出范围时会自动关闭。Drop 的实现会忽略关闭时检测到的错误。如果必须手动处理这些错误,请使用sync_all 方法。”

所以这是可行的,但是,添加

sync_all
带来的性能下降是业务无法接受的。考虑到使用情况,变化是巨大的。例如,过去需要 5 秒的事情现在只需 25 秒。我估计在本地 SSD 上调用
sync_all
会增加 5 毫秒到 10 毫秒之间的时间。

所以我正在寻找替代解决方案,而不仅仅是打电话

sync_all
。是否有另一种快速检查磁盘空间不足错误的方法?

文档提到 Drop 的实现会忽略关闭时的错误。我可以提供一个不支持的自定义实现吗?我该怎么办呢?

rust cloud nfs disk
1个回答
0
投票

这在很大程度上取决于您的实际要求,但一种可能的解决方案可能是在带外执行

sync_all
,这样您的直接工作就不会受到阻碍,但在某些时候您仍然会收到错误:

pub fn out_of_SeqCstband_cleanup(writes: usize) {
    let keep_on = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
    let (input, out) = std::sync::mpsc::channel::<std::fs::File>();
    let cleanup = std::thread::spawn({
        let keep_on = std::sync::Arc::clone(&keep_on);
        move || {
            while let Ok(f) = out.recv() {
                if dbg!(f.sync_all()).is_err() {
                    // signal that an error occured, the main thread should now stop trying to write
                    keep_on.store(false, std::sync::atomic::Ordering::SeqCst);
                }
            }
        }
    });
    for i in 0..writes {
        if !keep_on.load(std::sync::atomic::Ordering::SeqCst) {
            break;
        }
        let mut f = std::fs::File::create(format!("{i}.txt")).unwrap();
        // fake some work that is being done
        #[allow(deprecated)] std::thread::sleep_ms(5);
        write!(f, "hello").unwrap();
        input.send(f).unwrap();
    }
    drop(input);
    cleanup.join().unwrap();
}

缺点是您无法立即知道光盘已满,但可能只有在您尝试写入更多文件后才能知道。
另一件需要注意的事情是,如果写入是瓶颈,则可能会无限期地增加通道(或者在某个时刻绑定通道最终会再次等待内联)。

Playground 上的粗略迷你基准测试

© www.soinside.com 2019 - 2024. All rights reserved.