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

org.apache.solr.cluster.placement.plugins.SimplePlacementFactory Maven / Gradle / Ivy

There is a newer version: 9.7.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.solr.cluster.placement.plugins;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.solr.cluster.Node;
import org.apache.solr.cluster.Replica;
import org.apache.solr.cluster.SolrCollection;
import org.apache.solr.cluster.placement.PlacementContext;
import org.apache.solr.cluster.placement.PlacementPlugin;
import org.apache.solr.cluster.placement.PlacementPluginFactory;

/**
 * Factory for creating {@link SimplePlacementPlugin}, a placement plugin implementing the logic
 * from the old LegacyAssignStrategy. This chooses nodes with the fewest cores
 * (especially cores of the same collection).
 *
 * 

See {@link SameCollWeightedNode} for information on how this PlacementFactory weights nodes. * *

See {@link AffinityPlacementFactory} for a more realistic example and documentation. */ public class SimplePlacementFactory implements PlacementPluginFactory { @Override public PlacementPlugin createPluginInstance() { return new SimplePlacementPlugin(); } public static class SimplePlacementPlugin extends OrderedNodePlacementPlugin { @Override protected Map getBaseWeightedNodes( PlacementContext placementContext, Set nodes, Iterable relevantCollections, boolean skipNodesWithErrors) { HashMap nodeVsShardCount = new HashMap<>(); for (Node n : nodes) { nodeVsShardCount.computeIfAbsent(n, SameCollWeightedNode::new); } return nodeVsShardCount; } } /** * This implementation weights nodes according to how many replicas of the same collection and * shard reside on the node. The implementation tries to spread replicas of the same * collection/shard across different nodes, so nodes that contain more of the same * collection/shard will be weighted higher than nodes that only contain replicas for unique * collections/shards. * *

The total weight of the SameCollWeightedNode is the sum of: * *

    *
  • The number of replicas on the node *
  • 5 * for each collection, the sum of: *
      *
    • (the number of replicas for that collection - 1)^2 *
    *
  • 1000 * for each shard, the sum of: *
      *
    • (the number of replicas for that shard - 1)^2 *
    *
* * The count of overlapping replicas for collections/shards must be squared, since we want higher * values to be penalized more than lower values. If a node has 2 collections with 3 replicas * each, it should be weighted less than a node with 1 collection that has 5 replicas placed * there. Without squaring, the weight for the first node would be 26, and the weight of the * second node would be 25. So node #2 would be weighted lower even though it is considered to be * violating the constraints more. When we square the overlapping replica counts, the weight of * the first node would be 46 and the weight of the second node would be 85. This is the preferred * order. * *

The "relevant" weight with a replica is the sum of: * *

    *
  • The number of replicas on the node *
  • 5 * (the number of replicas on the node for that replica's collection - 1) *
  • 1000 * (the number of replicas on the node for that replica's shard - 1) *
* *

Multiple replicas of the same shard are permitted to live on the same Node, but as shown * above, the weight penalty for such is very high. */ private static class SameCollWeightedNode extends OrderedNodePlacementPlugin.WeightedNode { private static final int SAME_COL_MULT = 5; private static final int SAME_SHARD_MULT = 1000; public Map collectionReplicas; public int totalWeight = 0; SameCollWeightedNode(Node node) { super(node); this.collectionReplicas = new HashMap<>(); } @Override public int calcWeight() { return totalWeight; } @Override public int calcRelevantWeightWithReplica(Replica replica) { // Don't add 1 to the individual replica Counts, because 1 is subtracted from each when // calculating weights. // So since 1 would be added to each for the new replica, we can just use the original number // to calculate the weights. int colReplicaCount = collectionReplicas.getOrDefault(replica.getShard().getCollection().getName(), 0); int shardReplicaCount = getReplicasForShardOnNode(replica.getShard()).size(); return getAllReplicaCount() + 1 + colReplicaCount * SAME_COL_MULT + shardReplicaCount * SAME_SHARD_MULT; } @Override public boolean canAddReplica(Replica replica) { return true; } @Override protected boolean addProjectedReplicaWeights(Replica replica) { int colReplicaCountWith = collectionReplicas.merge(replica.getShard().getCollection().getName(), 1, Integer::sum); int shardReplicaCountWith = getReplicasForShardOnNode(replica.getShard()).size(); totalWeight += addedWeightOfAdditionalReplica(colReplicaCountWith - 1, shardReplicaCountWith - 1); return false; } @Override protected void initReplicaWeights(Replica replica) { addProjectedReplicaWeights(replica); } @Override protected void removeProjectedReplicaWeights(Replica replica) { Integer colReplicaCountWithout = Optional.ofNullable( collectionReplicas.computeIfPresent( replica.getShard().getCollection().getName(), (k, v) -> v - 1)) .orElse(0); int shardReplicaCountWithout = getReplicasForShardOnNode(replica.getShard()).size(); totalWeight -= addedWeightOfAdditionalReplica(colReplicaCountWithout, shardReplicaCountWithout); } private int addedWeightOfAdditionalReplica( int colReplicaCountWithout, int shardReplicaCountWithout) { int additionalWeight = 1; if (colReplicaCountWithout > 0) { // x * 2 - 1 === x^2 - (x - 1)^2 additionalWeight += SAME_COL_MULT * (colReplicaCountWithout * 2 - 1); } if (shardReplicaCountWithout > 0) { // x * 2 - 1 === x^2 - (x - 1)^2 additionalWeight += SAME_SHARD_MULT * (colReplicaCountWithout * 2 - 1); } return additionalWeight; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy