Live data from Hacker News

Async I/O on Linux in databases

blog.canoozie.net

91–100 of 100 posts

Re: Async I/O on Linux in databases

#91

Earlier quoted context omitted.

You should prefer RWF_SYNC in case the write involves changes to the file metadata (For example, most append operations will alter the file size).

Agreed, when metadata changes are involved then RWF_SYNC must be used. RWF_DSYNC is sufficient and faster when data is overwritten without metadata changes to the file.

No that’s incorrect. File size changes caused by append are covered by fdatasync in terms of durability guarantees.

Re: Async I/O on Linux in databases

#92
1. Write intent 2. Don’t use intent write as success 3. Report success on different operation completion.

While restoring: 1. Ignore all intents 2. Use only different operations with corresponding intents.

I think this article introduces so much chaos that it’s like many „almost” helpful info on io_uring and finally hurts the tech. io_uring IMHO lacks clean and simple examples and here we again have some bad-explained theories instead of meat.

Re: Async I/O on Linux in databases

#93

Earlier quoted context omitted.

Sorry, that was a typo in my comment (now edited). "Now" was meant to be "more" i.e. "perhaps [io_uring] has more control [than sync APIs]?" Byte range is support is interesting but also present in the Linux sync API: https://man7.org/linux/man-pages/man2/sync_file_range.2.html I meant more like, perhaps it's possible to concurrently queue fsync for different writes in a way that isn't possible with the sync API. Fro…

You can insert synchronization OPs (i.e. barriers) in the queue to guarantee in-order execution.

You can also directly link submitted operations into a chain that will be executed in-order but without ordering dependencies on other operations not submitted as part of the chain.

Re: Async I/O on Linux in databases

#94
post #40

Earlier quoted context omitted.

> As I said, I don't know anything about fsync in io_uring. Maybe that has now control? io_uring fsync has byte range support: https://man7.org/linux/man-pages/man2/io_uring_enter.2.html#...

Sorry, that was a typo in my comment (now edited). "Now" was meant to be "more" i.e. "perhaps [io_uring] has more control [than sync APIs]?" Byte range is support is interesting but also present in the Linux sync API: https://man7.org/linux/man-pages/man2/sync_file_range.2.html I meant more like, perhaps it's possible to concurrently queue fsync for different writes in a way that isn't possible with the sync API. Fro…

> Byte range is support is interesting but also present in the Linux sync API: https://man7.org/linux/man-pages/man2/sync_file_range.2.html

Unfortunately, I think sync_file_range() provides much weaker guarantees than byte-range fsync() and even byte-range fdatasync().

As I understand it from historical behaviour and documentation, sync_file_range() doesn't push durability barriers down the underlying storage devices, nor does it ensure that all metadata needed to access the written pages is itself written and made durable, for example when writing to a hole in a sparse file, to the end-hole created by enlarging a file with ftruncate(), or to fallocate'd pages.

As a result, that means sync_file_range() can only be used as a performance tweak, and not for any durability guarantees that fdatasync() / fsync() are used for.

I'd be delighted to find this has improved since I last looked, but that's what I recall about sync_file_range().

Re: Async I/O on Linux in databases

#95
post #34

Earlier quoted context omitted.

Reading through the article it’s explained in the recovery process. He reads the intent log entries and the completion entries and only applies them if they both exist. So there is no guarantee that operations are committed by virtue of not being acknowledged to the application (asynchronous) the recovery replay will be consistent. I could see it would be problematic for any data where the order of operations is impo…

There's not even a guarantee that the intent log flushes to disk before the completion log. You can get completions entries in the completion log that were lost in the intent log. So, no, there's no guarantee of consistent recovery. You'd be better off with a single log.

The first part is correct, which is why during recovery transactions need to exist in both places to be applied else they are discarded (from either). If it works as stated on paper then it would give the C for consistency in recovery but of course fails at durability.

Re: Async I/O on Linux in databases

#96
post #44

Earlier quoted context omitted.

