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

com.vip.saturn.job.sharding.task.ExecuteJobServerOnlineShardingTask Maven / Gradle / Ivy

There is a newer version: 3.5.1
Show newest version
package com.vip.saturn.job.sharding.task;

import com.vip.saturn.job.sharding.entity.Executor;
import com.vip.saturn.job.sharding.entity.Shard;
import com.vip.saturn.job.sharding.node.SaturnExecutorsNode;
import com.vip.saturn.job.sharding.service.NamespaceShardingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 作业的executor上线,executor级别平衡摘取,但是只能摘取该作业的shard;添加的新的shard
 */
public class ExecuteJobServerOnlineShardingTask extends AbstractAsyncShardingTask {

	private static final Logger log = LoggerFactory.getLogger(ExecuteJobServerOnlineShardingTask.class);

	private String jobName;

	private String executorName;

	public ExecuteJobServerOnlineShardingTask(NamespaceShardingService namespaceShardingService, String jobName,
			String executorName) {
		super(namespaceShardingService);
		this.jobName = jobName;
		this.executorName = executorName;
	}

	@Override
	protected void logStartInfo() {
		log.info("Execute the {}, jobName is {}, executorName is {}", this.getClass().getSimpleName(), jobName,
				executorName);
	}

	private String getExecutorIp() throws Exception {
		String ip = null;
		String executorIpNodePath = SaturnExecutorsNode.getExecutorIpNodePath(executorName);
		if (curatorFramework.checkExists().forPath(SaturnExecutorsNode.getExecutorIpNodePath(executorName)) != null) {
			byte[] ipBytes = curatorFramework.getData().forPath(executorIpNodePath);
			if (ipBytes != null) {
				ip = new String(ipBytes, "UTF-8");
			}
		}
		return ip;
	}

	private Shard createLocalShard(List lastOnlineExecutorList, int loadLevel) {
		List itemList = new ArrayList<>();
		for (int i = 0; i < lastOnlineExecutorList.size(); i++) {
			List shardList = lastOnlineExecutorList.get(i).getShardList();
			for (int j = 0; j < shardList.size(); j++) {
				Shard shardAlreadyExists = shardList.get(j);
				if (shardAlreadyExists.getJobName().equals(jobName)) {
					itemList.add(shardAlreadyExists.getItem());
				}
			}
		}
		int item = 0;
		if (!itemList.isEmpty()) {
			int itemListSize = itemList.size();
			boolean[] flags = new boolean[itemListSize + 1];
			for (int i = 0; i < itemListSize; i++) {
				Integer itemAlreadyExists = itemList.get(i);
				if (itemAlreadyExists <= itemListSize) {
					flags[itemAlreadyExists] = true;
				}
			}
			for (int i = 0; i < flags.length; i++) {
				if (!flags[i]) {
					item = i;
					break;
				}
			}
		}
		Shard shard = new Shard();
		shard.setJobName(jobName);
		shard.setItem(item);
		shard.setLoadLevel(loadLevel);
		return shard;
	}

	private boolean hasShardRunning(List lastOnlineExecutorList) {
		for (int i = 0; i < lastOnlineExecutorList.size(); i++) {
			List shardList = lastOnlineExecutorList.get(i).getShardList();
			for (int j = 0; j < shardList.size(); j++) {
				if (shardList.get(j).getJobName().equals(jobName)) {
					return true;
				}
			}
		}
		return false;
	}

	private List pickShardsRunningInDispreferList(List preferListConfigured,
			List lastOnlineExecutorList) {
		List shards = new ArrayList<>();
		for (int i = 0; i < lastOnlineExecutorList.size(); i++) {
			Executor executor = lastOnlineExecutorList.get(i);
			if (!preferListConfigured.contains(executor.getExecutorName())) {
				Iterator iterator = executor.getShardList().iterator();
				while (iterator.hasNext()) {
					Shard shard = iterator.next();
					if (shard.getJobName().equals(jobName)) {
						executor.setTotalLoadLevel(executor.getTotalLoadLevel() - shard.getLoadLevel());
						iterator.remove();
						shards.add(shard);
					}
				}
			}
		}
		return shards;
	}

