mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-10 23:12:54 +00:00
fix(l0_flush): drops permit before fsync, potential cause for OOMs (#8327)
## Problem Slack thread: https://neondb.slack.com/archives/C033RQ5SPDH/p1720511577862519 We're seeing OOMs in staging on a pageserver that has l0_flush.mode=Direct enabled. There's a strong correlation between jumps in `maxrss_kb` and `pageserver_timeline_ephemeral_bytes`, so, it's quite likely that l0_flush.mode=Direct is the culprit. Notably, the expected max memory usage on that staging server by the l0_flush.mode=Direct is ~2GiB but we're seeing as much as 24GiB max RSS before the OOM kill. One hypothesis is that we're dropping the semaphore permit before all the dirtied pages have been flushed to disk. (The flushing to disk likely happens in the fsync inside the `.finish()` call, because we're using ext4 in data=ordered mode). ## Summary of changes Hold the permit until after we're done with `.finish()`.
This commit is contained in:
committed by
GitHub
parent
3f7aebb01c
commit
9bb16c8780
@@ -715,16 +715,22 @@ impl InMemoryLayer {
|
||||
res?;
|
||||
}
|
||||
}
|
||||
|
||||
// Hold the permit until the IO is done; if we didn't, one could drop this future,
|
||||
// thereby releasing the permit, but the Vec<u8> remains allocated until the IO completes.
|
||||
// => we'd have more concurrenct Vec<u8> than allowed as per the semaphore.
|
||||
drop(_concurrency_permit);
|
||||
}
|
||||
}
|
||||
|
||||
// MAX is used here because we identify L0 layers by full key range
|
||||
let delta_layer = delta_layer_writer.finish(Key::MAX, timeline, ctx).await?;
|
||||
|
||||
// Hold the permit until all the IO is done, including the fsync in `delta_layer_writer.finish()``.
|
||||
//
|
||||
// If we didn't and our caller drops this future, tokio-epoll-uring would extend the lifetime of
|
||||
// the `file_contents: Vec<u8>` until the IO is done, but not the permit's lifetime.
|
||||
// Thus, we'd have more concurrenct `Vec<u8>` in existence than the semaphore allows.
|
||||
//
|
||||
// We hold across the fsync so that on ext4 mounted with data=ordered, all the kernel page cache pages
|
||||
// we dirtied when writing to the filesystem have been flushed and marked !dirty.
|
||||
drop(_concurrency_permit);
|
||||
|
||||
Ok(Some(delta_layer))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user