-
Notifications
You must be signed in to change notification settings - Fork 3
[MIST-1131] Implement recovery-based scale out #1137
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
Open
DifferentSC
wants to merge
6
commits into
snuspl:master
Choose a base branch
from
DifferentSC:MIST-1131
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
25c7e04
[MIST-1131] Implement recovery-based scale out
69e5bbe
Merge branch 'master' into MIST-1131
4b64010
Fix compilation error
8a24cb7
Merge branch 'master' into MIST-1131
36edb6d
Remove RecoveryStarter
c3a011b
Update app task list map when scaling-out
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
...-core/src/main/java/edu/snu/mist/core/master/lb/scaling/RecoveryBasedScaleOutManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| /* | ||
| * Copyright (C) 2018 Seoul National University | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package edu.snu.mist.core.master.lb.scaling; | ||
|
|
||
| import edu.snu.mist.core.master.ProxyToTaskMap; | ||
| import edu.snu.mist.core.master.TaskRequestor; | ||
| import edu.snu.mist.core.master.TaskStatsMap; | ||
| import edu.snu.mist.core.master.lb.AppTaskListMap; | ||
| import edu.snu.mist.core.master.lb.parameters.OverloadedTaskLoadThreshold; | ||
| import edu.snu.mist.core.master.lb.parameters.UnderloadedTaskLoadThreshold; | ||
| import edu.snu.mist.core.master.recovery.RecoveryScheduler; | ||
| import edu.snu.mist.core.master.recovery.SingleNodeRecoveryScheduler; | ||
| import edu.snu.mist.formats.avro.GroupStats; | ||
| import edu.snu.mist.formats.avro.MasterToTaskMessage; | ||
| import edu.snu.mist.formats.avro.TaskStats; | ||
| import org.apache.reef.tang.Injector; | ||
| import org.apache.reef.tang.Tang; | ||
| import org.apache.reef.tang.annotations.Parameter; | ||
|
|
||
| import javax.inject.Inject; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| /** | ||
| * The scale out manager which is implemented based on recovery process. | ||
| */ | ||
| public final class RecoveryBasedScaleOutManager implements ScaleOutManager { | ||
|
|
||
| /** | ||
| * The shared task stats map. | ||
| */ | ||
| private final TaskStatsMap taskStatsMap; | ||
|
|
||
| /** | ||
| * The shared task to proxy map. | ||
| */ | ||
| private final ProxyToTaskMap proxyToTaskMap; | ||
|
|
||
| /** | ||
| * The app task list map. | ||
| */ | ||
| private final AppTaskListMap appTaskListMap; | ||
|
|
||
| /** | ||
| * The shared task requestor to driver. | ||
| */ | ||
| private final TaskRequestor taskRequestor; | ||
|
|
||
| /** | ||
| * The overloaded task load threshold. | ||
| */ | ||
| private final double overloadedTaskLoadThreshold; | ||
|
|
||
| /** | ||
| * The underloaded task load threshold. | ||
| */ | ||
| private final double underloadedTaskLoadThreshold; | ||
|
|
||
| /** | ||
| * The single executor thread for running recovery. | ||
| */ | ||
| private final ExecutorService singleThreadedExecutorService; | ||
|
|
||
| @Inject | ||
| private RecoveryBasedScaleOutManager( | ||
| final TaskStatsMap taskStatsMap, | ||
| final ProxyToTaskMap proxyToTaskMap, | ||
| final AppTaskListMap appTaskListMap, | ||
| final TaskRequestor taskRequestor, | ||
| @Parameter(UnderloadedTaskLoadThreshold.class) final double underloadedTaskLoadThreshold, | ||
| @Parameter(OverloadedTaskLoadThreshold.class) final double overloadedTaskLoadThreshold) { | ||
| this.taskStatsMap = taskStatsMap; | ||
| this.proxyToTaskMap = proxyToTaskMap; | ||
| this.appTaskListMap = appTaskListMap; | ||
| this.taskRequestor = taskRequestor; | ||
| this.underloadedTaskLoadThreshold = underloadedTaskLoadThreshold; | ||
| this.overloadedTaskLoadThreshold = overloadedTaskLoadThreshold; | ||
| this.singleThreadedExecutorService = Executors.newSingleThreadExecutor(); | ||
| } | ||
|
|
||
| @Override | ||
| public void scaleOut() throws Exception { | ||
| // Step 1: Request a new task and setup the connection. | ||
| taskRequestor.setupTaskAndConn(1); | ||
| // Step 2: Get the groups which will be moved from overloaded tasks to the newly allocated groups. | ||
| // Our goal is to move the queries from the overloaded tasks to the newly allocated task as much as we can | ||
| // without making the new task overloaded. | ||
| final List<String> overloadedTaskList = new ArrayList<>(); | ||
| for (final Map.Entry<String, TaskStats> entry: taskStatsMap.entrySet()) { | ||
| if (entry.getValue().getTaskLoad() > overloadedTaskLoadThreshold) { | ||
| overloadedTaskList.add(entry.getKey()); | ||
| } | ||
| } | ||
| // Calculate the maximum load of the new task. | ||
| final double maximumNewTaskLoad = (underloadedTaskLoadThreshold + overloadedTaskLoadThreshold) / 2.; | ||
| final double movableGroupLoadPerTask = maximumNewTaskLoad / overloadedTaskList.size(); | ||
| final Map<String, GroupStats> movedGroupStatsMap = new HashMap<>(); | ||
| // Choose the moved groups from the overloaded tasks. | ||
| for (final String overloadedTaskId : overloadedTaskList) { | ||
| final TaskStats taskStats = taskStatsMap.get(overloadedTaskId); | ||
| final Map<String, GroupStats> groupStatsMap = taskStats.getGroupStatsMap(); | ||
|
|
||
| // Organize the group stats according to the applications. | ||
| final Map<String, List<GroupStats>> appGroupStatsMap = new HashMap<>(); | ||
| for (final Map.Entry<String, GroupStats> entry : groupStatsMap.entrySet()) { | ||
| final String appId = entry.getValue().getAppId(); | ||
| if (!appGroupStatsMap.containsKey(appId)) { | ||
| appGroupStatsMap.put(appId, new ArrayList<>()); | ||
| } | ||
| appGroupStatsMap.get(appId).add(entry.getValue()); | ||
| } | ||
|
|
||
| // Select the moved group. | ||
| final List<String> movedGroupList = new ArrayList<>(); | ||
| final int numEp = taskStats.getNumEventProcessors(); | ||
| double movedGroupLoad = 0.; | ||
| for (final Map.Entry<String, List<GroupStats>> entry : appGroupStatsMap.entrySet()) { | ||
| final String appId = entry.getKey(); | ||
| final List<GroupStats> groupStatsList = entry.getValue(); | ||
| boolean isAppCompletelyMoved = true; | ||
| for (final GroupStats groupStats : groupStatsList) { | ||
| final double effectiveGroupLoad = groupStats.getGroupLoad() / numEp; | ||
| if (movedGroupLoad + effectiveGroupLoad < movableGroupLoadPerTask) { | ||
| movedGroupStatsMap.put(groupStats.getGroupId(), groupStats); | ||
| movedGroupList.add(groupStats.getGroupId()); | ||
| movedGroupLoad += effectiveGroupLoad; | ||
| } else { | ||
| isAppCompletelyMoved = false; | ||
| } | ||
| } | ||
| if (isAppCompletelyMoved) { | ||
| // Update the AppTaskListMap if all the groups in the app are removed. | ||
| appTaskListMap.removeAppFromTask(overloadedTaskId, appId); | ||
| } else { | ||
| // No more groups to move. | ||
| break; | ||
| } | ||
| } | ||
| // Remove the stopped groups in the overloaded tasks. | ||
| final MasterToTaskMessage proxyToTask = proxyToTaskMap.get(overloadedTaskId); | ||
| proxyToTask.removeGroup(movedGroupList); | ||
| } | ||
| // Recover the moved groups into the new task using a single node recovery scheduler. | ||
| final Injector injector = Tang.Factory.getTang().newInjector(); | ||
| injector.bindVolatileInstance(TaskStatsMap.class, taskStatsMap); | ||
| injector.bindVolatileInstance(ProxyToTaskMap.class, proxyToTaskMap); | ||
| final RecoveryScheduler recoveryScheduler = injector.getInstance(SingleNodeRecoveryScheduler.class); | ||
| // Start the recovery process. | ||
| recoveryScheduler.recover(movedGroupStatsMap); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() throws Exception { | ||
| singleThreadedExecutorService.shutdown(); | ||
| singleThreadedExecutorService.awaitTermination(60000, TimeUnit.MILLISECONDS); | ||
| } | ||
| } |
31 changes: 31 additions & 0 deletions
31
mist-core/src/main/java/edu/snu/mist/core/master/lb/scaling/ScaleOutManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /* | ||
| * Copyright (C) 2018 Seoul National University | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package edu.snu.mist.core.master.lb.scaling; | ||
|
|
||
| import org.apache.reef.tang.annotations.DefaultImplementation; | ||
|
|
||
| /** | ||
| * The interface for scaling out. | ||
| */ | ||
| @DefaultImplementation(RecoveryBasedScaleOutManager.class) | ||
| public interface ScaleOutManager extends AutoCloseable { | ||
|
|
||
| /** | ||
| * Perform scale-out according to the given implementation. | ||
| * @throws Exception | ||
| */ | ||
| void scaleOut() throws Exception; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Why do we need this information?
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.
Can't we send the group load info from Task by dividing the load by the number of event processors?