	private int getTotalLoadLevel(List shardList, List executorList) {
		int total = 0;
		for (int i = 0; i < shardList.size(); i++) {
			total += shardList.get(i).getLoadLevel();
		}
		for (int i = 0; i < executorList.size(); i++) {
			total += executorList.get(i).getTotalLoadLevel();
		}
		return total;
	}

	// 计算平均load,然后摘取最接近平均负载的shard。
	private void pickBalance(List shardList, List executorList) {
		int totalLoadLevel = getTotalLoadLevel(shardList, executorList);
		int averageTotalLoad = totalLoadLevel / (executorList.size());
		for (Executor executor : executorList) {
			pickBalanceOnAExecutor(shardList, executor, averageTotalLoad);
		}
	}

	private void pickBalanceOnAExecutor(List shardList, Executor executor, int averageTotalLoad) {
		int pickLoadLevel = executor.getTotalLoadLevel() - averageTotalLoad;
		while (pickLoadLevel > 0 && !executor.getShardList().isEmpty()) {
			// 摘取现在totalLoad > 平均值的executor里面的shard
			Shard pickShard = null;
			for (int j = 0; j < executor.getShardList().size(); j++) {
				Shard shard = executor.getShardList().get(j);
				if (!shard.getJobName().equals(jobName)) { // 如果当前Shard不属于该作业,则不摘取,继续下一个
					continue;
				}
				if (pickShard == null) {
					pickShard = shard;
					continue;
				}
				if (pickShard.getLoadLevel() >= pickLoadLevel) {
					if (shard.getLoadLevel() >= pickLoadLevel && shard.getLoadLevel() < pickShard.getLoadLevel()) {
						pickShard = shard;
					}
					continue;
				}
				if (shard.getLoadLevel() >= pickLoadLevel) {
					pickShard = shard;
				} else {
					if (shard.getLoadLevel() > pickShard.getLoadLevel()) {
						pickShard = shard;
					}
				}
			}
			if (pickShard != null) {
				executor.setTotalLoadLevel(executor.getTotalLoadLevel() - pickShard.getLoadLevel());
				executor.getShardList().remove(pickShard);
				shardList.add(pickShard);
			} else { // 没有符合摘取条件的,无需再选择摘取
				break;
			}
			pickLoadLevel = executor.getTotalLoadLevel() - averageTotalLoad;
		}
	}

	private List createUnLocalShards(int shardingTotalCount, int loadLevel) {
		List shards = new ArrayList<>();
		for (int i = 0; i < shardingTotalCount; i++) {
			Shard shard = new Shard();
			shard.setJobName(jobName);
			shard.setItem(i);
			shard.setLoadLevel(loadLevel);
			shards.add(shard);
		}
		return shards;
	}

	private boolean shardsAllRunningInDispreferList(List preferListConfigured,
			List lastOnlineExecutorList) {
		for (int i = 0; i < lastOnlineExecutorList.size(); i++) {
			Executor executor = lastOnlineExecutorList.get(i);
			if (preferListConfigured.contains(executorName)) {
				List shardList = executor.getShardList();
				for (int j = 0; j < shardList.size(); j++) {
					if (shardList.get(j).getJobName().equals(jobName)) {
						return false;
					}
				}
			}
		}
		return true;
	}

	public void pickIntelligent(List allEnableJobs, List shardList,
			List lastOnlineTrafficExecutorList) throws Exception {
		boolean preferListIsConfigured = preferListIsConfigured(jobName); // 是否配置了preferList
		List preferListConfigured = getPreferListConfigured(jobName); // 配置态的preferList
		boolean localMode = isLocalMode(jobName);
		int loadLevel = getLoadLevel(jobName);
		if (localMode) {
			if ((!preferListIsConfigured || preferListConfigured.contains(executorName))
					&& allEnableJobs.contains(jobName)) {
				shardList.add(createLocalShard(lastOnlineTrafficExecutorList, loadLevel));
			}
			return;
		}

		int shardingTotalCount = getShardingTotalCount(jobName);
		boolean hasShardRunning = hasShardRunning(lastOnlineTrafficExecutorList);
		if (preferListIsConfigured) {
			pickIntelligentWithPreferListConfigured(allEnableJobs, shardList, lastOnlineTrafficExecutorList,
					preferListConfigured, hasShardRunning, shardingTotalCount, loadLevel);

		} else {
			// 如果有分片正在运行,则平衡摘取
			if (hasShardRunning) {
				pickBalance(shardList, lastOnlineTrafficExecutorList);
			} else {
				// 如果没有分片正在运行,则需要新建,无需平衡摘取
				if (allEnableJobs.contains(jobName)) {
					shardList.addAll(createUnLocalShards(shardingTotalCount, loadLevel));
				}
			}
		}
	}

