-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-21145][SS] Added StateStoreProviderId with queryRunId to reload StateStoreProviders when query is restarted #18355
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
|
|
||
| /** Used to identify the state store for a given operator. */ | ||
| case class OperatorStateId( | ||
| case class StatefulOperatorStateInfo( |
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.
Renamed to ***Info, so that there is less confusion with StateStoreId
| // Stop and verify whether the stores are deactivated in the coordinator | ||
| query.stop() | ||
| assert(coordRef.getLocation(providerId).isEmpty) | ||
|
|
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.
remove this line.
| } | ||
| awaitTerminationLock.notifyAll() | ||
| } | ||
| stateStoreCoordinator.deactivateInstances(terminatedQuery.runId) |
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 is the change that deactivate all the state stores related to the query thus enabling the executors to lazily unload all the related provider instances.
|
Test build #78266 has finished for PR 18355 at commit
|
|
Test build #78270 has finished for PR 18355 at commit
|
|
Test build #78317 has finished for PR 18355 at commit
|
|
Test build #3804 has finished for PR 18355 at commit
|
|
Test build #78349 has finished for PR 18355 at commit
|
|
test this please |
|
Test build #78358 has finished for PR 18355 at commit
|
|
|
||
| // Both providers should have the same StateStoreId, but the should be different objects | ||
| assert(loadedProvidersAfterRun2(0).stateStoreId === loadedProvidersAfterRun2(1).stateStoreId) | ||
| assert(loadedProvidersAfterRun2(0).hashCode !== loadedProvidersAfterRun2(1).hashCode) |
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: assert(loadedProvidersAfterRun2(0) ne loadedProvidersAfterRun2(1))
|
LGTM. Just one nit. |
|
retest this please |
|
Test build #78408 has finished for PR 18355 at commit
|
|
retest this please. |
|
Test build #78410 has finished for PR 18355 at commit
|
|
Test build #3806 has finished for PR 18355 at commit
|
|
Test build #78492 has finished for PR 18355 at commit
|
|
Merging this to master. Thank you @zsxwing for reviewing and @HyukjinKwon for suggesting the workaround to the unidoc issue. |
…d StateStoreProviders when query is restarted ## What changes were proposed in this pull request? StateStoreProvider instances are loaded on-demand in a executor when a query is started. When a query is restarted, the loaded provider instance will get reused. Now, there is a non-trivial chance, that the task of the previous query run is still running, while the tasks of the restarted run has started. So for a stateful partition, there may be two concurrent tasks related to the same stateful partition, and there for using the same provider instance. This can lead to inconsistent results and possibly random failures, as state store implementations are not designed to be thread-safe. To fix this, I have introduced a `StateStoreProviderId`, that unique identifies a provider loaded in an executor. It has the query run id in it, thus making sure that restarted queries will force the executor to load a new provider instance, thus avoiding two concurrent tasks (from two different runs) from reusing the same provider instance. Additional minor bug fixes - All state stores related to query run is marked as deactivated in the `StateStoreCoordinator` so that the executors can unload them and clear resources. - Moved the code that determined the checkpoint directory of a state store from implementation-specific code (`HDFSBackedStateStoreProvider`) to non-specific code (StateStoreId), so that implementation do not accidentally get it wrong. - Also added store name to the path, to support multiple stores per sql operator partition. *Note:* This change does not address the scenario where two tasks of the same run (e.g. speculative tasks) are concurrently running in the same executor. The chance of this very small, because ideally speculative tasks should never run in the same executor. ## How was this patch tested? Existing unit tests + new unit test. Author: Tathagata Das <tathagata.das1565@gmail.com> Closes apache#18355 from tdas/SPARK-21145.
| val env = SparkEnv.get | ||
| if (env != null) { | ||
| if (_coordRef == null) { | ||
| logInfo("Env is not null") |
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.
@tdas could you say what's the reason to add this message on the "INFO" level?
What changes were proposed in this pull request?
StateStoreProvider instances are loaded on-demand in a executor when a query is started. When a query is restarted, the loaded provider instance will get reused. Now, there is a non-trivial chance, that the task of the previous query run is still running, while the tasks of the restarted run has started. So for a stateful partition, there may be two concurrent tasks related to the same stateful partition, and there for using the same provider instance. This can lead to inconsistent results and possibly random failures, as state store implementations are not designed to be thread-safe.
To fix this, I have introduced a
StateStoreProviderId, that unique identifies a provider loaded in an executor. It has the query run id in it, thus making sure that restarted queries will force the executor to load a new provider instance, thus avoiding two concurrent tasks (from two different runs) from reusing the same provider instance.Additional minor bug fixes
StateStoreCoordinatorso that the executors can unload them and clear resources.HDFSBackedStateStoreProvider) to non-specific code (StateStoreId), so that implementation do not accidentally get it wrong.Note: This change does not address the scenario where two tasks of the same run (e.g. speculative tasks) are concurrently running in the same executor. The chance of this very small, because ideally speculative tasks should never run in the same executor.
How was this patch tested?
Existing unit tests + new unit test.