Postgres claims to have some kind of commit batching, but I couldn't figure out how to turn it on. I wanted to scrub a table by processing each row, but without holding locks, so I wanted to commit every few hundred rows, but with only ACI and not D, since I could just run the process again. I don't think Postgres supports this feature. It also seemed to be calling fsync much more than once per transaction.

Looking through the options listed under "Non-Durable Settings", [1] I guess synchronous_commit = off fits the bill? [1]: https://www.postgresql.org/docs/current/non-durability.html

Nope, Other commenter noted it:

https://www.postgresql.org/docs/current/runtime-config-wal.h...

Don't use synchronous_commit = off is durability ~= 0 (i.e. "I hope the write made it to disk")

Re: Async I/O on Linux in databases

#97
Great article -- it's really subtle to see where the real perf gains came from but will try and summarize it for those who may come after:

The gains are from batching and doing work in-between. io_uring does "batching at a distance", and the DB can write to memory and perform operations in between. When io_uring checks the queues (intent/operation), it will find more than one operation, and do them all at once.

You don't lose durability with this setup -- you just do more speculative work (if you got the worst possible crash at the worst possible time), and if a bunch of things completed (because io_uring did them all at once) you get more confirmations you can send back faster.

Latency MIGHT suffer, but throughput would (and does) increase.

Re: Async I/O on Linux in databases

#98

Earlier quoted context omitted.

Agreed, when metadata changes are involved then RWF_SYNC must be used. RWF_DSYNC is sufficient and faster when data is overwritten without metadata changes to the file.

No that’s incorrect. File size changes caused by append are covered by fdatasync in terms of durability guarantees.

It looks plausible: XFS's xfs_dio_write_end_io() updates the on-disk file size. Do you have a link to documentation that confirms this is true for Linux or POSIX filesystems?

Edit: POSIX 1003.1-2017 defines fdatasync(2) behavior in 3.384 Synchronized I/O Data Integrity Completion, where it says "For write, when the operation has been completed or diagnosed if unsuccessful. The write is complete only when the data specified in the write request is successfully transferred and all file system information required to retrieve the data is successfully transferred".

So I think POSIX does guarantee that a write at the end of the file with O_DSYNC/followed by fdatasync(2) (and therefore, Linux RWF_DSYNC) is sufficient. Thank you for pointing out that RWF_DSYNC is sufficient for appends, vlovich123!

Re: Async I/O on Linux in databases

#99
post #44

Earlier quoted context omitted.

Well, there already is slightly more fine gained control: in the sync version, you can perhaps call sync write() a few times before calling fsync() once i.e. basically batch up a few writes. That does have the disadvantage that you can't easily queue new writes while waiting for the previous ones. Perhaps you could use calls to write() in another thread while the first one is waiting for fsync() for the previous batc…

Postgres claims to have some kind of commit batching, but I couldn't figure out how to turn it on. I wanted to scrub a table by processing each row, but without holding locks, so I wanted to commit every few hundred rows, but with only ACI and not D, since I could just run the process again. I don't think Postgres supports this feature. It also seemed to be calling fsync much more than once per transaction.

> It also seemed to be calling fsync much more than once per transaction.

If it's called many more times than once per transaction the likely reason is that wal_buffers is sized small. Whenever generated WAL exceeds wal_buffers, postgres flushes the WAL, so it does not have to reopen the file later. At that point you already gotten most benefits from batching too.

Edit: A second reason is that data pages need to be written out due to cache pressure or such, and that requires the WAL to be flushed first.

Re: Async I/O on Linux in databases

#100

Earlier quoted context omitted.

Maybe I don’t understand what you’re trying to do, but you can directly control how frequently commits occur. BEGIN INSERT … —- batch of N size COMMIT AND CHAIN INSERT …

Chance of Postgres commit mapping 1:1 onto posix fsync or equivalent: slim.

Without parallelism, each commit will be at least one fdatasync (or fsync, O_SYNC/O_DSYNC write, depending on configuration). With parallelism, concurrent transaction might be flushed together, reducing the total number of fsyncs.
Post reply on HN