	public void pickIntelligentWithPreferListConfigured(List allEnableJobs, List shardList,
			List lastOnlineTrafficExecutorList, List preferListConfigured, boolean hasShardRunning,
			int shardingTotalCount, int loadLevel) throws Exception {
		boolean useDispreferList = useDispreferList(jobName); // 是否useDispreferList

		if (preferListConfigured.contains(executorName)) {
			// 如果有分片正在运行,摘取全部运行在非优先节点上的分片,还可以平衡摘取
			if (hasShardRunning) {
				shardList.addAll(pickShardsRunningInDispreferList(preferListConfigured, lastOnlineTrafficExecutorList));
				pickBalance(shardList, lastOnlineTrafficExecutorList);
			} else {
				// 如果没有分片正在运行,则需要新建,无需平衡摘取
				if (allEnableJobs.contains(jobName)) {
					shardList.addAll(createUnLocalShards(shardingTotalCount, loadLevel));
				}
			}
		} else {
			if (useDispreferList) {
				// 如果有分片正在运行,并且都是运行在非优先节点上,可以平衡摘取分片
				// 如果有分片正在运行,并且有运行在优先节点上,则摘取全部运行在非优先节点上的分片,不能再平衡摘取
				if (hasShardRunning) {
					boolean shardsAllRunningInDispreferList = shardsAllRunningInDispreferList(preferListConfigured,
							lastOnlineTrafficExecutorList);
					if (shardsAllRunningInDispreferList) {
						pickBalance(shardList, lastOnlineTrafficExecutorList);
					} else {
						shardList.addAll(
								pickShardsRunningInDispreferList(preferListConfigured, lastOnlineTrafficExecutorList));
					}
				} else {
					// 如果没有分片正在运行,则需要新建,无需平衡摘取
					if (allEnableJobs.contains(jobName)) {
						shardList.addAll(createUnLocalShards(shardingTotalCount, loadLevel));
					}
				}
			} else { // 不能再平衡摘取
				// 摘取全部运行在非优先节点上的分片
				shardList.addAll(pickShardsRunningInDispreferList(preferListConfigured, lastOnlineTrafficExecutorList));
			}
		}
	}

	@Override
	protected boolean pick(List allJobs, List allEnableJobs, List shardList,
			List lastOnlineExecutorList, List lastOnlineTrafficExecutorList) throws Exception {
		// 很小的可能性:status的新增事件先于ip的新增事件
		// 那么,如果lastOnlineExecutorList不包含executorName,则添加一个新的Executor
		// 添加当前作业至jobNameList
		Executor targetExecutor = null;
		for (int i = 0; i < lastOnlineExecutorList.size(); i++) {
			Executor executor = lastOnlineExecutorList.get(i);
			if (executor.getExecutorName().equals(executorName)) {
				targetExecutor = executor;
				break;
			}
		}
		if (targetExecutor == null) {
			targetExecutor = new Executor();
			targetExecutor.setExecutorName(executorName);
			targetExecutor.setIp(getExecutorIp());
			targetExecutor.setNoTraffic(getExecutorNoTraffic(executorName));
			targetExecutor.setShardList(new ArrayList());
			targetExecutor.setJobNameList(new ArrayList());
			targetExecutor.setTotalLoadLevel(0);
			lastOnlineExecutorList.add(targetExecutor);
			if (!targetExecutor.isNoTraffic()) {
				lastOnlineTrafficExecutorList.add(targetExecutor);
			}
		}
		if (!targetExecutor.getJobNameList().contains(jobName)) {
			targetExecutor.getJobNameList().add(jobName);
		}

		// 如果该Executor流量被摘取,则无需摘取,返回true
		if (targetExecutor.isNoTraffic()) {
			return true;
		}

		pickIntelligent(allEnableJobs, shardList, lastOnlineTrafficExecutorList);

		return true;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy