示例#1
0
ShardId BalancerPolicy::_getMostOverloadedShard(const ShardStatisticsVector& shardStats,
                                                const DistributionStatus& distribution,
                                                const string& chunkTag,
                                                const set<ShardId>& excludedShards) {
    ShardId worst;
    unsigned maxChunks = 0;

    for (const auto& stat : shardStats) {
        if (excludedShards.count(stat.shardId))
            continue;

        const unsigned shardChunkCount =
            distribution.numberOfChunksInShardWithTag(stat.shardId, chunkTag);
        if (shardChunkCount <= maxChunks)
            continue;

        worst = stat.shardId;
        maxChunks = shardChunkCount;
    }

    return worst;
}
示例#2
0
bool BalancerPolicy::_singleZoneBalance(const ShardStatisticsVector& shardStats,
                                        const DistributionStatus& distribution,
                                        const string& tag,
                                        size_t imbalanceThreshold,
                                        vector<MigrateInfo>* migrations,
                                        set<ShardId>* usedShards) {
    const ShardId from = _getMostOverloadedShard(shardStats, distribution, tag, *usedShards);
    if (!from.isValid())
        return false;

    const size_t max = distribution.numberOfChunksInShardWithTag(from, tag);
    if (max == 0)
        return false;

    const ShardId to = _getLeastLoadedReceiverShard(shardStats, distribution, tag, *usedShards);
    if (!to.isValid()) {
        if (migrations->empty()) {
            log() << "No available shards to take chunks for tag [" << tag << "]";
        }
        return false;
    }

    const size_t min = distribution.numberOfChunksInShardWithTag(to, tag);
    if (min >= max)
        return false;

    const size_t totalNumberOfChunksWithTag =
        (tag.empty() ? distribution.totalChunks() : distribution.totalChunksWithTag(tag));

    size_t totalNumberOfShardsWithTag = 0;

    for (const auto& stat : shardStats) {
        if (tag.empty() || stat.shardTags.count(tag)) {
            totalNumberOfShardsWithTag++;
        }
    }

    // totalNumberOfShardsWithTag cannot be zero if the to shard is valid
    invariant(totalNumberOfShardsWithTag);
    invariant(totalNumberOfChunksWithTag >= max);

    // The ideal should be at least one per shard
    const size_t idealNumberOfChunksPerShardWithTag =
        (totalNumberOfChunksWithTag < totalNumberOfShardsWithTag)
        ? 1
        : (totalNumberOfChunksWithTag / totalNumberOfShardsWithTag);

    const size_t imbalance = max - idealNumberOfChunksPerShardWithTag;

    LOG(1) << "collection : " << distribution.nss().ns();
    LOG(1) << "zone       : " << tag;
    LOG(1) << "donor      : " << from << " chunks on " << max;
    LOG(1) << "receiver   : " << to << " chunks on " << min;
    LOG(1) << "ideal      : " << idealNumberOfChunksPerShardWithTag;
    LOG(1) << "threshold  : " << imbalanceThreshold;

    // Check whether it is necessary to balance within this zone
    if (imbalance < imbalanceThreshold)
        return false;

    const vector<ChunkType>& chunks = distribution.getChunks(from);

    unsigned numJumboChunks = 0;

    for (const auto& chunk : chunks) {
        if (distribution.getTagForChunk(chunk) != tag)
            continue;

        if (chunk.getJumbo()) {
            numJumboChunks++;
            continue;
        }

        migrations->emplace_back(distribution.nss().ns(), to, chunk);
        invariant(usedShards->insert(chunk.getShard()).second);
        invariant(usedShards->insert(to).second);
        return true;
    }

    if (numJumboChunks) {
        warning() << "Shard: " << from << ", collection: " << distribution.nss().ns()
                  << " has only jumbo chunks for zone \'" << tag
                  << "\' and cannot be balanced. Jumbo chunks count: " << numJumboChunks;
    }

    return false;
}