use of org.apache.accumulo.core.spi.balancer.data.TabletStatistics in project accumulo by apache.
the class SimpleLoadBalancer method move.
/**
* Select a tablet based on differences between table loads; if the loads are even, use the
* busiest table
*/
List<TabletMigration> move(ServerCounts tooMuch, ServerCounts tooLittle, int count, Map<TableId, Map<TabletId, TabletStatistics>> donerTabletStats) {
if (count == 0) {
return Collections.emptyList();
}
List<TabletMigration> result = new ArrayList<>();
// Copy counts so we can update them as we propose migrations
Map<TableId, Integer> tooMuchMap = tabletCountsPerTable(tooMuch.status);
Map<TableId, Integer> tooLittleMap = tabletCountsPerTable(tooLittle.status);
for (int i = 0; i < count; i++) {
TableId table;
Integer tooLittleCount;
if (tableToBalance == null) {
// find a table to migrate
// look for an uneven table count
int biggestDifference = 0;
TableId biggestDifferenceTable = null;
for (var tableEntry : tooMuchMap.entrySet()) {
TableId tableID = tableEntry.getKey();
tooLittleMap.putIfAbsent(tableID, 0);
int diff = tableEntry.getValue() - tooLittleMap.get(tableID);
if (diff > biggestDifference) {
biggestDifference = diff;
biggestDifferenceTable = tableID;
}
}
if (biggestDifference < 2) {
table = busiest(tooMuch.status.getTableMap());
} else {
table = biggestDifferenceTable;
}
} else {
// just balance the given table
table = tableToBalance;
}
Map<TabletId, TabletStatistics> onlineTabletsForTable = donerTabletStats.get(table);
try {
if (onlineTabletsForTable == null) {
onlineTabletsForTable = new HashMap<>();
List<TabletStatistics> stats = getOnlineTabletsForTable(tooMuch.server, table);
if (stats == null) {
log.warn("Unable to find tablets to move");
return result;
}
for (TabletStatistics stat : stats) onlineTabletsForTable.put(stat.getTabletId(), stat);
donerTabletStats.put(table, onlineTabletsForTable);
}
} catch (Exception ex) {
log.error("Unable to select a tablet to move", ex);
return result;
}
TabletId tabletId = selectTablet(onlineTabletsForTable);
onlineTabletsForTable.remove(tabletId);
if (tabletId == null)
return result;
tooMuchMap.put(table, tooMuchMap.get(table) - 1);
/*
* If a table grows from 1 tablet then tooLittleMap.get(table) can return a null, since there
* is only one tabletserver that holds all of the tablets. Here we check to see if in fact
* that is the case and if so set the value to 0.
*/
tooLittleCount = tooLittleMap.get(table);
if (tooLittleCount == null) {
tooLittleCount = 0;
}
tooLittleMap.put(table, tooLittleCount + 1);
tooMuch.count--;
tooLittle.count++;
result.add(new TabletMigration(tabletId, tooMuch.server, tooLittle.server));
}
return result;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletStatistics in project accumulo by apache.
the class SimpleLoadBalancer method selectTablet.
static TabletId selectTablet(Map<TabletId, TabletStatistics> extents) {
if (extents.isEmpty())
return null;
TabletId mostRecentlySplit = null;
long splitTime = 0;
for (Entry<TabletId, TabletStatistics> entry : extents.entrySet()) if (entry.getValue().getSplitCreationTime() >= splitTime) {
splitTime = entry.getValue().getSplitCreationTime();
mostRecentlySplit = entry.getKey();
}
return mostRecentlySplit;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletStatistics in project accumulo by apache.
the class ChaoticLoadBalancer method balance.
@Override
public long balance(BalanceParameters params) {
Map<TabletServerId, Long> numTablets = new HashMap<>();
List<TabletServerId> underCapacityTServer = new ArrayList<>();
if (!params.currentMigrations().isEmpty()) {
outstandingMigrationsProblem.setMigrations(params.currentMigrations());
problemReporter.reportProblem(outstandingMigrationsProblem);
return 100;
}
problemReporter.clearProblemReportTimes();
boolean moveMetadata = random.nextInt(4) == 0;
long totalTablets = 0;
for (Entry<TabletServerId, TServerStatus> e : params.currentStatus().entrySet()) {
long tabletCount = 0;
for (TableStatistics ti : e.getValue().getTableMap().values()) {
tabletCount += ti.getTabletCount();
}
numTablets.put(e.getKey(), tabletCount);
underCapacityTServer.add(e.getKey());
totalTablets += tabletCount;
}
// totalTablets is fuzzy due to asynchronicity of the stats
// *1.2 to handle fuzziness, and prevent locking for 'perfect' balancing scenarios
long avg = (long) Math.ceil(((double) totalTablets) / params.currentStatus().size() * 1.2);
for (Entry<TabletServerId, TServerStatus> e : params.currentStatus().entrySet()) {
for (String tableId : e.getValue().getTableMap().keySet()) {
TableId id = TableId.of(tableId);
if (!moveMetadata && MetadataTable.ID.equals(id))
continue;
try {
for (TabletStatistics ts : getOnlineTabletsForTable(e.getKey(), id)) {
int index = random.nextInt(underCapacityTServer.size());
TabletServerId dest = underCapacityTServer.get(index);
if (dest.equals(e.getKey()))
continue;
params.migrationsOut().add(new TabletMigration(ts.getTabletId(), e.getKey(), dest));
if (numTablets.put(dest, numTablets.get(dest) + 1) > avg)
underCapacityTServer.remove(index);
if (numTablets.put(e.getKey(), numTablets.get(e.getKey()) - 1) <= avg && !underCapacityTServer.contains(e.getKey()))
underCapacityTServer.add(e.getKey());
// option!
if (underCapacityTServer.isEmpty())
underCapacityTServer.addAll(numTablets.keySet());
}
} catch (AccumuloSecurityException e1) {
// Shouldn't happen, but carry on if it does
log.debug("Encountered AccumuloSecurityException. This should not happen. Carrying on anyway.", e1);
} catch (AccumuloException e1) {
// Shouldn't happen, but carry on if it does
log.debug("Encountered AccumuloException. This should not happen. Carrying on anyway.", e1);
}
}
}
return 100;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletStatistics in project accumulo by apache.
the class HostRegexTableLoadBalancer method balance.
@Override
public long balance(BalanceParameters params) {
long minBalanceTime = 20_000;
// Iterate over the tables and balance each of them
Map<String, TableId> tableIdMap = environment.getTableIdMap();
Map<TableId, String> tableIdToTableName = tableIdMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
tableIdToTableName.keySet().forEach(this::checkTableConfig);
long now = System.currentTimeMillis();
HrtlbConf myConf = hrtlbConf.get();
SortedMap<TabletServerId, TServerStatus> current = params.currentStatus();
Set<TabletId> migrations = params.currentMigrations();
List<TabletMigration> migrationsOut = params.migrationsOut();
Map<String, SortedMap<TabletServerId, TServerStatus>> currentGrouped = splitCurrentByRegex(params.currentStatus());
if ((now - this.lastOOBCheck) > myConf.oobCheckMillis) {
try {
// Check to see if a tablet is assigned outside the bounds of the pool. If so, migrate it.
for (String table : tableIdMap.keySet()) {
LOG.debug("Checking for out of bounds tablets for table {}", table);
String tablePoolName = getPoolNameForTable(table);
for (Entry<TabletServerId, TServerStatus> e : current.entrySet()) {
// pool names are the same as table names, except in the DEFAULT case.
// If this table is assigned to a pool for this host, then move on.
List<String> hostPools = getPoolNamesForHost(e.getKey());
if (hostPools.contains(tablePoolName)) {
continue;
}
TableId tid = tableIdMap.get(table);
if (tid == null) {
LOG.warn("Unable to check for out of bounds tablets for table {}," + " it may have been deleted or renamed.", table);
continue;
}
try {
List<TabletStatistics> outOfBoundsTablets = getOnlineTabletsForTable(e.getKey(), tid);
if (outOfBoundsTablets == null) {
continue;
}
for (TabletStatistics ts : outOfBoundsTablets) {
if (migrations.contains(ts.getTabletId())) {
LOG.debug("Migration for out of bounds tablet {} has already been requested", ts.getTabletId());
continue;
}
String poolName = getPoolNameForTable(table);
SortedMap<TabletServerId, TServerStatus> currentView = currentGrouped.get(poolName);
if (currentView != null) {
int skip = random.nextInt(currentView.size());
Iterator<TabletServerId> iter = currentView.keySet().iterator();
for (int i = 0; i < skip; i++) {
iter.next();
}
TabletServerId nextTS = iter.next();
LOG.info("Tablet {} is currently outside the bounds of the" + " regex, migrating from {} to {}", ts.getTabletId(), e.getKey(), nextTS);
migrationsOut.add(new TabletMigration(ts.getTabletId(), e.getKey(), nextTS));
if (migrationsOut.size() >= myConf.maxTServerMigrations) {
break;
}
} else {
LOG.warn("No tablet servers online for pool {}, unable to" + " migrate out of bounds tablets", poolName);
}
}
} catch (AccumuloException | AccumuloSecurityException e1) {
LOG.error("Error in OOB check getting tablets for table {} from server {} {}", tid, e.getKey().getHost(), e);
}
}
}
} finally {
// this could have taken a while...get a new time
this.lastOOBCheck = System.currentTimeMillis();
}
}
if (!migrationsOut.isEmpty()) {
LOG.warn("Not balancing tables due to moving {} out of bounds tablets", migrationsOut.size());
LOG.info("Migrating out of bounds tablets: {}", migrationsOut);
return minBalanceTime;
}
if (migrations != null && !migrations.isEmpty()) {
if (migrations.size() >= myConf.maxOutstandingMigrations) {
LOG.warn("Not balancing tables due to {} outstanding migrations", migrations.size());
if (LOG.isTraceEnabled()) {
LOG.trace("Sample up to 10 outstanding migrations: {}", Iterables.limit(migrations, 10));
}
return minBalanceTime;
}
LOG.debug("Current outstanding migrations of {} being applied", migrations.size());
if (LOG.isTraceEnabled()) {
LOG.trace("Sample up to 10 outstanding migrations: {}", Iterables.limit(migrations, 10));
}
migrationsFromLastPass.keySet().retainAll(migrations);
SortedMap<TabletServerId, TServerStatusImpl> currentCopy = new TreeMap<>();
current.forEach((tid, status) -> currentCopy.put(tid, (TServerStatusImpl) status));
Multimap<TabletServerId, String> serverTableIdCopied = HashMultimap.create();
for (TabletMigration migration : migrationsFromLastPass.values()) {
TableStatisticsImpl fromInfo = getTableInfo(currentCopy, serverTableIdCopied, migration.getTablet().getTable().canonical(), migration.getOldTabletServer());
if (fromInfo != null) {
fromInfo.setOnlineTabletCount(fromInfo.getOnlineTabletCount() - 1);
}
TableStatisticsImpl toInfo = getTableInfo(currentCopy, serverTableIdCopied, migration.getTablet().getTable().canonical(), migration.getNewTabletServer());
if (toInfo != null) {
toInfo.setOnlineTabletCount(toInfo.getOnlineTabletCount() + 1);
}
}
migrations = EMPTY_MIGRATIONS;
} else {
migrationsFromLastPass.clear();
}
for (TableId tableId : tableIdMap.values()) {
String tableName = tableIdToTableName.get(tableId);
String regexTableName = getPoolNameForTable(tableName);
SortedMap<TabletServerId, TServerStatus> currentView = currentGrouped.get(regexTableName);
if (currentView == null) {
LOG.warn("Skipping balance for table {} as no tablet servers are online.", tableName);
continue;
}
ArrayList<TabletMigration> newMigrations = new ArrayList<>();
getBalancerForTable(tableId).balance(new BalanceParamsImpl(currentView, migrations, newMigrations));
if (newMigrations.isEmpty()) {
tableToTimeSinceNoMigrations.remove(tableId);
} else if (tableToTimeSinceNoMigrations.containsKey(tableId)) {
if ((now - tableToTimeSinceNoMigrations.get(tableId)) > HOURS.toMillis(1)) {
LOG.warn("We have been consistently producing migrations for {}: {}", tableName, Iterables.limit(newMigrations, 10));
}
} else {
tableToTimeSinceNoMigrations.put(tableId, now);
}
migrationsOut.addAll(newMigrations);
if (migrationsOut.size() >= myConf.maxTServerMigrations) {
break;
}
}
for (TabletMigration migration : migrationsOut) {
migrationsFromLastPass.put(migration.getTablet(), migration);
}
LOG.info("Migrating tablets for balance: {}", migrationsOut);
return minBalanceTime;
}
use of org.apache.accumulo.core.spi.balancer.data.TabletStatistics in project accumulo by apache.
the class HostRegexTableLoadBalancerReconfigurationTest method getOnlineTabletsForTable.
@Override
public List<TabletStatistics> getOnlineTabletsForTable(TabletServerId tserver, TableId tableId) {
List<TabletStatistics> tablets = new ArrayList<>();
// Report assignment information
for (Entry<TabletId, TabletServerId> e : this.assignments.entrySet()) {
if (e.getValue().equals(tserver) && e.getKey().getTable().equals(tableId)) {
TabletStats ts = new TabletStats();
TabletId tid = e.getKey();
ts.setExtent(new KeyExtent(tid.getTable(), tid.getEndRow(), tid.getPrevEndRow()).toThrift());
tablets.add(new TabletStatisticsImpl(ts));
}
}
return tablets;
}
Aggregations