-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[Spark-20087][CORE] Attach accumulators / metrics to 'TaskKilled' end reason #21165
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
common logic in TaskRunner to reduce duplicate code
|
Ok to test |
squito
left a comment
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.
one small change, otherwise lgtm assuming tests pass
| * 3. Set the finished flag to true and clear current thread's interrupt status | ||
| */ | ||
| private def collectAccumulatorsAndResetStatusOnFailure(taskStart: Long) = { | ||
| reportGCAndExecutorTimeIfPossible(taskStart) |
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 don't think the extra reportGCAndExecutorTimeIfPossible is necessary, you can just inline it. and also the original if (task != null) is probably easier to follow than Option(task).map
| * 2. Collect accumulator updates | ||
| * 3. Set the finished flag to true and clear current thread's interrupt status | ||
| */ | ||
| private def collectAccumulatorsAndResetStatusOnFailure(taskStart: Long) = { |
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.
@squito after address your comment, do you think we should come up with a more specific method name?
| private[spark] val accums: Seq[AccumulatorV2[_, _]] = Nil) | ||
| extends TaskFailedReason { | ||
|
|
||
| override def toErrorString: String = "TaskKilled ($reason)" |
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.
s"TaskKilled ($reason)"
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.
Will do.
Didn't notice s is missing
| case exceptionFailure: ExceptionFailure => | ||
| // Nothing left to do, already handled above for accumulator updates. | ||
|
|
||
| case _: TaskKilled => |
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.
nit: combine this with the ExceptionFailure case.
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.
will do.
|
I'm not against the change, but since this changes the semantics of accumulators, we should document the changes in a migration document or something, WDYT @cloud-fan @gatorsmile ? |
|
Also, please update the PR title: |
I think documentation is necessary, will update the documentation tomorrow (Beijing time) |
|
It should be |
Thanks. Updated. |
|
I add a note for accumulator update. Please comment if more document is needed. |
|
I do agree task killed event should carry metrics update, as it's reasonable to count killed tasks for something like how many bytes were read from files. However, I don't agree user side accumulators should get updates from killed tasks, that changes the semantic of accumulators. And I don't think end-users need to care about killed tasks. Similarly, when we implement task metrics, we need to count failed tasks, but user side accumulator still skips failed tasks. I think we should also follow that approach. I haven't read the PR yet, but please make sure this patch only touches internal accumulators that are used for metrics reporting. |
I don't agree that end-user didn't care killed tasks. For example user may want to record CPU time for every task and get the total CPU time for the application. However the default behaviour should keep backward-compatibility with existing behaviour. The metadata has However we didn't expose this field to end user... |
The problem is, shall we allow end users to collect metrics via accumulators? Currently only Spark can do that via internal accumulators which count failed tasks. We need a careful API design about how to expose this ability in the end users. In the meanwhile, since we already count failed tasks, it makes sense to also count killed tasks for internal metrics collecting. We should not do these 2 things together, and to me the second one is way simpler to get in and we should do it first. |
Agreed. For the scope of this pr, let's get killed tasks's accumulators into metrics first. After that we can discuss the possibility to expose the ability under users' request.
After a second look, this part is already be handled by Task's collectAccumulatorUpdates: |
|
@jiangxb1987 @cloud-fan I think it's ready for review. |
| case class TaskKilled( | ||
| reason: String, | ||
| accumUpdates: Seq[AccumulableInfo] = Seq.empty, | ||
| private[spark] val accums: Seq[AccumulatorV2[_, _]] = Nil) |
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.
Previously we use AccumulableInfo to expose accumulator information to end users. Now AccumulatorV2 is already a public classs and we don't need to do it anymore, I think we can just do
case class TaskKilled(reason: String, accums: Seq[AccumulatorV2[_, _]])
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.
Yeah, I noticed accumUpdates: Seq[AccumulableInfo] is only used in JsonProtocol. Is that for a reason?
The current impl is constructed to be sync with existing TaskEndReason such as ExceptionFailure
@DeveloperApi
case class ExceptionFailure(
className: String,
description: String,
stackTrace: Array[StackTraceElement],
fullStackTrace: String,
private val exceptionWrapper: Option[ThrowableSerializationWrapper],
accumUpdates: Seq[AccumulableInfo] = Seq.empty,
private[spark] var accums: Seq[AccumulatorV2[_, _]] = Nil)
I'd prefer to keep in sync, leave two options for cleanup:
- leave it as it is, then cleanup with ExceptionFailure together
- Cleanup ExceptionFailure first.
@cloud-fan what do you think?
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.
let's clean up ExceptionFailure at the same time, and use only AccumulatorV2 in this PR.
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.
@cloud-fan After a second look, I don't think we can clean up ExceptionFailure unless we can break JsonProtocol
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.
now the question is: shall we keep the unnecessary Seq[AccumulableInfo] in new APIs, to make the API consistent? I'd like to not keep the Seq[AccumulableInfo], we may deprecate it in the existing APIs in the near future.
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'm ok with not keeping Seq[AccumulableInfo]. But it means inconsistent logic and api and may make future refactoring a bit difficult.
Let's see what I can do.
I'd like to not keep the Seq[AccumulableInfo], we may deprecate it in the existing APIs in the near future.
BTW, I think we have already deprecated AccumulableInfo. Unless we are planing to remove it in Spark 3.0 and Spark 3.0 is the next release, AccumulableInfo will be there for a long time
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.
Hi @cloud-fan, I have looked at how to remove Seq[AccumulableInfo] tonight.
It turns out that we cannot because JsonProtocol calls taskEndReasonFromJson to reconstruct TaskEndReasons. Since AccumulatorV2 is an abstract class, we cannot simply construct AccumulatorV2s from json.
Even we are promoting AccumulatorV2, we still need AccumulableInfo when (de)serializing json.
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 see, that makes sense, let's keep AccumulableInfo.
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.
@cloud-fan so, could you trigger the test and have a look?
And looks like I am not in the whitelist again...
|
ping @cloud-fan |
|
ok to test |
docs/rdd-programming-guide.md
Outdated
|
|
||
| </div> | ||
|
|
||
| In new version of Spark(> 2.3), the semantic of Accumulator has been changed a bit: it now includes updates from |
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.
it's not needed now
|
Test build #90585 has finished for PR 21165 at commit
|
| private def collectAccumulatorsAndResetStatusOnFailure(taskStart: Long) = { | ||
| // Report executor runtime and JVM gc time | ||
| Option(task).foreach(t => { | ||
| t.metrics.setExecutorRunTime(System.currentTimeMillis() - taskStart) |
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.
taskStartTime
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.
e, startStart is already defined previously. Do you think we need to replace all the taskStart to taskStartTime
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.
we should at least rename it in this method as it's newly added code. We can also update the existing code if it's not a lot of 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.
Will do it..
|
LGTM |
|
Test build #90595 has finished for PR 21165 at commit
|
|
Looks like that simply add fields with default values into case class will break binary compatibility. |
|
I think we can just update MimaExcludes, since it's developer API. cc @JoshRosen |
Rename taskStart -> taskStartTime in executor
|
Test build #90643 has finished for PR 21165 at commit
|
|
Gently ping @cloud-fan again. |
| val exceptionFailure = new ExceptionFailure( | ||
| new SparkException("fondue?"), | ||
| accumInfo).copy(accums = accumUpdates) | ||
| accumInfo1).copy(accums = accumUpdates1) |
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.
not caused by you but why we do a copy instead of passing accumUpdates1 to the constructor directly?
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.
We can avoid the copy call.
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.
Ah, this copy call cannot be avoided as only the 2 arguments constructor
private[spark] def this(e: Throwable, accumUpdates: Seq[AccumulableInfo]) is defined.
|
|
||
| val taskKilled = new TaskKilled( | ||
| "test", | ||
| accumInfo2).copy(accums = accumUpdates2) |
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.
ditto
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.
We can avoid this copy call
|
LGTM |
|
Test build #90891 has finished for PR 21165 at commit
|
|
retest this please |
1 similar comment
|
retest this please |
|
Test build #90901 has finished for PR 21165 at commit
|
|
thanks, merging to master! |
What changes were proposed in this pull request?
The ultimate goal is for listeners to onTaskEnd to receive metrics when a task is killed intentionally, since the data is currently just thrown away. This is already done for ExceptionFailure, so this just copies the same approach.
How was this patch tested?
Updated existing tests.
This is a rework of #17422, all credits should go to @noodle-fb