All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.runtime.resourcemanager.slotmanager.DefaultResourceAllocationStrategy Maven / Gradle / Ivy

There is a newer version: 1.19.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.flink.runtime.resourcemanager.slotmanager;

import org.apache.flink.api.common.JobID;
import org.apache.flink.runtime.blocklist.BlockedTaskManagerChecker;
import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
import org.apache.flink.runtime.slots.ResourceRequirement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

import static org.apache.flink.runtime.resourcemanager.slotmanager.SlotManagerUtils.getEffectiveResourceProfile;

/**
 * The default implementation of {@link ResourceAllocationStrategy}.
 *
 * 

For each requirement, this strategy tries to fulfill it with any registered or pending * resources (registered is prioritized). If a requirement cannot be fulfilled by any registered or * pending resources, it allocates a new pending resource, with the pre-defined total and default * slot resource profiles, thus all new pending resources should have the same profiles. A * requirement is considered unfulfillable if it is not fulfilled by any registered or pending * resources and cannot fit into the pre-defined total resource profile. * *

Note: This strategy tries to find a feasible allocation result, rather than an optimal one (in * term of resource utilization). It also does not guarantee always finding a feasible solution when * exist. * *

Note: The current implementation of this strategy is non-optimal, in terms of computation * efficiency. In the worst case, for each distinctly profiled requirement it checks all registered * and pending resources. Further optimization requires complex data structures for ordering * multi-dimensional resource profiles. The complexity is not necessary. */ public class DefaultResourceAllocationStrategy implements ResourceAllocationStrategy { private final ResourceProfile defaultSlotResourceProfile; private final ResourceProfile totalResourceProfile; private final int numSlotsPerWorker; public DefaultResourceAllocationStrategy( ResourceProfile totalResourceProfile, int numSlotsPerWorker) { this.totalResourceProfile = totalResourceProfile; this.numSlotsPerWorker = numSlotsPerWorker; this.defaultSlotResourceProfile = SlotManagerUtils.generateDefaultSlotResourceProfile( totalResourceProfile, numSlotsPerWorker); } @Override public ResourceAllocationResult tryFulfillRequirements( Map> missingResources, TaskManagerResourceInfoProvider taskManagerResourceInfoProvider, BlockedTaskManagerChecker blockedTaskManagerChecker) { final ResourceAllocationResult.Builder resultBuilder = ResourceAllocationResult.builder(); final List registeredResources = getAvailableResources( taskManagerResourceInfoProvider, resultBuilder, blockedTaskManagerChecker); final List pendingResources = getPendingResources(taskManagerResourceInfoProvider, resultBuilder); for (Map.Entry> resourceRequirements : missingResources.entrySet()) { final JobID jobId = resourceRequirements.getKey(); final Collection unfulfilledJobRequirements = tryFulfillRequirementsForJobWithResources( jobId, resourceRequirements.getValue(), registeredResources); if (!unfulfilledJobRequirements.isEmpty()) { tryFulfillRequirementsForJobWithPendingResources( jobId, unfulfilledJobRequirements, pendingResources, resultBuilder); } } return resultBuilder.build(); } private static List getAvailableResources( TaskManagerResourceInfoProvider taskManagerResourceInfoProvider, ResourceAllocationResult.Builder resultBuilder, BlockedTaskManagerChecker blockedTaskManagerChecker) { return taskManagerResourceInfoProvider.getRegisteredTaskManagers().stream() .filter( taskManager -> !blockedTaskManagerChecker.isBlockedTaskManager( taskManager.getTaskExecutorConnection().getResourceID())) .map( taskManager -> new InternalResourceInfo( taskManager.getDefaultSlotResourceProfile(), taskManager.getAvailableResource(), (jobId, slotProfile) -> resultBuilder.addAllocationOnRegisteredResource( jobId, taskManager.getInstanceId(), slotProfile))) .collect(Collectors.toList()); } private static List getPendingResources( TaskManagerResourceInfoProvider taskManagerResourceInfoProvider, ResourceAllocationResult.Builder resultBuilder) { return taskManagerResourceInfoProvider.getPendingTaskManagers().stream() .map( pendingTaskManager -> new InternalResourceInfo( pendingTaskManager.getDefaultSlotResourceProfile(), pendingTaskManager.getTotalResourceProfile(), (jobId, slotProfile) -> resultBuilder.addAllocationOnPendingResource( jobId, pendingTaskManager .getPendingTaskManagerId(), slotProfile))) .collect(Collectors.toList()); } private static int tryFulfilledRequirementWithResource( List internalResource, int numUnfulfilled, ResourceProfile requiredResource, JobID jobId) { final Iterator internalResourceInfoItr = internalResource.iterator(); while (numUnfulfilled > 0 && internalResourceInfoItr.hasNext()) { final InternalResourceInfo currentTaskManager = internalResourceInfoItr.next(); while (numUnfulfilled > 0 && currentTaskManager.tryAllocateSlotForJob(jobId, requiredResource)) { numUnfulfilled--; } if (currentTaskManager.availableProfile.equals(ResourceProfile.ZERO)) { internalResourceInfoItr.remove(); } } return numUnfulfilled; } private static Collection tryFulfillRequirementsForJobWithResources( JobID jobId, Collection missingResources, List registeredResources) { Collection outstandingRequirements = new ArrayList<>(); for (ResourceRequirement resourceRequirement : missingResources) { int numMissingRequirements = tryFulfilledRequirementWithResource( registeredResources, resourceRequirement.getNumberOfRequiredSlots(), resourceRequirement.getResourceProfile(), jobId); if (numMissingRequirements > 0) { outstandingRequirements.add( ResourceRequirement.create( resourceRequirement.getResourceProfile(), numMissingRequirements)); } } return outstandingRequirements; } private static boolean canFulfillRequirement( ResourceProfile requirement, ResourceProfile resourceProfile) { return resourceProfile.allFieldsNoLessThan(requirement); } private void tryFulfillRequirementsForJobWithPendingResources( JobID jobId, Collection unfulfilledRequirements, List availableResources, ResourceAllocationResult.Builder resultBuilder) { for (ResourceRequirement missingResource : unfulfilledRequirements) { // for this strategy, all pending resources should have the same default slot resource final ResourceProfile effectiveProfile = getEffectiveResourceProfile( missingResource.getResourceProfile(), defaultSlotResourceProfile); int numUnfulfilled = tryFulfilledRequirementWithResource( availableResources, missingResource.getNumberOfRequiredSlots(), missingResource.getResourceProfile(), jobId); if (!totalResourceProfile.allFieldsNoLessThan(effectiveProfile)) { // Can not fulfill this resource type will the default worker. resultBuilder.addUnfulfillableJob(jobId); continue; } while (numUnfulfilled > 0) { // Circularly add new pending task manager final PendingTaskManager newPendingTaskManager = new PendingTaskManager(totalResourceProfile, numSlotsPerWorker); resultBuilder.addPendingTaskManagerAllocate(newPendingTaskManager); ResourceProfile remainResource = totalResourceProfile; while (numUnfulfilled > 0 && canFulfillRequirement(effectiveProfile, remainResource)) { numUnfulfilled--; resultBuilder.addAllocationOnPendingResource( jobId, newPendingTaskManager.getPendingTaskManagerId(), effectiveProfile); remainResource = remainResource.subtract(effectiveProfile); } if (!remainResource.equals(ResourceProfile.ZERO)) { availableResources.add( new InternalResourceInfo( defaultSlotResourceProfile, remainResource, (jobID, slotProfile) -> resultBuilder.addAllocationOnPendingResource( jobID, newPendingTaskManager.getPendingTaskManagerId(), slotProfile))); } } } } private static class InternalResourceInfo { private final ResourceProfile defaultSlotProfile; private final BiConsumer allocationConsumer; private ResourceProfile availableProfile; InternalResourceInfo( ResourceProfile defaultSlotProfile, ResourceProfile availableProfile, BiConsumer allocationConsumer) { this.defaultSlotProfile = defaultSlotProfile; this.availableProfile = availableProfile; this.allocationConsumer = allocationConsumer; } boolean tryAllocateSlotForJob(JobID jobId, ResourceProfile requirement) { final ResourceProfile effectiveProfile = getEffectiveResourceProfile(requirement, defaultSlotProfile); if (availableProfile.allFieldsNoLessThan(effectiveProfile)) { availableProfile = availableProfile.subtract(effectiveProfile); allocationConsumer.accept(jobId, effectiveProfile); return true; } else { return false; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy