Two liabilities: recovery and space
Which two liabilities does every commit build up, and what does recovery time really depend on?
Logs and undo and Group commit and fsync bought cheap commits by deferring work. The log lets you say "yes" after one sequential force and settle up later. This article is the bill arriving.
Two different liabilities build up on every commit, and most explanations mix them up:
- A recovery liability: the distance back to a point where you know how the on-disk state relates to the log. Measured in time to restart.
- A space liability: how much log you must physically keep. Measured in bytes retained.
They have different collectors and different release conditions. The central mistake is to think one pays off the other:
The guiding question: since the log is an unbounded liability that grows at the write rate, what is the cheapest way to create a recent, trustworthy starting point, and who must agree before the past may be thrown away?
The log is the only part of the system that grows in proportion to your success. Every mechanism here is a negotiation with someone who has not finished reading it yet.
The equation this article optimizes
Recovery must replay the log from the oldest record whose effect might not be on disk. So:
RTO ≈ (checkpoint_interval × log_write_rate) / replay_rateThe term that people get wrong is replay_rate. Writing the log is sequential. Redo is random reads, because each record must first fetch its page before it can be applied. On a cold buffer pool (memory just emptied by the restart), replay is limited by random page reads and can run slower than the workload that produced the log. This is the mechanism behind the old InnoDB advice that a large redo log means unusable recovery.
This asymmetry is also why ARIES recovery has three passes, not two:
- Analysis: read the log from the last checkpoint and rebuild the table of dirty pages (pages that were changed in memory but may not be on disk) and the list of transactions that were active.
- Redo: "repeat history": re-apply every logged change that the pages do not yet contain, for all transactions, even those that will be rolled back.
- Undo: roll back the transactions that had not committed ("the losers").
The analysis pass exists so that the redo pass knows which pages it will need before it starts, and can prefetch them in batches, turning random reads into something organized. Recovery speed is bought with a pass that does no recovery. During undo, each reversal is itself logged (a compensation log record, CLR) so that a crash during recovery does not undo the same change twice, and the work stays bounded.
Why redo the losers at all, if undo is about to reverse them? Undo operations, especially "physiological" ones on index pages, are defined relative to the exact state at the moment of the crash. Restoring that state first makes undo a well-defined inverse. You cannot skip redo selectively, because at redo time you do not yet know what undo will need to see. And because each CLR carries an undoNextLSN (the next record still to undo) and is never itself undone, a crash in the middle of a long rollback resumes where it stopped instead of starting over. Crashes during recovery are the normal case, not the edge case, and ARIES is the standard demonstration of designing for that.
One practical correction to the equation above: ARIES checkpoints are fuzzy, so the real bound on redo distance is the oldest dirty page, set by how far behind the background page cleaner is, not by the checkpoint interval alone. This is why tuning the background writer can move recovery time more than tuning checkpoint timeouts, and why a system under heavy write load recovers more slowly than the same system idle.
Write the equation as a ratio: recovery costs write_rate / replay_rate seconds of downtime for each second of checkpoint interval.
- time between checkpoints
- bytes of log written per second
- bytes of log replayed per second on a cold pool
Data table
| Checkpoint interval τ (seconds) | series | Recovery time |
|---|---|---|
| 30 s | log 20 MB/s, replay 10 MB/s | 60 s |
| 52.1 s | log 20 MB/s, replay 10 MB/s | 104 s |
| 74.3 s | log 20 MB/s, replay 10 MB/s | 149 s |
| 96.4 s | log 20 MB/s, replay 10 MB/s | 193 s |
| 119 s | log 20 MB/s, replay 10 MB/s | 237 s |
| 141 s | log 20 MB/s, replay 10 MB/s | 281 s |
| 163 s | log 20 MB/s, replay 10 MB/s | 326 s |
| 185 s | log 20 MB/s, replay 10 MB/s | 370 s |
| 207 s | log 20 MB/s, replay 10 MB/s | 414 s |
| 229 s | log 20 MB/s, replay 10 MB/s | 458 s |
| 251 s | log 20 MB/s, replay 10 MB/s | 503 s |
| 273 s | log 20 MB/s, replay 10 MB/s | 547 s |
| 296 s | log 20 MB/s, replay 10 MB/s | 591 s |
| 318 s | log 20 MB/s, replay 10 MB/s | 635 s |
| 340 s | log 20 MB/s, replay 10 MB/s | 680 s |
| 362 s | log 20 MB/s, replay 10 MB/s | 724 s |
| 384 s | log 20 MB/s, replay 10 MB/s | 768 s |
| 406 s | log 20 MB/s, replay 10 MB/s | 812 s |
| 428 s | log 20 MB/s, replay 10 MB/s | 857 s |
| 450 s | log 20 MB/s, replay 10 MB/s | 901 s |
| 473 s | log 20 MB/s, replay 10 MB/s | 945 s |
| 495 s | log 20 MB/s, replay 10 MB/s | 989 s |
| 517 s | log 20 MB/s, replay 10 MB/s | 1,030 s |
| 539 s | log 20 MB/s, replay 10 MB/s | 1,080 s |
| 561 s | log 20 MB/s, replay 10 MB/s | 1,120 s |
| 583 s | log 20 MB/s, replay 10 MB/s | 1,170 s |
| 605 s | log 20 MB/s, replay 10 MB/s | 1,210 s |
| 627 s | log 20 MB/s, replay 10 MB/s | 1,250 s |
| 650 s | log 20 MB/s, replay 10 MB/s | 1,300 s |
| 672 s | log 20 MB/s, replay 10 MB/s | 1,340 s |
| 694 s | log 20 MB/s, replay 10 MB/s | 1,390 s |
| 716 s | log 20 MB/s, replay 10 MB/s | 1,430 s |
| 738 s | log 20 MB/s, replay 10 MB/s | 1,480 s |
| 760 s | log 20 MB/s, replay 10 MB/s | 1,520 s |
| 782 s | log 20 MB/s, replay 10 MB/s | 1,560 s |
| 804 s | log 20 MB/s, replay 10 MB/s | 1,610 s |
| 827 s | log 20 MB/s, replay 10 MB/s | 1,650 s |
| 849 s | log 20 MB/s, replay 10 MB/s | 1,700 s |
| 871 s | log 20 MB/s, replay 10 MB/s | 1,740 s |
| 893 s | log 20 MB/s, replay 10 MB/s | 1,790 s |
| 915 s | log 20 MB/s, replay 10 MB/s | 1,830 s |
| 937 s | log 20 MB/s, replay 10 MB/s | 1,870 s |
| 959 s | log 20 MB/s, replay 10 MB/s | 1,920 s |
| 981 s | log 20 MB/s, replay 10 MB/s | 1,960 s |
| 1,000 s | log 20 MB/s, replay 10 MB/s | 2,010 s |
| 1,030 s | log 20 MB/s, replay 10 MB/s | 2,050 s |
| 1,050 s | log 20 MB/s, replay 10 MB/s | 2,100 s |
| 1,070 s | log 20 MB/s, replay 10 MB/s | 2,140 s |
| 1,090 s | log 20 MB/s, replay 10 MB/s | 2,180 s |
| 1,110 s | log 20 MB/s, replay 10 MB/s | 2,230 s |
| 1,140 s | log 20 MB/s, replay 10 MB/s | 2,270 s |
| 1,160 s | log 20 MB/s, replay 10 MB/s | 2,320 s |
| 1,180 s | log 20 MB/s, replay 10 MB/s | 2,360 s |
| 1,200 s | log 20 MB/s, replay 10 MB/s | 2,410 s |
| 1,220 s | log 20 MB/s, replay 10 MB/s | 2,450 s |
| 1,250 s | log 20 MB/s, replay 10 MB/s | 2,490 s |
| 1,270 s | log 20 MB/s, replay 10 MB/s | 2,540 s |
| 1,290 s | log 20 MB/s, replay 10 MB/s | 2,580 s |
| 1,310 s | log 20 MB/s, replay 10 MB/s | 2,630 s |
| 1,340 s | log 20 MB/s, replay 10 MB/s | 2,670 s |
| 1,360 s | log 20 MB/s, replay 10 MB/s | 2,720 s |
| 1,380 s | log 20 MB/s, replay 10 MB/s | 2,760 s |
| 1,400 s | log 20 MB/s, replay 10 MB/s | 2,800 s |
| 1,420 s | log 20 MB/s, replay 10 MB/s | 2,850 s |
| 1,450 s | log 20 MB/s, replay 10 MB/s | 2,890 s |
| 1,470 s | log 20 MB/s, replay 10 MB/s | 2,940 s |
| 1,490 s | log 20 MB/s, replay 10 MB/s | 2,980 s |
| 1,510 s | log 20 MB/s, replay 10 MB/s | 3,020 s |
| 1,530 s | log 20 MB/s, replay 10 MB/s | 3,070 s |
| 1,560 s | log 20 MB/s, replay 10 MB/s | 3,110 s |
| 1,580 s | log 20 MB/s, replay 10 MB/s | 3,160 s |
| 1,600 s | log 20 MB/s, replay 10 MB/s | 3,200 s |
| 1,620 s | log 20 MB/s, replay 10 MB/s | 3,250 s |
| 1,650 s | log 20 MB/s, replay 10 MB/s | 3,290 s |
| 1,670 s | log 20 MB/s, replay 10 MB/s | 3,330 s |
| 1,690 s | log 20 MB/s, replay 10 MB/s | 3,380 s |
| 1,710 s | log 20 MB/s, replay 10 MB/s | 3,420 s |
| 1,730 s | log 20 MB/s, replay 10 MB/s | 3,470 s |
| 1,760 s | log 20 MB/s, replay 10 MB/s | 3,510 s |
| 1,780 s | log 20 MB/s, replay 10 MB/s | 3,560 s |
| 1,800 s | log 20 MB/s, replay 10 MB/s | 3,600 s |
| 30 s | log 28 MB/s, replay 14 MB/s | 60 s |
| 52.1 s | log 28 MB/s, replay 14 MB/s | 104 s |
| 74.3 s | log 28 MB/s, replay 14 MB/s | 149 s |
| 96.4 s | log 28 MB/s, replay 14 MB/s | 193 s |
| 119 s | log 28 MB/s, replay 14 MB/s | 237 s |
| 141 s | log 28 MB/s, replay 14 MB/s | 281 s |
| 163 s | log 28 MB/s, replay 14 MB/s | 326 s |
| 185 s | log 28 MB/s, replay 14 MB/s | 370 s |
| 207 s | log 28 MB/s, replay 14 MB/s | 414 s |
| 229 s | log 28 MB/s, replay 14 MB/s | 458 s |
| 251 s | log 28 MB/s, replay 14 MB/s | 503 s |
| 273 s | log 28 MB/s, replay 14 MB/s | 547 s |
| 296 s | log 28 MB/s, replay 14 MB/s | 591 s |
| 318 s | log 28 MB/s, replay 14 MB/s | 635 s |
| 340 s | log 28 MB/s, replay 14 MB/s | 680 s |
| 362 s | log 28 MB/s, replay 14 MB/s | 724 s |
| 384 s | log 28 MB/s, replay 14 MB/s | 768 s |
| 406 s | log 28 MB/s, replay 14 MB/s | 812 s |
| 428 s | log 28 MB/s, replay 14 MB/s | 857 s |
| 450 s | log 28 MB/s, replay 14 MB/s | 901 s |
| 473 s | log 28 MB/s, replay 14 MB/s | 945 s |
| 495 s | log 28 MB/s, replay 14 MB/s | 989 s |
| 517 s | log 28 MB/s, replay 14 MB/s | 1,030 s |
| 539 s | log 28 MB/s, replay 14 MB/s | 1,080 s |
| 561 s | log 28 MB/s, replay 14 MB/s | 1,120 s |
| 583 s | log 28 MB/s, replay 14 MB/s | 1,170 s |
| 605 s | log 28 MB/s, replay 14 MB/s | 1,210 s |
| 627 s | log 28 MB/s, replay 14 MB/s | 1,250 s |
| 650 s | log 28 MB/s, replay 14 MB/s | 1,300 s |
| 672 s | log 28 MB/s, replay 14 MB/s | 1,340 s |
| 694 s | log 28 MB/s, replay 14 MB/s | 1,390 s |
| 716 s | log 28 MB/s, replay 14 MB/s | 1,430 s |
| 738 s | log 28 MB/s, replay 14 MB/s | 1,480 s |
| 760 s | log 28 MB/s, replay 14 MB/s | 1,520 s |
| 782 s | log 28 MB/s, replay 14 MB/s | 1,560 s |
| 804 s | log 28 MB/s, replay 14 MB/s | 1,610 s |
| 827 s | log 28 MB/s, replay 14 MB/s | 1,650 s |
| 849 s | log 28 MB/s, replay 14 MB/s | 1,700 s |
| 871 s | log 28 MB/s, replay 14 MB/s | 1,740 s |
| 893 s | log 28 MB/s, replay 14 MB/s | 1,790 s |
| 915 s | log 28 MB/s, replay 14 MB/s | 1,830 s |
| 937 s | log 28 MB/s, replay 14 MB/s | 1,870 s |
| 959 s | log 28 MB/s, replay 14 MB/s | 1,920 s |
| 981 s | log 28 MB/s, replay 14 MB/s | 1,960 s |
| 1,000 s | log 28 MB/s, replay 14 MB/s | 2,010 s |
| 1,030 s | log 28 MB/s, replay 14 MB/s | 2,050 s |
| 1,050 s | log 28 MB/s, replay 14 MB/s | 2,100 s |
| 1,070 s | log 28 MB/s, replay 14 MB/s | 2,140 s |
| 1,090 s | log 28 MB/s, replay 14 MB/s | 2,180 s |
| 1,110 s | log 28 MB/s, replay 14 MB/s | 2,230 s |
| 1,140 s | log 28 MB/s, replay 14 MB/s | 2,270 s |
| 1,160 s | log 28 MB/s, replay 14 MB/s | 2,320 s |
| 1,180 s | log 28 MB/s, replay 14 MB/s | 2,360 s |
| 1,200 s | log 28 MB/s, replay 14 MB/s | 2,410 s |
| 1,220 s | log 28 MB/s, replay 14 MB/s | 2,450 s |
| 1,250 s | log 28 MB/s, replay 14 MB/s | 2,490 s |
| 1,270 s | log 28 MB/s, replay 14 MB/s | 2,540 s |
| 1,290 s | log 28 MB/s, replay 14 MB/s | 2,580 s |
| 1,310 s | log 28 MB/s, replay 14 MB/s | 2,630 s |
| 1,340 s | log 28 MB/s, replay 14 MB/s | 2,670 s |
| 1,360 s | log 28 MB/s, replay 14 MB/s | 2,720 s |
| 1,380 s | log 28 MB/s, replay 14 MB/s | 2,760 s |
| 1,400 s | log 28 MB/s, replay 14 MB/s | 2,800 s |
| 1,420 s | log 28 MB/s, replay 14 MB/s | 2,850 s |
| 1,450 s | log 28 MB/s, replay 14 MB/s | 2,890 s |
| 1,470 s | log 28 MB/s, replay 14 MB/s | 2,940 s |
| 1,490 s | log 28 MB/s, replay 14 MB/s | 2,980 s |
| 1,510 s | log 28 MB/s, replay 14 MB/s | 3,020 s |
| 1,530 s | log 28 MB/s, replay 14 MB/s | 3,070 s |
| 1,560 s | log 28 MB/s, replay 14 MB/s | 3,110 s |
| 1,580 s | log 28 MB/s, replay 14 MB/s | 3,160 s |
| 1,600 s | log 28 MB/s, replay 14 MB/s | 3,200 s |
| 1,620 s | log 28 MB/s, replay 14 MB/s | 3,250 s |
| 1,650 s | log 28 MB/s, replay 14 MB/s | 3,290 s |
| 1,670 s | log 28 MB/s, replay 14 MB/s | 3,330 s |
| 1,690 s | log 28 MB/s, replay 14 MB/s | 3,380 s |
| 1,710 s | log 28 MB/s, replay 14 MB/s | 3,420 s |
| 1,730 s | log 28 MB/s, replay 14 MB/s | 3,470 s |
| 1,760 s | log 28 MB/s, replay 14 MB/s | 3,510 s |
| 1,780 s | log 28 MB/s, replay 14 MB/s | 3,560 s |
| 1,800 s | log 28 MB/s, replay 14 MB/s | 3,600 s |
| 30 s | log 10 MB/s, replay 40 MB/s | 7.5 s |
| 52.1 s | log 10 MB/s, replay 40 MB/s | 13 s |
| 74.3 s | log 10 MB/s, replay 40 MB/s | 18.6 s |
| 96.4 s | log 10 MB/s, replay 40 MB/s | 24.1 s |
| 119 s | log 10 MB/s, replay 40 MB/s | 29.6 s |
| 141 s | log 10 MB/s, replay 40 MB/s | 35.2 s |
| 163 s | log 10 MB/s, replay 40 MB/s | 40.7 s |
| 185 s | log 10 MB/s, replay 40 MB/s | 46.2 s |
| 207 s | log 10 MB/s, replay 40 MB/s | 51.8 s |
| 229 s | log 10 MB/s, replay 40 MB/s | 57.3 s |
| 251 s | log 10 MB/s, replay 40 MB/s | 62.8 s |
| 273 s | log 10 MB/s, replay 40 MB/s | 68.3 s |
| 296 s | log 10 MB/s, replay 40 MB/s | 73.9 s |
| 318 s | log 10 MB/s, replay 40 MB/s | 79.4 s |
| 340 s | log 10 MB/s, replay 40 MB/s | 84.9 s |
| 362 s | log 10 MB/s, replay 40 MB/s | 90.5 s |
| 384 s | log 10 MB/s, replay 40 MB/s | 96 s |
| 406 s | log 10 MB/s, replay 40 MB/s | 102 s |
| 428 s | log 10 MB/s, replay 40 MB/s | 107 s |
| 450 s | log 10 MB/s, replay 40 MB/s | 113 s |
| 473 s | log 10 MB/s, replay 40 MB/s | 118 s |
| 495 s | log 10 MB/s, replay 40 MB/s | 124 s |
| 517 s | log 10 MB/s, replay 40 MB/s | 129 s |
| 539 s | log 10 MB/s, replay 40 MB/s | 135 s |
| 561 s | log 10 MB/s, replay 40 MB/s | 140 s |
| 583 s | log 10 MB/s, replay 40 MB/s | 146 s |
| 605 s | log 10 MB/s, replay 40 MB/s | 151 s |
| 627 s | log 10 MB/s, replay 40 MB/s | 157 s |
| 650 s | log 10 MB/s, replay 40 MB/s | 162 s |
| 672 s | log 10 MB/s, replay 40 MB/s | 168 s |
| 694 s | log 10 MB/s, replay 40 MB/s | 173 s |
| 716 s | log 10 MB/s, replay 40 MB/s | 179 s |
| 738 s | log 10 MB/s, replay 40 MB/s | 185 s |
| 760 s | log 10 MB/s, replay 40 MB/s | 190 s |
| 782 s | log 10 MB/s, replay 40 MB/s | 196 s |
| 804 s | log 10 MB/s, replay 40 MB/s | 201 s |
| 827 s | log 10 MB/s, replay 40 MB/s | 207 s |
| 849 s | log 10 MB/s, replay 40 MB/s | 212 s |
| 871 s | log 10 MB/s, replay 40 MB/s | 218 s |
| 893 s | log 10 MB/s, replay 40 MB/s | 223 s |
| 915 s | log 10 MB/s, replay 40 MB/s | 229 s |
| 937 s | log 10 MB/s, replay 40 MB/s | 234 s |
| 959 s | log 10 MB/s, replay 40 MB/s | 240 s |
| 981 s | log 10 MB/s, replay 40 MB/s | 245 s |
| 1,000 s | log 10 MB/s, replay 40 MB/s | 251 s |
| 1,030 s | log 10 MB/s, replay 40 MB/s | 256 s |
| 1,050 s | log 10 MB/s, replay 40 MB/s | 262 s |
| 1,070 s | log 10 MB/s, replay 40 MB/s | 267 s |
| 1,090 s | log 10 MB/s, replay 40 MB/s | 273 s |
| 1,110 s | log 10 MB/s, replay 40 MB/s | 279 s |
| 1,140 s | log 10 MB/s, replay 40 MB/s | 284 s |
| 1,160 s | log 10 MB/s, replay 40 MB/s | 290 s |
| 1,180 s | log 10 MB/s, replay 40 MB/s | 295 s |
| 1,200 s | log 10 MB/s, replay 40 MB/s | 301 s |
| 1,220 s | log 10 MB/s, replay 40 MB/s | 306 s |
| 1,250 s | log 10 MB/s, replay 40 MB/s | 312 s |
| 1,270 s | log 10 MB/s, replay 40 MB/s | 317 s |
| 1,290 s | log 10 MB/s, replay 40 MB/s | 323 s |
| 1,310 s | log 10 MB/s, replay 40 MB/s | 328 s |
| 1,340 s | log 10 MB/s, replay 40 MB/s | 334 s |
| 1,360 s | log 10 MB/s, replay 40 MB/s | 339 s |
| 1,380 s | log 10 MB/s, replay 40 MB/s | 345 s |
| 1,400 s | log 10 MB/s, replay 40 MB/s | 350 s |
| 1,420 s | log 10 MB/s, replay 40 MB/s | 356 s |
| 1,450 s | log 10 MB/s, replay 40 MB/s | 362 s |
| 1,470 s | log 10 MB/s, replay 40 MB/s | 367 s |
| 1,490 s | log 10 MB/s, replay 40 MB/s | 373 s |
| 1,510 s | log 10 MB/s, replay 40 MB/s | 378 s |
| 1,530 s | log 10 MB/s, replay 40 MB/s | 384 s |
| 1,560 s | log 10 MB/s, replay 40 MB/s | 389 s |
| 1,580 s | log 10 MB/s, replay 40 MB/s | 395 s |
| 1,600 s | log 10 MB/s, replay 40 MB/s | 400 s |
| 1,620 s | log 10 MB/s, replay 40 MB/s | 406 s |
| 1,650 s | log 10 MB/s, replay 40 MB/s | 411 s |
| 1,670 s | log 10 MB/s, replay 40 MB/s | 417 s |
| 1,690 s | log 10 MB/s, replay 40 MB/s | 422 s |
| 1,710 s | log 10 MB/s, replay 40 MB/s | 428 s |
| 1,730 s | log 10 MB/s, replay 40 MB/s | 433 s |
| 1,760 s | log 10 MB/s, replay 40 MB/s | 439 s |
| 1,780 s | log 10 MB/s, replay 40 MB/s | 444 s |
| 1,800 s | log 10 MB/s, replay 40 MB/s | 450 s |