-
Notifications
You must be signed in to change notification settings - Fork 16
Blog post on query cancellation #75
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
Conversation
I've marked this as draft for now. I think I have the narrative arc I was going for in place, but the text probably still needs some editing work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found this write-up very helpful and clear. Just a couple small typo suggestions and 1 clarifying question:
When calling `Receiver::recv` for one of these channels, a unit of Tokio task budget is consumed. | ||
As a consequence, query plans that made use of exchange-like operators were already mostly cancelable. | ||
|
||
### Depleting The Budget |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was looking for docs on poll_proceed
and made_progress
and I'm wondering if those functions have been renamed to has_budget_remaining
and consume_budget
recently? https://docs.rs/tokio/latest/tokio/task/coop/index.html#functions
Or, am I looking in the wrong place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
poll_proceed
/made_progress
are the functions Tokio itself uses to consume budget in resources like Channel
. consume_budget
is implemented using those two as well.
At the moment they're still pub(crate)
in tokio. I'm working on a PR to make them accessible at tokio-rs/tokio#7405. I wrote this post under the assumption that this will get merged. We shouldn't publish this post until that actually lands.
The DataFusion PR apache/datafusion#16398 currently contains three variants: one with the manual counter, one using has_budget_remaining
/consume_budget
as approximation, and one using poll_proceed
/made_progress
which doesn't compile just yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the context!
One other thing I'm curious about. This write-up discusses the change in terms of enabling long-running tasks to be cancelled, but would making CPU-intensive exec blocks more cooperative also help alleviate blocking IO on the main runtime if users don't set up a separate runtime ala apache/datafusion#16331? That could be a really nice benefit besides cancelability of this, if so. @alamb? |
It should make some more room for the IO indeed. Cancellation is just one facet of the more general problem of fairness in a cooperatively scheduled runtime. Yielding every now and then helps to ensure every concurrent task gets a fair share of time to run. |
A colleague of mine suggested to add some more diagrams. I know UML is out of fashion, but here's a sketch of what's actually happening when you imagine Tokio's budget is initialized to 1. Would something like this be a useful addition, or trying to cram too much information in a small space? I think it is hugely helpful (we just shouldn't call it UML to avoid getting painted with the "old folks brush" 😆 ) |
FYI @ozankabak and @zhuqi-lucas |
@@ -0,0 +1,353 @@ | |||
--- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took the liberty of pushing this "front matter" and ASF header to this post
I tried to render the blog locally to preview but found it wasn't in the blog list without this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since Datadobi is paying for my time while I work on this stuff, would it be possible/allowed to add a small note mentioning that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes of course -- we have done this on other blogs as well
Something like "Thank you to Datadobi for supporting this work" would be very much following the same pattern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great to me -- thank you @pepijnve
I am approving as I think the post could be posted as is, but of course we can also make it better.
I left a bunch of suggestions, but I also happy to help implement them if you prefer. Sorry I got carried away but I really like this post and thank you so much for writing it
## The Challenge of Cancelling Long-Running Queries | ||
|
||
Have you ever tried to cancel a query that just wouldn't stop? | ||
In this post, we'll take a look at why that can happen in DataFusion and what the community did to resolve the problem in depth. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would also help here in the intro to emphasize other learnings a potential reader might get (to convince them to read more):
- Review the async model / tokio tasks
- Learn how DataFusion uses that model for CPU bound work
- Learn how query engines in general, and DataFusion specifically implement cooperative scheduling and cancelling
So manybe something like
In this post, we'll take a look at why that can happen in DataFusion and what the community did to resolve the problem in depth. | |
In this post, we'll review how Rust's `async` model works, and how DataFusion uses that model for CPU intensive tasks and how they implement cancellation. Then we'll review some cases where queries could not be cancelled in DataFusion and what the community did to resolve the problem. |
|
||
### Understanding Rust's Async Model | ||
|
||
To really understand the cancellation problem you need to be somewhat familiar with Rust's asynchronous programming model. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To really understand the cancellation problem you need to be somewhat familiar with Rust's asynchronous programming model. | |
DataFusion, somewhat unconventionally, [uses the Rust async system and the tokio task pool](https://docs.rs/datafusion/latest/datafusion/#thread-scheduling-cpu--io-thread-pools-and-tokio-runtimes) for CPU intensive processing. | |
To really understand the the cancellation problem you need to understand the DataFusion execution model which and thus with Rust's asynchronous programming model. |
|
||
#### Futures Are Inert | ||
|
||
Rust's asynchronous programming model is built around the `Future<T>` trait. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@djanderson it may help, but I think even if the CPU intensive tasks yielded more frequently we would still need a separate runtime to avoid increasing io latnecy |
@pepijnve I pushed an Acknowedgement and "About DataFusion" sections |
Hi @pepijnve -- I wonder if you plan to work on this post in the near term? If not I will try and find time to add some diagrams / etc to help it get ready to publish (as I think it is important content) Thanks again for the work so far |
I was not planning on changing it substantially anymore. I was thinking of maybe rereading the text with a fresh pair of eyes and editing a sentence here or there, but that's it. Need to switch gears from open source contribution mode to building our own product for a bit. |
Makes sense -- thank you -- I'll do the same (with fresh eyes) and polish it up and get it ready to merge. Thank you |
I pushed the images to this post, updated the publish date to June 30 (next Monday), and started doing some wordsmiting I'll finish up my polishing today and then maybe try and highlight this draft in case others want a chance to review it. It is really neat. Thanks again @pepijnve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @pepijnve it is very nice structured
I was wondering if it makes sense to add challenges why async is challenging to cancel on low level but it probably would be noisy. But just in case this article shed the light on cancellation challenges including Rust ecosystem https://without.boats/blog/asynchronous-clean-up/ |
Man that post somewhat blew my mind (I only understood about 50% of it). |
In my opinion this article does a pretty good job explaining the issues with cancellation, but it doesn't talk about |
Wait till you read their work on Pin/Unpin. |
Thanks for the pointer. I think this would be useful as hyperlink in the intro where we're trying to say "cancelling async ain't that simple". Another useful blog post to link to might be https://cybernetist.com/2024/04/19/rust-tokio-task-cancellation-patterns/ |
If we do link to it I would link directly to https://without.boats/blog/asynchronous-clean-up/#cancellation rather than the top of the article. The idea of a 'spectrum of cooperativeness' when it comes to cancellation is a very elegant way of describing the problem. DataFusion tasks were a mix of implicitly cooperative (the Receiver users) and non-cooperative. The work that was done tries to move all tasks towards the cooperative end of the spectrum. |
@alamb I've done some work to make the diagrams a bit prettier using Excalidraw. Massaged the text a bit further. Tried to improve the flow from one section to the next. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you @pepijnve
I went through the draft again and I think it is looking REALLY nice -- something to be proud of I think I pushed one more commit with some wordsmithing obsession and new links ab0094c I can't want to publish this. It is going to be so good |
The blog is live! |
Published on Datafusion Linkedin resource |
Just read the post. Coming back here to thank everyone for the contribution! I always learn so much from these. I think it would be great to have a comment section for the blog posts. I opened #80 to discuss this idea |
Blog post describing the problem solved by and the changes made in 16398