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
Cancellation of divergent recursive dataflows #16800
Comments
That would be a great incentive to build confidence on I had put up a PR for this recently but we didn't want to potentially introduce further instability to the system because |
An More generally .. though I'm sure also more frighteningly .. this could just be a temporal filter on round of iteration, which DD supports also (well, manipulation of the timestamp component, which is what temporal filters end up being). |
Summarizing some offline discussion with @antiguru. It seems that we have two options for the frontend.
I'm leaning towards option (2) - the @frankmcsherry I'm interested in your opinion here. |
The first option seems the best to me (although I can't tell if the second option allows an |
To summarize:
|
I'll work now on option 1. from above, i.e., adding an optional clause to This will reduce the problem of divergent dataflows, but it won't completely go away: Maybe the user doesn't specify this extra clause, and then she still ends up with a problematic dataflow that continues to be alive indefinitely. So we'll also want to work on properly cancelling the dataflows when the associated index and/or view is dropped. Edit: This seems to be #2392 |
This we could work-around by having a reasonable default value, either hardcoded, or a session variable. |
Well, I'm not sure what value we would to set. The problem is that a good default value might be wildly different for different queries. A query that works with only small datasets might do thousands of iterations in a minute, but a query that is working with large datasets could run essentially forever even with tens of iterations. (Also, there are queries where even though the initial dataset is large and the first few iterations do a lot of work, there are still many iterations with small deltas.) So, I would be worried that having a non-infinite default value would bite some users, who don't realize that the default is not infinite, but at the same time wouldn't help some other users, whose queries would still run for a long time. Btw. I'm not sure I fully understand why this problem is specific to WMR. Any query might take a very long time to complete, e.g., if a cross join surprisingly appears in a plan when a user forgets a join condition. Is the idea that in many of those situations, the query will OOM after a not very large amount of time anyway? Is this somehow less the case for WMR? Another question: Does the problem come up only for VIEW dropping, or does it also happen with a SELECT? So, for a SELECT, does the dataflow go away if I hit Ctrl+C? Edit: It seems to me SELECT also has the same problem. |
Btw. it would be great to print a notice to the user when the limit is reached. Then we could set a relatively lower default. But I'm not sure whether we have the infrastructure for this. |
I'm not sure that #2392 is the right mechanism to prevent divergent dataflows. Recursive queries have memory requirements proportional to the trace, which means that we might OOM faster than the user has a chance to react. Limiting the number of recursions might help here.
Currently, we let the computation finish, however long this might take. In the future, we might be able to uninstall the dataflows, but I'd prefer if we don't introduce this as a hard dependency. I agree we have to think a bit more about this because we're mixing a product and an engineering question. I think it makes sense to have the infrastructure in place to set a limit on iterations and to have an optional global limit (or set the default to u64::MAX). We can then think about setting a default value and how to communicate it to users with product.
Yep, this would be nice, but I don't think we have a way to communicate notices from the dataflow layer, only errors, but that's not what we'd like to have here. |
Btw. one more complication is that if we have a per-WMR limit, then we will need to change |
@ggevay one nit: it's important to prevent users from saying: WITH MUTUALLY RECURSIVE LIMIT 0 The current semantics of WMR blocks are of a do { /* sequential updates */ } while /* no change*/ and I can imagine that the code of some optimizations will get unnecessary complicated if we want to handle the |
Well, I think OOMing would often be a better situation than either silently stopping after a default limit or running forever:
Also note that when a user is developing a query, she should always run her experimental queries on such a cluster that is ok to suddenly crash, because queries can suddenly OOM due to a wide range of user mistakes (also unrelated to WMR). Nevertheless, I think we need to have both Both of these are good for mitigating the effect of divergent WMRs at least in some cases (e.g., A. is good if the user explicitly sets some nice limit, and B. is good when the WMR is running forever, but somehow not OOMing, e.g., Marcos' query in the issue decription), and both of these are also good for certain things other than divergent WMRs. (E.g., A. is good for output debugging after each WMR iteration, and B. is good for terminating bad queries that don't even have WMR.) So I'll go ahead with implementing the limit. I'm still not sure whether we should have a default limit, but we can decide this later (with Product in the loop (@heeringa)). Maybe some large number, e.g., 1000? Or we wait until we can show notices to the user?
Do we have an issue for it at least? |
It seems that we are proposing various solution with two overlapping goals in mind:
We might decide that we use the same solution for both or use two separate solutions. Let's use this issue to track (1) and #18362 to track (2). |
Yes, we might want to have two limits: a soft limit for 2. and a hard limit that errors out for 1. Note that 1. is easier, because it's ok if the limit setting is per-query (and/or a session variable), whereas for 2. it would be useful to have it per-WMR. I'll implement 1. first, because that seems to be the most pressing matter. Then we can do 2. soon afterwards, possibly in two steps:
|
I added a comment in #18362 with a straight-forward way to emulate (2) in SQL using mechanic changes to an existing WMR query. It could be that this solution is more robust w.r.t. the |
This is great, @aalexandrov, thank you very much! Then I'll go for 1., and put aside my |
Yes, will do, thanks for the reminder! |
Indeed, if that lands, that would mostly address this issue. But unfortunately we don't know when that will land. It might turn out to be a very long time, because it might require tricky fixes in Timely and/or Differential, and Frank is very busy nowadays. Maybe if a very thorough testing finds that it works well, then it might go in without too much involvement from Frank. In the meantime, I'm working on iteration limits as an alternative fix, because there are also other use cases for limits besides stopping divergent dataflows anyway, as explained in the design doc. |
I plan to put up a design doc in the next days to propose some alternate ways of shutting down dataflows as long as we don't yet have |
I wanted to propose the same thing, it sounds like the easiest thing to do with our existing token infrastructure. The implementation was only a few lines of code so I pushed it here #18718 |
#18718 is merged now, so divergent WMR dataflows are cancelled as one would expect. @ggevay @aalexandrov I suggest we close this issue here as complete. If we still want a hard limit (we might not?) we should open a separate ticket to track that specifically. |
Thanks a lot @teskje and @petrosagg! We'll discuss the hard limit later when @antiguru comes back. (I think he mentioned it to me once that a default hard limit might be desirable even if we have dataflow cancellation.) I opened an issue: #18832. |
In PR #16787, it has been observed that if we render a divergent dataflow, it keeps on executing even if the corresponding view and indexes associated to it are dropped. We should think of a way to handle cancellation of dataflows that are non-terminating.
Here is an example of how to reproduce the issue:
Now, in the memory visualizer, it is possible to see that the dataflow continues to be alive and producing ever increasing numbers of records.
The text was updated successfully, but these errors were encountered: