任务数分配

This commit is contained in:
huangsimin 2022-08-02 18:19:26 +08:00
parent c339e6e3f0
commit 42e66efe67
7 changed files with 146 additions and 39 deletions

10
.vscode/launch.json vendored
View File

@ -4,6 +4,13 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"type": "java",
"name": "Launch Utils",
"request": "launch",
"mainClass": "com.yuandian.dataflow.utils.Utils",
"projectName": "dataflow"
},
{ {
"type": "java", "type": "java",
"name": "Raft-0", "name": "Raft-0",
@ -57,8 +64,7 @@
"group": "", "group": "",
"order": 3 "order": 3
} }
}, }
], ],
"compounds": [ "compounds": [

View File

@ -1,12 +1,16 @@
package com.yuandian.dataflow.controller; package com.yuandian.dataflow.controller;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.alipay.sofa.jraft.Status; import com.alipay.sofa.jraft.Status;
import com.alipay.sofa.jraft.entity.PeerId;
import com.alipay.sofa.jraft.error.RemotingException; import com.alipay.sofa.jraft.error.RemotingException;
import com.alipay.sofa.jraft.rpc.InvokeCallback; import com.alipay.sofa.jraft.rpc.InvokeCallback;
import com.google.protobuf.Any; import com.google.protobuf.Any;
@ -21,6 +25,7 @@ import com.yuandian.dataflow.statemachine.operate.Operate;
import com.yuandian.dataflow.statemachine.operate.Operate.OperateType; import com.yuandian.dataflow.statemachine.operate.Operate.OperateType;
import com.yuandian.dataflow.statemachine.state.State; import com.yuandian.dataflow.statemachine.state.State;
import com.yuandian.dataflow.statemachine.state.WorkerState; import com.yuandian.dataflow.statemachine.state.WorkerState;
import com.yuandian.dataflow.utils.Utils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -28,69 +33,107 @@ import lombok.extern.slf4j.Slf4j;
@MasterRegister @MasterRegister
public class MasterProcessor implements MasterExecute { public class MasterProcessor implements MasterExecute {
/**
* 最大任务数限制
*/
private final int MAX_TASKS = 100; private final int MAX_TASKS = 100;
private final int DEFAULT_ASYNC_TIMEOUT = 5000;
public static Random rand = new Random();
@Override @Override
public void loop(MasterContext cxt) { public void loop(MasterContext cxt) {
// try { ArrayList<Any> packets = new ArrayList<>();
// Thread.sleep(1000); // 模拟发送包的数据到该节点上
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block for (int i = 0; i < ThreadLocalRandom.current().nextLong(1000, 5000); i++) {
// e.printStackTrace(); var p = Any.pack(BacktrackingFlowOuterClass.BacktrackingFlow
// } .newBuilder()
.setTableId(10086)
.build());
packets.add(p);
}
// 必须复制. raft有一直使用该list
var alivePeers = List.copyOf(StateFactory.getRaftNode().listAlivePeers()); var alivePeers = List.copyOf(StateFactory.getRaftNode().listAlivePeers());
log.debug("master({}) execute {}", StateFactory.getServerId(), alivePeers); log.debug("master({}) execute {}", StateFactory.getServerId(), alivePeers);
if (alivePeers == null) { if (alivePeers == null) {
cxt.sleep(100); // 休眠100毫秒.
return; return;
} }
var peerSize = alivePeers.size();
// 等待全部反馈后才能进入下次循环
CountDownLatch latch = new CountDownLatch(alivePeers.size()); CountDownLatch latch = new CountDownLatch(alivePeers.size());
// 读一致性 // 读一致性
StateFactory.readIndexState(new GenericClosure() { StateFactory.readIndexState(new GenericClosure() {
@Override @Override
public void run(Status status) { public void run(Status status) {
var state = this.<State>getValue();
// log.debug("masterExecute start {} {}", status, alivePeers); // log.debug("masterExecute start {} {}", status, alivePeers);
var state = this.<State>getValue();
alivePeers.forEach((peer) -> { if (state == null) {
log.error("readIndexState获取的状态为 {}", state);
return;
}
PeerId[] peers = new PeerId[alivePeers.size()];
alivePeers.toArray(peers);
if (state == null) { var canTasks = new int[alivePeers.size()];
log.error("readIndexState获取的状态为 {}", state);
for(int i = 0; i < peers.length; i++) {
var peer = peers[i];
WorkerState ws = state.getWorkers().get(peer);
if (ws == null) {
log.error("WorkerState获取的状态为 {}", ws);
return; return;
} }
var can = MAX_TASKS - ws.getTaskQueueSize();
canTasks[i] = can;
}
var allocTasks = Utils.allocationTasks(packets.size(), canTasks);
for(int i = 0; i < peers.length; i++) {
var peer = peers[i];
WorkerState ws = state.getWorkers().get(peer); WorkerState ws = state.getWorkers().get(peer);
if (ws == null) { if (ws == null) {
log.error("WorkerState获取的状态为 {}", ws); log.error("WorkerState获取的状态为 {}", ws);
return; return;
} }
var canTasks = MAX_TASKS - ws.getTaskQueueSize(); // TODO: 处理完善的任务数量
if(canTasks > 0) { allocTasks;
log.info("剩余能处理的任务数量[{}] :{}", peer, canTasks); log.info("剩余能处理的任务数量[{}] :{}", peer, canTasks);
}
if (canTasks <= 0) {
return;
}
ws.setUpdateAt(Instant.now()); ws.setUpdateAt(Instant.now());
ws.setTaskQueueSize(MAX_TASKS); ws.setTaskQueueSize(MAX_TASKS);
// 模拟发送包的数据到该节点上 // 模拟发送包的数据到该节点上
var request = new PacketsRequest(); // var request = new PacketsRequest();
for (int i = 0; i < canTasks; i++) { // for (int i = 0; i < canTasks; i++) {
var p = Any.pack(BacktrackingFlowOuterClass.BacktrackingFlow // var p = Any.pack(BacktrackingFlowOuterClass.BacktrackingFlow
.newBuilder() // .newBuilder()
.setTableId(10086) // .setTableId(10086)
.build()); // .build());
request.getPackets().add(p); // request.getPackets().add(p);
} // }
// 先提交 节点的 剩余能处理的任务数量. 然后再处理 // 先提交 节点的 剩余能处理的任务数量. 然后再处理
var request = new PacketsRequest(); // 数据包切片
request.setPackets(packets);
Operate.CallOperate( Operate.CallOperate(
new Operate(OperateType.PUT_WORKERSTATE, ws), new Operate(OperateType.PUT_WORKERSTATE, ws),
new GenericClosure() { new GenericClosure() {
@ -109,14 +152,14 @@ public class MasterProcessor implements MasterExecute {
} }
// log.debug("PacketsRequest: {}", result); // log.debug("PacketsRequest: {}", result);
} }
}, 5000); }, DEFAULT_ASYNC_TIMEOUT);
} catch (InterruptedException | RemotingException e) { } catch (InterruptedException | RemotingException e) {
log.info("error send packets {}", e.toString()); log.info("error send packets {}", e.toString());
} }
} }
}); });
}); }
} }
@ -124,7 +167,7 @@ public class MasterProcessor implements MasterExecute {
}); });
try { try {
latch.await(5000, TimeUnit.MILLISECONDS); latch.await(DEFAULT_ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
log.error("{}", e.toString()); log.error("{}", e.toString());
} }

View File

@ -45,7 +45,7 @@ public class PacketsProcessor implements RpcProcessor<PacketsProcessor.PacketsRe
private ArrayList<Any> packets = new ArrayList<>(); private ArrayList<Any> packets = new ArrayList<>();
} }
public static Random rand = new Random();
@Override @Override
public void handleRequest(RpcContext rpcCtx, PacketsRequest request) { public void handleRequest(RpcContext rpcCtx, PacketsRequest request) {

View File

@ -6,10 +6,9 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MasterContext { public class MasterContext {
private AtomicBoolean isExit = new AtomicBoolean(false); private AtomicBoolean isExit = new AtomicBoolean(false);
private Object share; private Object share;
public Boolean getIsExit() { public Boolean getIsExit() {
@ -27,4 +26,13 @@ public class MasterContext {
public void setShare(Object share) { public void setShare(Object share) {
this.share = share; this.share = share;
} }
public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
log.error("{}",e);
this.setIsExit(true); // 设置推出. 在下个循环退出
}
}
} }

View File

@ -23,6 +23,8 @@ import lombok.extern.slf4j.Slf4j;
@Data @Data
public class Operate implements Serializable { public class Operate implements Serializable {
private static int DEFAULT_ASYNC_TIMEOUT = 5000;
public static enum OperateType { public static enum OperateType {
/** /**
* 同步WorkerState状态. * 同步WorkerState状态.
@ -85,7 +87,7 @@ public class Operate implements Serializable {
closure.run(Status.OK()); closure.run(Status.OK());
} }
}, 5000); }, DEFAULT_ASYNC_TIMEOUT);
} catch (InterruptedException | RemotingException e) { } catch (InterruptedException | RemotingException e) {
closure.failure(e.getMessage(), null); closure.failure(e.getMessage(), null);
closure.run(new Status(100000, "invokeAsync fail")); closure.run(new Status(100000, "invokeAsync fail"));
@ -93,4 +95,7 @@ public class Operate implements Serializable {
} }
} }
} }

View File

@ -35,7 +35,7 @@ public class WorkerState implements Serializable {
/** /**
* 任务队列的数量 * 任务队列的数量
*/ */
public long taskQueueSize; public int taskQueueSize;
/** /**
* 更新时间 * 更新时间
*/ */

View File

@ -1,5 +1,10 @@
package com.yuandian.dataflow.utils; package com.yuandian.dataflow.utils;
import java.util.ArrayList;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Utils { public class Utils {
@ -37,5 +42,45 @@ public class Utils {
return pos; return pos;
} }
/**
* 负载分配算法
* @param total 总的任务数
* @param canTasks 每个节点可以处理的任务数
* @return 返回每个节点应该分配的任务数
*/
public static int[] allocationTasks(int total, int[] canTasks) {
int[] atasks = new int[canTasks.length];
int totalCans = 0;
for(var i = 0;i < canTasks.length;i++) {
var can = canTasks[i];
totalCans += can;
}
if(total - totalCans > 0) {
for(var i = 0;i < canTasks.length;i++) {
atasks[i] = canTasks[i];
}
return atasks;
}
// 剩下来的平均值
int remainAvg = (totalCans - total) / canTasks.length;
for(var i = 0;i < canTasks.length;i++) {
var can = canTasks[i];
if(remainAvg <= can) {
atasks[i] = can - remainAvg;
}
}
return atasks;
}
} }