Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run Layer::get_value_reconstruct_data in spawn_blocking #4498

Conversation

problame
Copy link
Contributor

@problame problame commented Jun 13, 2023

This PR concludes the "async Layer::get_value_reconstruct_data" project.

The problem we're solving is that, before this patch, we'd execute Layer::get_value_reconstruct_data on the tokio executor threads.
This function is IO- and/or CPU-intensive.
The IO is using VirtualFile / std::fs; hence it's blocking.
This results in unfairness towards other tokio tasks, especially under (disk) load.

Some context can be found at #4154
where I suspect (but can't prove) load spikes of logical size calculation to
cause heavy eviction skew.

Sadly we don't have tokio runtime/scheduler metrics to quantify the unfairness.
But generally, we know blocking the executor threads on std::fs IO is bad.
So, let's have this change and watch out for severe perf regressions in staging & during rollout.

Changes

  • rename Layer::get_value_reconstruct_data to Layer::get_value_reconstruct_data_blocking
  • add a new blanket impl'd Layer::get_value_reconstruct_data async_trait method that runs get_value_reconstruct_data_blocking inside spawn_blocking.
  • The spawn_blocking requires 'static lifetime of the captured variables; hence I had to change the data flow to move the ValueReconstructState into and back out of get_value_reconstruct_data instead of passing a reference. It's a small struct, so I don't expect a big performance penalty.

Performance

Fundamentally, the code changes cause the following performance-relevant changes:

  • Latency & allocations: each get_value_reconstruct_data call now makes a short-lived allocation because async_trait is just sugar for boxed futures under the hood
  • Latency: spawn_blocking adds some latency because it needs to move the work to a thread pool
    • using spawn_blocking plus the existing synchronous code inside is probably more efficient better than switching all the synchronous code to tokio::fs because each tokio::fs call does spawn_blocking under the hood.
  • Throughput: the spawn_blocking thread pool is much larger than the async executor thread pool. Hence, as long as the disks can keep up, which they should according to AWS specs, we will be able to deliver higher get_value_reconstruct_data throughput.
  • Disk IOPS utilization: we will see higher disk utilization if we get more throughput. Not a problem because the disks in prod are currently under-utilized, according to node_exporter metrics & the AWS specs.
  • CPU utilization: at higher throughput, CPU utilization will be higher.

Slightly higher latency under regular load is acceptable given the throughput gains and expected better fairness during disk load peaks, such as logical size calculation peaks uncovered in #4154.

Full Stack Of Preliminary PRs

This PR builds on top of the following preliminary PRs

  1. Clean-ups
  1. Don't hold timelines lock over load layer map #4364
  2. make Delta{Value,Key}Iter Send #4472
  3. refactor check_checkpoint_distance to prepare for async Timeline::layers #4476
  4. make TimelineWriter Send by using tokio::sync Mutex internally #4477
  5. init_empty_layer_map: use try_write #4485
  6. turn Timeline::layers into tokio::sync::RwLock #4441

@problame problame requested a review from skyzh June 13, 2023 18:09
@skyzh
Copy link
Member

skyzh commented Jun 13, 2023

I would prefer merge and observe the performance difference in prod/staging at some time

@github-actions
Copy link

github-actions bot commented Jun 13, 2023

1016 tests run: 974 passed, 0 failed, 42 skipped (full report)


Flaky tests (1)

Postgres 14

  • test_crafted_wal_end[last_wal_record_crossing_segment]: ✅ debug
The comment gets automatically updated with the latest test results
9afb589 at 2023-06-23T15:00:04.219Z :recycle:

@problame problame requested review from shanyp and LizardWizzard June 14, 2023 09:17
@problame problame marked this pull request as ready for review June 14, 2023 09:40
@problame problame requested review from a team as code owners June 14, 2023 09:40
@problame problame requested review from fprasx and removed request for a team and fprasx June 14, 2023 09:40
Copy link
Contributor

@LizardWizzard LizardWizzard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Minor nits. Note there is run_benchmarks label so you can run benchmarks before merging. I havent used it but some people did.

Two comments point to possible optimizations, feel free to close them (we can get back to them later if needed).

pageserver/src/tenant/storage_layer.rs Show resolved Hide resolved
pageserver/src/tenant/storage_layer.rs Show resolved Hide resolved
pageserver/src/tenant/storage_layer/image_layer.rs Outdated Show resolved Hide resolved
pageserver/src/tenant/storage_layer/inmemory_layer.rs Outdated Show resolved Hide resolved
@problame problame added the run-benchmarks Indicates to the CI that benchmarks should be run for PR marked with this label label Jun 14, 2023
@problame problame enabled auto-merge (squash) June 14, 2023 17:05
…ne-get/get-value-reconstruct-data-spawn-blocking
@problame problame disabled auto-merge June 15, 2023 12:20
problame added 2 commits June 16, 2023 16:55
…ne-get/get-value-reconstruct-data-spawn-blocking
…ne-get/get-value-reconstruct-data-spawn-blocking
@problame problame removed the run-benchmarks Indicates to the CI that benchmarks should be run for PR marked with this label label Jun 23, 2023
@problame problame merged commit 1faf69a into main Jun 26, 2023
@problame problame deleted the problame/async-timeline-get/get-value-reconstruct-data-spawn-blocking branch June 26, 2023 09:43
shanyp added a commit that referenced this pull request Jun 27, 2023
shanyp added a commit that referenced this pull request Jun 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants