elasticsearch源码分析-05分片分配

谈Elasticsearch下分布式存储的数据分布 本文探讨了Elasticsearch是如何让数据均衡的分布在不同的节点上,主要有三个影响:节点位置、磁盘空间、单个节点的Index和Shard个数。 阅读详情

分片分配

上面的集群状态和索引级状态已经恢复完成,开始分配索引分片,恢复分片级元数据,构建routingTable路由表
allocationService的创建在ClusterModule的构造函数中

public ClusterModule(Settings settings, ClusterService clusterService, List<ClusterPlugin> clusterPlugins,
                     ClusterInfoService clusterInfoService) {
    this.clusterPlugins = clusterPlugins;
    //分配选择器
    this.deciderList = createAllocationDeciders(settings, clusterService.getClusterSettings(), clusterPlugins);
    this.allocationDeciders = new AllocationDeciders(deciderList);
    //分片分配
    this.shardsAllocator = createShardsAllocator(settings, clusterService.getClusterSettings(), clusterPlugins);
    this.clusterService = clusterService;
    this.indexNameExpressionResolver = new IndexNameExpressionResolver();
    //分配服务
    this.allocationService = new AllocationService(allocationDeciders, shardsAllocator, clusterInfoService);
}

在这里初始化了分配选择器

Map<Class, AllocationDecider> deciders = new LinkedHashMap<>();
addAllocationDecider(deciders, new MaxRetryAllocationDecider());
addAllocationDecider(deciders, new ResizeAllocationDecider());
addAllocationDecider(deciders, new ReplicaAfterPrimaryActiveAllocationDecider());
addAllocationDecider(deciders, new RebalanceOnlyWhenActiveAllocationDecider());
addAllocationDecider(deciders, new ClusterRebalanceAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new ConcurrentRebalanceAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new EnableAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new NodeVersionAllocationDecider());
addAllocationDecider(deciders, new SnapshotInProgressAllocationDecider());
addAllocationDecider(deciders, new RestoreInProgressAllocationDecider());
addAllocationDecider(deciders, new FilterAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new SameShardAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new DiskThresholdDecider(settings, clusterSettings));
addAllocationDecider(deciders, new ThrottlingAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new ShardsLimitAllocationDecider(settings, clusterSettings));
addAllocationDecider(deciders, new AwarenessAllocationDecider(settings, clusterSettings));

ES中分配分片有两种一个是allocators分配器和deciders决策器,allocators主要负责尝试寻找最优的节点来分配分片,deciders则判断当前分配方案是否可行
deciders都继承AllocationDecider类,这个抽象类有几种决策方法

  • canRebalance:分片是否可以平衡到给的的allocation
  • canAllocate:分片是否可以分配到给定的节点
  • canRemain:分片是否可以保留在给定的节点
  • shouldAutoExpandToNode:分片是否可以自动扩展到给定节点
  • canForceAllocatePrimary:主分片是否可以强制分配在给定节点
    决策结果分为ALWAYS、YES、NO、THROTTLE,默认值都是always。
    这些决策器可以分为一下几类:
  • 负载均衡类
//相同的shard不能分配到同一节点
SameShardAllocationDecider
//一个节点可以存在同一index下的分片数量限制
ShardsLimitAllocationDecider
//机架感知,尽量将分片分配到不同的机架上
AwarenessAllocationDecider
  • 并发控制类
//重新负载并发控制
ConcurrentRebalanceAllocationDecider
//根据磁盘空间进行分配决策
DiskThresholdDecider
//恢复节点限速控制
ThrottlingAllocationDecider
  • 条件限制类
//所有分片都处于活跃状态才能rebalance
RebalanceOnlyWhenActiveAllocationDecider
//可以配置根据节点ip或名称,过滤节点
FilterAllocationDecider
//只有在主分片分配后再分配
ReplicaAfterPrimaryActiveAllocationDecider
//根据active的shards来决定是否执行rebalance
ClusterRebalanceAllocationDecider

接着回到ClusterModule的构造函数中,这里创建shardsAllocator,就是BalancedShardsAllocator

//分片分配
        this.shardsAllocator = createShardsAllocator(settings, clusterService.getClusterSettings(), clusterPlugins);
 //分片平衡分配
        allocators.put(BALANCED_ALLOCATOR, () -> new BalancedShardsAllocator(settings, clusterSettings));

回到reroute方法

allocationService.reroute(newState, "state recovered");

public ClusterState reroute(ClusterState clusterState, String reason) {
    ClusterState fixedClusterState = adaptAutoExpandReplicas(clusterState);

    RoutingNodes routingNodes = getMutableRoutingNodes(fixedClusterState);
    // shuffle the unassigned nodes, just so we won't have things like poison failed shards
    //重新平衡未分配的节点
    routingNodes.unassigned().shuffle();
    RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, routingNodes, fixedClusterState,
                                                         clusterInfoService.getClusterInfo(), currentNanoTime());
    //分片
    reroute(allocation);
    if (fixedClusterState == clusterState && allocation.routingNodesChanged() == false) {
        return clusterState;
    }
    return buildResultAndLogHealthChange(clusterState, allocation, reason);
}

首先对未分配分片进行重新平衡,然后执行分配

private void reroute(RoutingAllocation allocation) {
    //移除延迟分片的分片
    removeDelayMarkers(allocation);
    //尝试先分配现有的分片副本
    allocateExistingUnassignedShards(allocation);  // try to allocate existing shard copies first
    //负载均衡的分配
    shardsAllocator.allocate(allocation);
    assert RoutingNodes.assertShardStats(allocation.routingNodes());
}

移除延迟分配的分片,然后尝试分配现有分片

private void allocateExistingUnassignedShards(RoutingAllocation allocation) {
        //按优先顺序排序
        allocation.routingNodes().unassigned().sort(PriorityComparator.getAllocationComparator(allocation)); // sort for priority ordering

        for (final ExistingShardsAllocator existingShardsAllocator : existingShardsAllocators.values()) {
            existingShardsAllocator.beforeAllocation(allocation);
        }
        //先分配已经分配过的主分片
        final RoutingNodes.UnassignedShards.UnassignedIterator primaryIterator = allocation.routingNodes().unassigned().iterator();
        while (primaryIterator.hasNext()) {
            final ShardRouting shardRouting = primaryIterator.next();
            if (shardRouting.primary()) {
                //分配主分片
                getAllocatorForShard(shardRouting, allocation)
                    .allocateUnassigned(shardRouting, allocation, primaryIterator);
            }
        }

        for (final ExistingShardsAllocator existingShardsAllocator : existingShardsAllocators.values()) {
            existingShardsAllocator.afterPrimariesBeforeReplicas(allocation);
        }
        //执行未分配分片分配
        final RoutingNodes.UnassignedShards.UnassignedIterator replicaIterator = allocation.routingNodes().unassigned().iterator();
        while (replicaIterator.hasNext()) {
            final ShardRouting shardRouting = replicaIterator.next();
            if (shardRouting.primary() == false) {
                getAllocatorForShard(shardRouting, allocation)
                    .allocateUnassigned(shardRouting, allocation, replicaIterator);
            }
        }
    }

执行GatewayAllocator执行已存在分片的分片

//已存在的分片分配
public void allocateUnassigned(ShardRouting shardRouting, final RoutingAllocation allocation,UnassignedAllocationHandler unassignedAllocationHandler) {
    assert primaryShardAllocator != null;
    assert replicaShardAllocator != null;
    innerAllocatedUnassigned(allocation, primaryShardAllocator, replicaShardAllocator, shardRouting, unassignedAllocationHandler);
}

protected static void innerAllocatedUnassigned(RoutingAllocation allocation,
                                               PrimaryShardAllocator primaryShardAllocator,
                                               ReplicaShardAllocator replicaShardAllocator,
                                               ShardRouting shardRouting,
                                               ExistingShardsAllocator.UnassignedAllocationHandler unassignedAllocationHandler) {
    assert shardRouting.unassigned();
    if (shardRouting.primary()) {//分配主shard
        primaryShardAllocator.allocateUnassigned(shardRouting, allocation, unassignedAllocationHandler);
    } else {//分配副本shard
        replicaShardAllocator.allocateUnassigned(shardRouting, allocation, unassignedAllocationHandler);
    }
}

主分分配器primaryShardAllocator和replicaShardAllocator都继承了BaseGatewayShardAllocator方法,在执行allocateUnassigned时主分片分配和副本分片分配会执行相同的方法,只是会执行不同的决策

public void allocateUnassigned(ShardRouting shardRouting, RoutingAllocation allocation,
                                   ExistingShardsAllocator.UnassignedAllocationHandler unassignedAllocationHandler) {
        //获取所有的shard信息,根据决策判断在那个节点可以分配shard,返回结果
        final AllocateUnassignedDecision allocateUnassignedDecision = makeAllocationDecision(shardRouting, allocation, logger);

        if (allocateUnassignedDecision.isDecisionTaken() == false) {
            // no decision was taken by this allocator
            return;
        }
        //所有决策都返回true
        if (allocateUnassignedDecision.getAllocationDecision() == AllocationDecision.YES) {
            unassignedAllocationHandler.initialize(allocateUnassignedDecision.getTargetNode().getId(),
                allocateUnassignedDecision.getAllocationId(),
                shardRouting.primary() ? ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE :
                                         allocation.clusterInfo().getShardSize(shardRouting, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE),
                allocation.changes());
        } else {
            unassignedAllocationHandler.removeAndIgnore(allocateUnassignedDecision.getAllocationStatus(), allocation.changes());
        }
    }

主分片分配决策

@Override
    public AllocateUnassignedDecision makeAllocationDecision(final ShardRouting unassignedShard,
                                                             final RoutingAllocation allocation,
                                                             final Logger logger) {
        if (isResponsibleFor(unassignedShard) == false) {
            // this allocator is not responsible for allocating this shard
            //此分配器不负责分配此分片
            return AllocateUnassignedDecision.NOT_TAKEN;
        }
        //debug决策过程
        final boolean explain = allocation.debugDecision();
        //获取所有shard信息
        final FetchResult<NodeGatewayStartedShards> shardState = fetchData(unassignedShard, allocation);
        //没有返回数据说明还在获取中
        if (shardState.hasData() == false) {
            allocation.setHasPendingAsyncFetch();
            List<NodeAllocationResult> nodeDecisions = null;
            if (explain) {
                nodeDecisions = buildDecisionsForAllNodes(unassignedShard, allocation);
            }
            return AllocateUnassignedDecision.no(AllocationStatus.FETCHING_SHARD_DATA, nodeDecisions);
        }

        // don't create a new IndexSetting object for every shard as this could cause a lot of garbage
        // on cluster restart if we allocate a boat load of shards
        final IndexMetadata indexMetadata = allocation.metadata().getIndexSafe(unassignedShard.index());
        //根据分片id,获取保持数据同步的shard集合
        final Set<String> inSyncAllocationIds = indexMetadata.inSyncAllocationIds(unassignedShard.id());
        //从快照恢复
        final boolean snapshotRestore = unassignedShard.recoverySource().getType() == RecoverySource.Type.SNAPSHOT;

        assert inSyncAllocationIds.isEmpty() == false;
        // use in-sync allocation ids to select nodes
        //使用同步分配 ID 来选择节点
        final NodeShardsResult nodeShardsResult = buildNodeShardsResult(unassignedShard, snapshotRestore,
            allocation.getIgnoreNodes(unassignedShard.shardId()), inSyncAllocationIds, shardState, logger);
        //是否已经有分配选择
        final boolean enoughAllocationsFound = nodeShardsResult.orderedAllocationCandidates.size() > 0;
        logger.debug("[{}][{}]: found {} allocation candidates of {} based on allocation ids: [{}]", unassignedShard.index(),
            unassignedShard.id(), nodeShardsResult.orderedAllocationCandidates.size(), unassignedShard, inSyncAllocationIds);

        if (enoughAllocationsFound == false) {
            if (snapshotRestore) {
                // let BalancedShardsAllocator take care of allocating this shard
                logger.debug("[{}][{}]: missing local data, will restore from [{}]",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard.recoverySource());
                return AllocateUnassignedDecision.NOT_TAKEN;
            } else {
                // We have a shard that was previously allocated, but we could not find a valid shard copy to allocate the primary.
                // We could just be waiting for the node that holds the primary to start back up, in which case the allocation for
                // this shard will be picked up when the node joins and we do another allocation reroute
                logger.debug("[{}][{}]: not allocating, number_of_allocated_shards_found [{}]",
                             unassignedShard.index(), unassignedShard.id(), nodeShardsResult.allocationsFound);
                return AllocateUnassignedDecision.no(AllocationStatus.NO_VALID_SHARD_COPY,
                    explain ? buildNodeDecisions(null, shardState, inSyncAllocationIds) : null);
            }
        }
        //构建节点分配分片
        NodesToAllocate nodesToAllocate = buildNodesToAllocate(
            allocation, nodeShardsResult.orderedAllocationCandidates, unassignedShard, false
        );
        DiscoveryNode node = null;
        String allocationId = null;
        boolean throttled = false;
        //可以分配
        if (nodesToAllocate.yesNodeShards.isEmpty() == false) {
            //获取第一个
            DecidedNode decidedNode = nodesToAllocate.yesNodeShards.get(0);
            logger.debug("[{}][{}]: allocating [{}] to [{}] on primary allocation",
                         unassignedShard.index(), unassignedShard.id(), unassignedShard, decidedNode.nodeShardState.getNode());
            //节点
            node = decidedNode.nodeShardState.getNode();
            //分片分配id
            allocationId = decidedNode.nodeShardState.allocationId();
        } else if (nodesToAllocate.throttleNodeShards.isEmpty() && !nodesToAllocate.noNodeShards.isEmpty()) {
            // The deciders returned a NO decision for all nodes with shard copies, so we check if primary shard
            // can be force-allocated to one of the nodes.
            //一个节点可以强制分配
            nodesToAllocate = buildNodesToAllocate(allocation, nodeShardsResult.orderedAllocationCandidates, unassignedShard, true);
            if (nodesToAllocate.yesNodeShards.isEmpty() == false) {
                final DecidedNode decidedNode = nodesToAllocate.yesNodeShards.get(0);
                final NodeGatewayStartedShards nodeShardState = decidedNode.nodeShardState;
                logger.debug("[{}][{}]: allocating [{}] to [{}] on forced primary allocation",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard, nodeShardState.getNode());
                node = nodeShardState.getNode();
                allocationId = nodeShardState.allocationId();
            } else if (nodesToAllocate.throttleNodeShards.isEmpty() == false) {
                logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on forced primary allocation",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToAllocate.throttleNodeShards);
                throttled = true;
            } else {
                logger.debug("[{}][{}]: forced primary allocation denied [{}]",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard);
            }
        } else {
            // we are throttling this, since we are allowed to allocate to this node but there are enough allocations
            // taking place on the node currently, ignore it for now
            logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on primary allocation",
                         unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToAllocate.throttleNodeShards);
            throttled = true;
        }

        List<NodeAllocationResult> nodeResults = null;
        if (explain) {
            //构建分配决策
            nodeResults = buildNodeDecisions(nodesToAllocate, shardState, inSyncAllocationIds);
        }
        //如果异步获取还没结束
        if (allocation.hasPendingAsyncFetch()) {
            return AllocateUnassignedDecision.no(AllocationStatus.FETCHING_SHARD_DATA, nodeResults);
        } else if (node != null) {
            return AllocateUnassignedDecision.yes(node, allocationId, nodeResults, false);
        } else if (throttled) {
            return AllocateUnassignedDecision.throttle(nodeResults);
        } else {
            return AllocateUnassignedDecision.no(AllocationStatus.DECIDERS_NO, nodeResults, true);
        }
    }

如果发现没有分片的状态数据时需要发送请求到其他所有节点获取分片信息,因为不知道哪个节点有shard的数据,启动时候需要遍历所有shard发起fetchData请求,如果集群规模比较大,shard分片数量比较多的的时候需要发送大量请求

//获取所有shard信息
final FetchResult<NodeGatewayStartedShards> shardState = fetchData(unassignedShard, allocation);

@Override
protected AsyncShardFetch.FetchResult<TransportNodesListGatewayStartedShards.NodeGatewayStartedShards>
                                                                        fetchData(ShardRouting shard, RoutingAllocation allocation) {
            AsyncShardFetch<TransportNodesListGatewayStartedShards.NodeGatewayStartedShards> fetch =
                asyncFetchStarted.computeIfAbsent(shard.shardId(),
                    shardId -> new InternalAsyncFetch<>(logger, "shard_started", shardId,
                        //分配索引的配置位置
                        IndexMetadata.INDEX_DATA_PATH_SETTING.get(allocation.metadata().index(shard.index()).getSettings()),
                        startedAction));
            //分片元数据
            AsyncShardFetch.FetchResult<TransportNodesListGatewayStartedShards.NodeGatewayStartedShards> shardState =
                    fetch.fetchData(allocation.nodes(), allocation.getIgnoreNodes(shard.shardId()));
            //处理返回的数据
            if (shardState.hasData()) {
                shardState.processAllocation(allocation);
            }
            return shardState;
        }

进行异步发送

void asyncFetch(final DiscoveryNode[] nodes, long fetchingRound) {
    logger.trace("{} fetching [{}] from {}", shardId, type, nodes);
    //获取shard的信息
    action.list(shardId, customDataPath, nodes, new ActionListener<BaseNodesResponse<T>>() {
        //所有节点已经返回了结果,开始处理
        @Override
        public void onResponse(BaseNodesResponse<T> response) {
            //处理获取的结果
            processAsyncFetch(response.getNodes(), response.failures(), fetchingRound);
        }

        @Override
        public void onFailure(Exception e) {
            List<FailedNodeException> failures = new ArrayList<>(nodes.length);
            for (final DiscoveryNode node: nodes) {
                failures.add(new FailedNodeException(node.getId(), "total failure in fetching", e));
            }
            processAsyncFetch(null, failures, fetchingRound);
        }
    });
}
private final TransportNodesListGatewayStartedShards startedAction;
asyncFetchStarted.computeIfAbsent(shard.shardId(),
shardId -> new InternalAsyncFetch<>(logger, "shard_started", shardId,
//分配索引的配置位置
IndexMetadata.INDEX_DATA_PATH_SETTING.get(allocation.metadata().index(shard.index()).getSettings()),startedAction));

action就是TransportNodesListGatewayStartedShards,调用list方法发送请求处理action为

public static final String ACTION_NAME = "internal:gateway/local/started_shards";

调用TransportNodesAction的doExecute方法

@Override
protected void doExecute(Task task, NodesRequest request, ActionListener<NodesResponse> listener) {
    //执行
    new AsyncAction(task, request, listener).start();
}

对端对此的处理在TransportNodesListGatewayStartedShards的nodeOperation方法

@Override
protected NodeGatewayStartedShards nodeOperation(NodeRequest request) {
    try {
        //shard标识
        final ShardId shardId = request.getShardId();
        logger.trace("{} loading local shard state info", shardId);
        //加载shard分配元数据
        ShardStateMetadata shardStateMetadata = ShardStateMetadata.FORMAT.loadLatestState(logger, namedXContentRegistry,
                                                                                          nodeEnv.availableShardPaths(request.shardId));
        if (shardStateMetadata != null) {
            if (indicesService.getShardOrNull(shardId) == null) {
                final String customDataPath;
                if (request.getCustomDataPath() != null) {
                    customDataPath = request.getCustomDataPath();
                } else {
                    // TODO: Fallback for BWC with older ES versions. Remove once request.getCustomDataPath() always returns non-null
                    final IndexMetadata metadata = clusterService.state().metadata().index(shardId.getIndex());
                    if (metadata != null) {
                        customDataPath = new IndexSettings(metadata, settings).customDataPath();
                    } else {
                        logger.trace("{} node doesn't have meta data for the requests index", shardId);
                        throw new ElasticsearchException("node doesn't have meta data for index " + shardId.getIndex());
                    }
                }
                // we don't have an open shard on the store, validate the files on disk are openable
                ShardPath shardPath = null;
                try {
                    shardPath = ShardPath.loadShardPath(logger, nodeEnv, shardId, customDataPath);
                    if (shardPath == null) {
                        throw new IllegalStateException(shardId + " no shard path found");
                    }
                    Store.tryOpenIndex(shardPath.resolveIndex(), shardId, nodeEnv::shardLock, logger);
                } catch (Exception exception) {
                    final ShardPath finalShardPath = shardPath;
                    logger.trace(() -> new ParameterizedMessage(
                        "{} can't open index for shard [{}] in path [{}]",
                        shardId,
                        shardStateMetadata,
                        (finalShardPath != null) ? finalShardPath.resolveIndex() : ""),
                                 exception);
                    String allocationId = shardStateMetadata.allocationId != null ?
                        shardStateMetadata.allocationId.getId() : null;
                    return new NodeGatewayStartedShards(clusterService.localNode(), allocationId, shardStateMetadata.primary,
                                                        exception);
                }
            }

            logger.debug("{} shard state info found: [{}]", shardId, shardStateMetadata);
            String allocationId = shardStateMetadata.allocationId != null ?
                shardStateMetadata.allocationId.getId() : null;
            return new NodeGatewayStartedShards(clusterService.localNode(), allocationId, shardStateMetadata.primary);
        }
        //没有shard元数据
        logger.trace("{} no local shard info found", shardId);
        return new NodeGatewayStartedShards(clusterService.localNode(), null, false);
    } catch (Exception e) {
        throw new ElasticsearchException("failed to load started shards", e);
    }
}

这里加载本地shard级元数据然后返回。接收到对端返回数据后将数据放入cache中以便后面执行reroute的时候不用重复获取,然后执行reroute(shardId, “post_response”)方法

@Override
protected void reroute(ShardId shardId, String reason) {
    logger.trace("{} scheduling reroute for {}", shardId, reason);
    assert rerouteService != null;
    rerouteService.reroute("async_shard_fetch", Priority.HIGH, ActionListener.wrap(
        r -> logger.trace("{} scheduled reroute completed for {}", shardId, reason),
        e -> logger.debug(new ParameterizedMessage("{} scheduled reroute failed for {}", shardId, reason), e)));
}

提交一个任务clusterService.submitStateUpdateTask

//cluster_reroute
            clusterService.submitStateUpdateTask(CLUSTER_UPDATE_TASK_SOURCE + "(" + reason + ")",
                new ClusterStateUpdateTask(priority) {

                    @Override
                    public ClusterState execute(ClusterState currentState) {
                        final boolean currentListenersArePending;
                        synchronized (mutex) {
                            assert currentListeners.isEmpty() == (pendingRerouteListeners != currentListeners)
                                : "currentListeners=" + currentListeners + ", pendingRerouteListeners=" + pendingRerouteListeners;
                            currentListenersArePending = pendingRerouteListeners == currentListeners;
                            if (currentListenersArePending) {
                                pendingRerouteListeners = null;
                            }
                        }
                        if (currentListenersArePending) {
                            logger.trace("performing batched reroute [{}]", reason);
                            return reroute.apply(currentState, reason);
                        } else {
                            logger.trace("batched reroute [{}] was promoted", reason);
                            return currentState;
                        }
                    }

                  ......
                });

调用execute方法执行return reroute.apply(currentState, reason),reroute在node构造函数中进行设置就是AllocationService的reroute

//集群重新平衡服务
final RerouteService rerouteService
                = new BatchedRerouteService(clusterService, clusterModule.getAllocationService()::reroute);

这里继续调用AllocationService的reroute方法,当前cache已经有了shard元数据,可以进行主分片分配流程
继续回到PrimaryShardAllocator.makeAllocationDecision方法中

final IndexMetadata indexMetadata = allocation.metadata().getIndexSafe(unassignedShard.index());
        //根据分片id,获取保持数据同步的shard集合
        final Set<String> inSyncAllocationIds = indexMetadata.inSyncAllocationIds(unassignedShard.id());

获取具有同步副本的shard

//使用同步分配 ID 来选择节点
final NodeShardsResult nodeShardsResult = buildNodeShardsResult(unassignedShard, snapshotRestore,                                             allocation.getIgnoreNodes(unassignedShard.shardId()), inSyncAllocationIds, shardState, logger);

protected static NodeShardsResult buildNodeShardsResult(ShardRouting shard, boolean matchAnyShard,
                                                            Set<String> ignoreNodes, Set<String> inSyncAllocationIds,
                                                            FetchResult<NodeGatewayStartedShards> shardState,
                                                            Logger logger) {
        List<NodeGatewayStartedShards> nodeShardStates = new ArrayList<>();
        int numberOfAllocationsFound = 0;
        for (NodeGatewayStartedShards nodeShardState : shardState.getData().values()) {
            DiscoveryNode node = nodeShardState.getNode();
            String allocationId = nodeShardState.allocationId();

            if (ignoreNodes.contains(node.getId())) {
                continue;
            }
            //没有发生异常
            if (nodeShardState.storeException() == null) {
                if (allocationId == null) {
                    logger.trace("[{}] on node [{}] has no shard state information", shard, nodeShardState.getNode());
                } else {
                    logger.trace("[{}] on node [{}] has allocation id [{}]", shard, nodeShardState.getNode(), allocationId);
                }
            } else {
                final String finalAllocationId = allocationId;
                if (nodeShardState.storeException() instanceof ShardLockObtainFailedException) {
                    logger.trace(() -> new ParameterizedMessage("[{}] on node [{}] has allocation id [{}] but the store can not be " +
                        "opened as it's locked, treating as valid shard", shard, nodeShardState.getNode(), finalAllocationId),
                        nodeShardState.storeException());
                } else {
                    logger.trace(() -> new ParameterizedMessage("[{}] on node [{}] has allocation id [{}] but the store can not be " +
                        "opened, treating as no allocation id", shard, nodeShardState.getNode(), finalAllocationId),
                        nodeShardState.storeException());
                    allocationId = null;
                }
            }

            if (allocationId != null) {
                assert nodeShardState.storeException() == null ||
                    nodeShardState.storeException() instanceof ShardLockObtainFailedException :
                    "only allow store that can be opened or that throws a ShardLockObtainFailedException while being opened but got a " +
                        "store throwing " + nodeShardState.storeException();
                //记录发现分片被分配的次数
                numberOfAllocationsFound++;
                //发回的节点shard是保持数据同步的
                if (matchAnyShard || inSyncAllocationIds.contains(nodeShardState.allocationId())) {
                    nodeShardStates.add(nodeShardState);
                }
            }
        }

        final Comparator<NodeGatewayStartedShards> comparator; // allocation preference
        if (matchAnyShard) {
            // prefer shards with matching allocation ids
            //匹配具有最新数据的节点靠前
            Comparator<NodeGatewayStartedShards> matchingAllocationsFirst = Comparator.comparing(
                (NodeGatewayStartedShards state) -> inSyncAllocationIds.contains(state.allocationId())).reversed();
            comparator = matchingAllocationsFirst.thenComparing(NO_STORE_EXCEPTION_FIRST_COMPARATOR)
                .thenComparing(PRIMARY_FIRST_COMPARATOR);
        } else {
            //没有发生异常的靠前
            comparator = NO_STORE_EXCEPTION_FIRST_COMPARATOR.thenComparing(PRIMARY_FIRST_COMPARATOR);
        }

        nodeShardStates.sort(comparator);

        if (logger.isTraceEnabled()) {
            logger.trace("{} candidates for allocation: {}", shard, nodeShardStates.stream().map(s -> s.getNode().getName())
                .collect(Collectors.joining(", ")));
        }
        return new NodeShardsResult(nodeShardStates, numberOfAllocationsFound);
    }

构造节点列表,如果atchAnyShard 设置为 false只会将同步副本中的shard放入列表,否则任何具有分配的节点都会被添加到列表中,但是同步副本shard在列表前面

//构建节点分配分片
NodesToAllocate nodesToAllocate = buildNodesToAllocate(
allocation, nodeShardsResult.orderedAllocationCandidates, unassignedShard, false
);

private static NodesToAllocate buildNodesToAllocate(RoutingAllocation allocation,
                                                        List<NodeGatewayStartedShards> nodeShardStates,
                                                        ShardRouting shardRouting,
                                                        boolean forceAllocate) {
        List<DecidedNode> yesNodeShards = new ArrayList<>();
        List<DecidedNode> throttledNodeShards = new ArrayList<>();
        List<DecidedNode> noNodeShards = new ArrayList<>();
        for (NodeGatewayStartedShards nodeShardState : nodeShardStates) {
            RoutingNode node = allocation.routingNodes().node(nodeShardState.getNode().getId());
            if (node == null) {
                continue;
            }
            //是否开启强制分配主节点
            Decision decision = forceAllocate ? allocation.deciders().canForceAllocatePrimary(shardRouting, node, allocation) :
                                                allocation.deciders().canAllocate(shardRouting, node, allocation);
            //记录分片分配的决策
            DecidedNode decidedNode = new DecidedNode(nodeShardState, decision);
            if (decision.type() == Type.THROTTLE) {
                throttledNodeShards.add(decidedNode);
            } else if (decision.type() == Type.NO) {
                noNodeShards.add(decidedNode);
            } else {
                yesNodeShards.add(decidedNode);
            }
        }
        return new NodesToAllocate(Collections.unmodifiableList(yesNodeShards), Collections.unmodifiableList(throttledNodeShards),
                                      Collections.unmodifiableList(noNodeShards));
    }

遍历所有deciders将决策结果分类保存THROTTLE、NO和YES三类然后返回

//可以分配
        if (nodesToAllocate.yesNodeShards.isEmpty() == false) {
            //获取第一个
            DecidedNode decidedNode = nodesToAllocate.yesNodeShards.get(0);
            logger.debug("[{}][{}]: allocating [{}] to [{}] on primary allocation",
                         unassignedShard.index(), unassignedShard.id(), unassignedShard, decidedNode.nodeShardState.getNode());
            //节点
            node = decidedNode.nodeShardState.getNode();
            //分片分配id
            allocationId = decidedNode.nodeShardState.allocationId();
        } else if (nodesToAllocate.throttleNodeShards.isEmpty() && !nodesToAllocate.noNodeShards.isEmpty()) {
            // The deciders returned a NO decision for all nodes with shard copies, so we check if primary shard
            // can be force-allocated to one of the nodes.
            //可以强制分配
            nodesToAllocate = buildNodesToAllocate(allocation, nodeShardsResult.orderedAllocationCandidates, unassignedShard, true);
            if (nodesToAllocate.yesNodeShards.isEmpty() == false) {
                final DecidedNode decidedNode = nodesToAllocate.yesNodeShards.get(0);
                final NodeGatewayStartedShards nodeShardState = decidedNode.nodeShardState;
                logger.debug("[{}][{}]: allocating [{}] to [{}] on forced primary allocation",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard, nodeShardState.getNode());
                node = nodeShardState.getNode();
                allocationId = nodeShardState.allocationId();
            } else if (nodesToAllocate.throttleNodeShards.isEmpty() == false) {
                logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on forced primary allocation",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToAllocate.throttleNodeShards);
                throttled = true;
            } else {
                logger.debug("[{}][{}]: forced primary allocation denied [{}]",
                             unassignedShard.index(), unassignedShard.id(), unassignedShard);
            }
        } else {
            // we are throttling this, since we are allowed to allocate to this node but there are enough allocations
            // taking place on the node currently, ignore it for now
            logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on primary allocation",
                         unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToAllocate.throttleNodeShards);
            throttled = true;
        }

        List<NodeAllocationResult> nodeResults = null;
        if (explain) {
            //构建分配决策
            nodeResults = buildNodeDecisions(nodesToAllocate, shardState, inSyncAllocationIds);
        }
        //如果异步获取还没结束
        if (allocation.hasPendingAsyncFetch()) {
            return AllocateUnassignedDecision.no(AllocationStatus.FETCHING_SHARD_DATA, nodeResults);
        } else if (node != null) {
            return AllocateUnassignedDecision.yes(node, allocationId, nodeResults, false);
        } else if (throttled) {
            return AllocateUnassignedDecision.throttle(nodeResults);
        } else {
            return AllocateUnassignedDecision.no(AllocationStatus.DECIDERS_NO, nodeResults, true);
        }

如果node可以分配主shard,则在该节点分配主分片。如果没有node可以选择分配主分片则查看是否可以强制分配主分片。如果没有节点可以分配主分片且返回需要限速节点则返回限速节点结果
回到BaseGatewayShardAllocator的allocateUnassigned方法

public void allocateUnassigned(ShardRouting shardRouting, RoutingAllocation allocation,
                                   ExistingShardsAllocator.UnassignedAllocationHandler unassignedAllocationHandler) {
        //获取所有的shard信息,根据决策判断在那个节点可以分配shard,返回结果
        final AllocateUnassignedDecision allocateUnassignedDecision = makeAllocationDecision(shardRouting, allocation, logger);

        if (allocateUnassignedDecision.isDecisionTaken() == false) {
            // no decision was taken by this allocator
            return;
        }
        //所有决策都返回true的node
        if (allocateUnassignedDecision.getAllocationDecision() == AllocationDecision.YES) {
            unassignedAllocationHandler.initialize(allocateUnassignedDecision.getTargetNode().getId(),
                allocateUnassignedDecision.getAllocationId(),
                shardRouting.primary() ? ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE :
                                         allocation.clusterInfo().getShardSize(shardRouting, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE),
                allocation.changes());
        } else {
            unassignedAllocationHandler.removeAndIgnore(allocateUnassignedDecision.getAllocationStatus(), allocation.changes());
        }
    }

调用initialize开始初始化主分片信息

public ShardRouting initializeShard(ShardRouting unassignedShard, String nodeId, @Nullable String existingAllocationId,
                                        long expectedSize, RoutingChangesObserver routingChangesObserver) {
        ensureMutable();
        assert unassignedShard.unassigned() : "expected an unassigned shard " + unassignedShard;
        //创建shardRouting
        ShardRouting initializedShard = unassignedShard.initialize(nodeId, existingAllocationId, expectedSize);
        //分配节点添加分配分片,node到shard关系
        node(nodeId).add(initializedShard);
        //活跃shard计数
        inactiveShardCount++;
        if (initializedShard.primary()) {
            inactivePrimaryCount++;
        }
        //添加分配恢复
        addRecovery(initializedShard);
        assignedShardsAdd(initializedShard);
        routingChangesObserver.shardInitialized(unassignedShard, initializedShard);
        return initializedShard;
    }

副本分片分配与主分片分配逻辑相同,调用了replicaShardAllocator.allocateUnassigned方法,调用ReplicaShardAllocator的makeAllocationDecision方法决策副本分片分配。先判断是否可以至少在一个节点上分配,如果不能分配则直接跳过后面的步骤。副本分片分配也需要获取一次shard信息,但是之前主分片分配已经获取了一次数据,副本分片分配可以直接使用上次执行获取分片的结果,如果没有node可以分配则查看是否延迟分配,然后执行initialize方法

public ShardRouting initializeShard(ShardRouting unassignedShard, String nodeId, @Nullable String existingAllocationId,
                                        long expectedSize, RoutingChangesObserver routingChangesObserver) {
        ensureMutable();
        assert unassignedShard.unassigned() : "expected an unassigned shard " + unassignedShard;
        //创建shardRouting
        ShardRouting initializedShard = unassignedShard.initialize(nodeId, existingAllocationId, expectedSize);
        //分配节点添加分配分片,node到shard关系
        node(nodeId).add(initializedShard);
        //活跃shard计数
        inactiveShardCount++;
        if (initializedShard.primary()) {
            inactivePrimaryCount++;
        }
        //添加分配恢复
        addRecovery(initializedShard);
        assignedShardsAdd(initializedShard);
        routingChangesObserver.shardInitialized(unassignedShard, initializedShard);
        return initializedShard;
    }

public ShardRouting initialize(String nodeId, @Nullable String existingAllocationId, long expectedShardSize) {
        assert state == ShardRoutingState.UNASSIGNED : this;
        assert relocatingNodeId == null : this;
        final AllocationId allocationId;
        //如果分配id不存在则新创建一个allocationId
        if (existingAllocationId == null) {
            allocationId = AllocationId.newInitializing();
        } else {
            allocationId = AllocationId.newInitializing(existingAllocationId);
        }
        return new ShardRouting(shardId, nodeId, null, primary, ShardRoutingState.INITIALIZING, recoverySource,
            unassignedInfo, allocationId, expectedShardSize);
    }

shard进入INITIALIZING状态
已存在shard分配结束执行不存在shard的分配

//负载均衡的分配
shardsAllocator.allocate(allocation);

public void allocate(RoutingAllocation allocation) {
        if (allocation.routingNodes().size() == 0) {
            failAllocationOfNewPrimaries(allocation);
            return;
        }
        final Balancer balancer = new Balancer(logger, allocation, weightFunction, threshold);
        //负载均衡的分配,未分配的分配
        balancer.allocateUnassigned();
        //移动分配
        balancer.moveShards();
        //负载平衡
        balancer.balance();
    }

reroute执行最后后会将shardRouting添加到集群状态中然后返回一个新的集群状态,然后会将集群状态广播出去开始执行recovery流程

ElasticSearch Shard原理与代码实例讲解 ElasticSearch Shard原理与代码实例讲解 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming 1. 背景介绍 1.1 问题的由来 阅读详情

相关推荐

Elasticsearch源码解析:核心模块解读

1. 背景介绍 1.1 Elasticsearch 的前世今生 Elasticsearch,简称为 ES,是一个开源的分布式搜索和分析引擎,以其强大的全文搜索能力和实时数据分析性能而闻名。它基于 Apache Lucene 库构建,提供了一个 RESTful API 来进行交互

AGI×大数据,开启智能时代的认知跃迁;解码AGI,赋能数据驱动的智能革命。 412

【Elasticsearch】Elasticsearch 的allocation模块源码流程分析

allocatio模块介绍 ES的分片分配就是把分片指派到集群中某个节点的过程,分配决策是有主节点完成的,其分配决策主要有两两面 1:哪些节点需要分配到哪个节点 2:哪个分片是主分片,哪个分片是副分片 对于分片的分配主要有两个组件allocation和deciders完成,allocation的任务是找个最优的节点来分配分片,而deciders负责判断是否要进行这次分配。 比如对于新建索引,allocation模块负责找出拥有分片最少的节点列表,然后deciders依次遍历节点,决定要不...

追赶者的博客 1064

弹性资源组件集成系列(一)datax集成弹性资源设计解释

弹性组件集成有弹性需求的组件,为组件增加高弹性容量,规划集成datax,elastic-job,xxl-job,sentinel dashboard,dolphinscheduer,eventbridgedatax datax基于社区版,此前已对datax进行重构,增加其metrics exporter,分布式特性,分布式模型是基于启动的worker分配,固定的worker数量,如果分片少,浪费资源;分片多,资源不足,只有排队等待。

leehom的博客 247

Elasticsearch 模块-Shard Allocation 机制

本文基于 Elasticsearch 7.4.0 版本官方文档, 整理关于 Shard Allocation 分片分配机制这一部分的理论知识, 望不吝赐教~

记忆碎片 2354

PCIe-4.2.3.2 Processing of Ordered Sets During Flit Mode Data Stream

动态门控检测(Gated Detection):绝不能在非预定时钟周期进行全时段 OS 匹配。这能节省大量动态功耗。并行容错比较器:必须实现 64-bit 宽的容错匹配器(5/8 表决),这对时序(Timing)要求较高,需要考虑多级流水线(Pipeline)设计。变长状态机(Variable Length FSM):SKP 子状态机必须具有Count_8B计数器,并且要有上限强退保护(Max Count = 6)。控制信号广播。

weixin_44700185的博客 35

【智能优化算法】2024年SCI鳗鱼-石斑鱼优化算法(EGO),含MathType公式、word伪代码、visio流程图、matlab代码等。

该文中包括5个内容:用MathType编辑的公式、伪代码、visio的流程图,matlab代码,PDF论文,拿来直接用,可以帮助科研者省下超多时间。 鳗鱼-石斑鱼优化算法(Eel and grouper optimizer ,EGO)是一种新型的元启发式算法(智能优化算法),灵感来源于海洋生态系统中鳗鱼和石斑鱼的共生作用和觅食策略。该成果由Ali Mohammadzadeh和Seyedali Mirjalili两位作者于2024年6月发表在SCI著名期刊《Cluster Computing》上。

2301_79359347的博客 1040

elasticsearch源码分析——源码编译

分析源码,首先要从搭建编译运行环境开始 项目 版本 运行环境 windows IDE intellij 2018.1.4 JDK 1.8.0_171 elasticsearch 5.5.1 gradle 4.3 maven 3.5.0 总是用得上的 备注:之前一直都用的是1.8.0_25...

u011426341的专栏 2981

告别抓瞎!手把手教你用Keysight Infinium和M8040完成PCIe 5.0 TX/RX信号完整性测试

本文详细介绍了如何使用Keysight Infinium示波器和M8040误码仪完成PCIe 5.0 TX/RX信号完整性测试。从测试前的设备准备、软件配置到具体的TX信号测试步骤和RX容限测试实战,提供了全面的操作指南和常见问题解决方案,帮助工程师高效完成PCIe 5.0合规性测试。

weixin_30911451的博客 502

3.3 掌握RDD分区

在有些情况下,使用Spark自带的分区器满足不了特定的需求。例如,某学生有以下3科成绩数据:科目成绩chinese98math88english96chinese现需要将每一科成绩单独分配到一个分区中,然后将3科成绩输出到HDFS的指定目录(每个分区对应一个结果文件),此时就需要对数据进行自定义分区。

qq_67460132的博客 335

CODESYS Softmotion(一)功能介绍

一、CODESYS SoftMotion RTE SL产品 1.1 CODESYS Runtime SL 产品家族介绍 目前支持的主流厂商的硬件产品,让部署在上面的成为实时设备。 对于Windows系统,根据需求选择对应的Runtime: RTE极大的提高了实时性,适合进行运动控制,同时RTE还支持了多个主从站协议: 还可以选择可选的功能(Single License): RTE对硬件和系统有要求,如果你需要硬件功能,那么网卡会有最低要求。 1.2 RTE的下载和安装 在官网http://codes

Fishfishfishfishcat 2万+

Qlib数据获取避坑指南:从CSV导入到自定义数据源的完整解决方案

本文详细解析了Qlib数据获取的完整解决方案,从CSV导入到自定义数据源,涵盖了股票数据处理的关键技巧和常见陷阱。特别针对Qlib平台的数据格式要求和复权处理提供了实用指南,帮助量化投资者高效整合Wind等第三方数据源,确保数据质量与模型性能。

weixin_29047919的博客 304

Redis资料汇总专题

很多朋友反映,说NoSQLFan上的资料不少,但是要找到自己实用的太难,于是萌生做这样一个专题的想法。通过将不同NoSQL产品从入门到精通的各种资料进行汇总,希望能够让大家更快的找到适合自己的教程或文章进行阅读。 最后更新时间:2013-04-22 1.Redis是什么? 十五分钟介绍 Redis数据结构Redis系统性介绍一个很棒的Redis介绍PPT强烈推荐!非同一般的R

Hello World . 1041

如何利用通达信进行选股集合操作

每个交易者实际上都有自己的选股策略,这是必然的,也会有自己的主观干预,但是还是需要从客观热点股票进行一个比对的,才能说主观和客观相结合不至于​偏离方向。 这几天我也发了节前最后一天我的选股策略盘中的选择结果, 我也从网上拿到了热点股票池,当拿到之后你会发现如何从几十个股票热点股票选出核心票,这就是个问题了,这里面一定要通过股价涨跌幅来进行过滤,而不是通过指标,因为一切指标都是根据价格变化而改变的了,所以​这一步不要走弯路。 1、把拿到的热点股票名单,导入通达信自定义板块 2、删除

抢财猫股票课堂 2581

147.【2024Java八股-全网最全-10w字】

eg: 学校、院校、经验、年龄、跳槽频率…基本包括16种常见使用场景: 、数据共享分布式、、全局 ID、计数器、限流、位统计、购物车、用户消息时间线 timeline、、抽奖、点赞、签到、打卡、商品标签、商品筛选、用户关注、推荐模型、排行榜.详细讲解16种使用场景: https://blog.youkuaiyun.com/zxl646801924/article/details/123202381用户使用id进行查询文章的时候,首先会查询redis数据库,如果在redis中命中数据,那么redis就向用户返回查询的结果

qq_69683957的博客 1736

如何给K8S配置一个具有永久有效的kubeconfig

在 Amazon EKS 环境中,Kubernetes 的认证机制与 AWS IAM 深度集成,通过aws-iam-authenticator动态生成临时凭证。这种设计虽然增强了安全性,但给需要持久化凭证的工具链(如 CI/CD 系统中的 KubeVela)带来了挑战。具体表现为:临时凭证失效​​:默认 Token 有效期为 15 分钟至 1 小时;​​IAM 角色限制​​:直接使用aws eks get-token生成的凭证无法持久化

小杨同学的博客 660

详解AUTOSAR:DaVinci Configurator配置CAN和UART数据协议解析器(RH850)(实战篇—1)

通过学习本篇博文项目,将会把所学的DaVinci Configurator知识系统串联起来。

不脱发的程序猿 2809

Elasticsearch-7.8.0 创建索引底层源码分析(1)

1、前言 本专栏系列基于 elasticsearch-7.8 版本分析 陆续打算推出的博文列表如下: 1、创建索引底层源码分析 2、更新索引底层源码分析 3、删除索引底层源码分析 4、elasticsearch中的线程池实现 5、elasticsearch启动过程源码流程分析 6、high level rest client请求流程分析 7、elastic search数据副本模型、读写模型 8、lucene学习总结系列 全文检索的基本原理 lucene的总体结构 lucene的索引文件格式..

dkjhl的博客 1683

45、使用 sqlread 函数将数据从数据库表导入 MATLAB

本文详细介绍了如何使用 MATLAB 中的 `sqlread` 函数从不同类型的数据库(如 Microsoft SQL Server 和 SQLite)中导入数据。文章涵盖了 `sqlread` 的基本语法、输入输出参数、使用示例以及注意事项,并通过多个实例演示了自定义导入选项、元信息检索和数据类型转换等内容。此外,还总结了导入数据库数据的通用流程及最佳实践建议,帮助用户更高效地进行数据分析和处理工作。

bash7scripter的博客 133

《Elasticsearch 源码解析与优化实战》第12章:allocation模型分析

简介 本文主要分析allocation 模块的结构和原理,然后以集群启动过程为例分析 allocation 模块的工作过程 什么是 allocation 分片分配就是把一个分片指派到集群中某个节点的过程。分配决策由主节点完成,分配决策包含两方面: 哪些分片应该分配给哪些节点 哪个分片作为主分片,哪些作为副本分片 对于新建索引和已有索引, 分片分配过程也不尽相同,不过不管哪种场景,ElasticSearch都通过两个基础组件完成工作:allocators [ˈæləʊkeɪtə(r)] 分配者和decid

chbxw 1125

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

聊聊elasticsearch的RoutingService

序 本文主要研究一下elasticsearch的RoutingService RoutingService elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/cluster/routing/RoutingService.java public class RoutingService extends AbstractLifecyc...

weixin_33854644的博客 216

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【弄nèng - Elasticsearch】运维篇 —— ES分片unassigned解决方案(ALLOCATION_FAILED,REPLICA_ADDED等)

文章目录1. 情况2. 继续深究3. 解决此问题用到的知识项目推荐 1. 情况 ES分片有一些未分配成功,集群状态处于黄色 我们可以通过以下api查看分片情况 GET _cat/shards?h=index,shard,prirep,state,unassigned.reason 通过返回值可以看到分片未分配的原因,一般有以下几个: INDEX_CREATED:由于创建索引的API导致未分配。...

司马缸砸缸了 4999

elasticsearch源码分析之分片分配(十)

分片是把索引数据切分成多个小的索引块,这些小的索引块能够分发到同一个集群中的不同节点。这个把shard分发到node的过程就是分片的分配。分配的原则是主要还是基于提高读写性能,实现负载均衡,备份恢复快。

thomas0yang的专栏 3400

elasticsearch分片分配和路由配置

本文基于es7.3版本。 集群级别的分片分配配置,主要有下面几个: cluster.routing.allocation.enable:启用或禁止特定种类分片的分配。有下面四种取值: all- (default) Allows shard allocation for all kinds of shards.允许所有种类分片的分配,包括primary和replica。默认行为。 prima...

w1346561235的博客 2958

Git:git深入理解及常见问题

Git深入理解及常见问题

netyeaxi的专栏 104

git checkout 与 git switch 的区别

git checkout 与 git switch 的区别

choumin的专栏 187

ES数据库学习系列·学习大纲(目录)

学习方式:每一小节一个 MD 文件,采用「理论讲解 + 动手实践」的方式编写。版本基准:Elasticsearch 8.x(Kibana Dev Tools 语法),涉及 Docker 安装。建议学习路径:按章节顺序学习,每节完成「实践」部分的命令后再进入下一节。

啊渊的专栏 208
上一篇: elasticsearch源码分析-04集群状态发布
下一篇: elasticsearch源码分析-06索引恢复
胖柯G
博客等级 码龄10年 453粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值