parent
5370a8b3dc
commit
9c03285d94
|
@ -145,7 +145,7 @@ CREATE TABLE XXL_JOB_QRTZ_LOCKS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE XXL_JOB_QRTZ_TRIGGER_INFO (
|
CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`job_group` int(11) NOT NULL COMMENT '任务组(执行器ID)',
|
`job_group` int(11) NOT NULL COMMENT '任务组(执行器ID)',
|
||||||
`job_name` varchar(255) NOT NULL COMMENT '任务名',
|
`job_name` varchar(255) NOT NULL COMMENT '任务名',
|
||||||
|
@ -155,6 +155,7 @@ CREATE TABLE XXL_JOB_QRTZ_TRIGGER_INFO (
|
||||||
`update_time` datetime DEFAULT NULL,
|
`update_time` datetime DEFAULT NULL,
|
||||||
`author` varchar(64) DEFAULT NULL COMMENT '作者',
|
`author` varchar(64) DEFAULT NULL COMMENT '作者',
|
||||||
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
|
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
|
||||||
|
`executor_route_strategy` varchar(20) DEFAULT NULL COMMENT '执行器路由策略',
|
||||||
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
|
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
|
||||||
`executor_param` varchar(255) DEFAULT NULL COMMENT '执行器任务参数',
|
`executor_param` varchar(255) DEFAULT NULL COMMENT '执行器任务参数',
|
||||||
`glue_switch` int(11) DEFAULT '0' COMMENT 'GLUE模式开关:0-否,1-是',
|
`glue_switch` int(11) DEFAULT '0' COMMENT 'GLUE模式开关:0-否,1-是',
|
||||||
|
@ -164,7 +165,6 @@ CREATE TABLE XXL_JOB_QRTZ_TRIGGER_INFO (
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_LOG` (
|
CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_LOG` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`job_group` int(11) NOT NULL COMMENT '任务组',
|
`job_group` int(11) NOT NULL COMMENT '任务组',
|
||||||
|
|
|
@ -21,8 +21,9 @@ public class XxlJobInfo {
|
||||||
private String author; // 负责人
|
private String author; // 负责人
|
||||||
private String alarmEmail; // 报警邮件
|
private String alarmEmail; // 报警邮件
|
||||||
|
|
||||||
private String executorHandler; // 执行器,任务Handler名称
|
private String executorRouteStrategy; // 执行器路由策略
|
||||||
private String executorParam; // 执行器,任务参数
|
private String executorHandler; // 执行器,任务Handler名称
|
||||||
|
private String executorParam; // 执行器,任务参数
|
||||||
|
|
||||||
private int glueSwitch; // GLUE模式开关:0-否,1-是
|
private int glueSwitch; // GLUE模式开关:0-否,1-是
|
||||||
private String glueSource; // GLUE源代码
|
private String glueSource; // GLUE源代码
|
||||||
|
@ -105,7 +106,15 @@ public class XxlJobInfo {
|
||||||
this.alarmEmail = alarmEmail;
|
this.alarmEmail = alarmEmail;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getExecutorHandler() {
|
public String getExecutorRouteStrategy() {
|
||||||
|
return executorRouteStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecutorRouteStrategy(String executorRouteStrategy) {
|
||||||
|
this.executorRouteStrategy = executorRouteStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecutorHandler() {
|
||||||
return executorHandler;
|
return executorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.xxl.job.admin.core.route;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.strategy.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public enum ExecutorRouteStrategyEnum {
|
||||||
|
|
||||||
|
FIRST("第一个", new ExecutorRouteFirst()),
|
||||||
|
LAST("最后一个", new ExecutorRouteLast()),
|
||||||
|
ROUND("轮询", new ExecutorRouteRound()),
|
||||||
|
RANDOM("随机", new ExecutorRouteRandom()),
|
||||||
|
CONSISTENT_HASH("一致性HASH", new ExecutorRouteConsistentHash()),
|
||||||
|
FAILOVER("故障转移", null);
|
||||||
|
|
||||||
|
ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
|
||||||
|
this.title = title;
|
||||||
|
this.router = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private ExecutorRouter router;
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
public ExecutorRouter getRouter() {
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem){
|
||||||
|
for (ExecutorRouteStrategyEnum item: ExecutorRouteStrategyEnum.values()) {
|
||||||
|
if (item.name().equals(name)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.xxl.job.admin.core.route;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public abstract class ExecutorRouter {
|
||||||
|
|
||||||
|
public abstract String route(int jobId, ArrayList<String> addressList);
|
||||||
|
|
||||||
|
public static String route(int jobId, ArrayList<String> addressList, String executorRouteStrategy){
|
||||||
|
if (CollectionUtils.isEmpty(addressList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ExecutorRouteStrategyEnum strategy = ExecutorRouteStrategyEnum.match(executorRouteStrategy, ExecutorRouteStrategyEnum.FIRST);
|
||||||
|
String routeAddress = strategy.getRouter().route(jobId, addressList);
|
||||||
|
return routeAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
int c1 = 0;
|
||||||
|
int c2 = 0;
|
||||||
|
int c3 = 0;
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
String ret = ExecutorRouter.route(i, new ArrayList<String>(Arrays.asList("127.0.0.1:0000", "127.0.0.1:2222", "127.0.0.1:3333")), ExecutorRouteStrategyEnum.CONSISTENT_HASH.name());
|
||||||
|
if (ret.equals("127.0.0.1:0000")) {
|
||||||
|
c1++;
|
||||||
|
} else if (ret.equals("127.0.0.1:2222")) {
|
||||||
|
c2++;
|
||||||
|
} else if (ret.equals("127.0.0.1:3333")) {
|
||||||
|
c3++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
System.out.println(end - start); // 1000*100=740、1000*1=162、
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println(c1);
|
||||||
|
System.out.println(c2);
|
||||||
|
System.out.println(c3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.xxl.job.admin.core.route.strategy;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分组下JOB均匀散列在不同机器上;且每个JOB固定调度其中一台机器;
|
||||||
|
* a、virtual node:解决不均衡问题
|
||||||
|
* b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public class ExecutorRouteConsistentHash extends ExecutorRouter {
|
||||||
|
|
||||||
|
private static int VIRTUAL_NODE_NUM = 5;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String route(int jobId, ArrayList<String> addressList) {
|
||||||
|
|
||||||
|
// ------A1------A2-------A3------
|
||||||
|
// -----------J1------------------
|
||||||
|
TreeMap<Long, String> addressRing = new TreeMap<Long, String>();
|
||||||
|
for (String address: addressList) {
|
||||||
|
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
|
||||||
|
long addressHash = hash("SHARD-" + address + "-NODE-" + i);
|
||||||
|
addressRing.put(addressHash, address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long jobHash = hash(String.valueOf(jobId));
|
||||||
|
SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);
|
||||||
|
if (!lastRing.isEmpty()) {
|
||||||
|
return lastRing.get(lastRing.firstKey());
|
||||||
|
}
|
||||||
|
return addressRing.firstEntry().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get hash code on 2^32 ring (md5散列的方式计算hash值)
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static long hash(String key) {
|
||||||
|
|
||||||
|
// md5 byte
|
||||||
|
MessageDigest md5;
|
||||||
|
try {
|
||||||
|
md5 = MessageDigest.getInstance("MD5");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("MD5 not supported", e);
|
||||||
|
}
|
||||||
|
md5.reset();
|
||||||
|
byte[] keyBytes = null;
|
||||||
|
try {
|
||||||
|
keyBytes = key.getBytes("UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException("Unknown string :" + key, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
md5.update(keyBytes);
|
||||||
|
byte[] digest = md5.digest();
|
||||||
|
|
||||||
|
// hash code, Truncate to 32-bits
|
||||||
|
long hashCode = ((long) (digest[3] & 0xFF) << 24)
|
||||||
|
| ((long) (digest[2] & 0xFF) << 16)
|
||||||
|
| ((long) (digest[1] & 0xFF) << 8)
|
||||||
|
| (digest[0] & 0xFF);
|
||||||
|
|
||||||
|
long truncateHashCode = hashCode & 0xffffffffL;
|
||||||
|
return truncateHashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.xxl.job.admin.core.route.strategy;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public class ExecutorRouteFirst extends ExecutorRouter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String route(int jobId, ArrayList<String> addressList) {
|
||||||
|
return addressList.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.xxl.job.admin.core.route.strategy;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public class ExecutorRouteLast extends ExecutorRouter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String route(int jobId, ArrayList<String> addressList) {
|
||||||
|
return addressList.get(addressList.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.xxl.job.admin.core.route.strategy;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public class ExecutorRouteRandom extends ExecutorRouter {
|
||||||
|
|
||||||
|
private static Random localRandom = new Random();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String route(int jobId, ArrayList<String> addressList) {
|
||||||
|
return addressList.get(localRandom.nextInt(addressList.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.xxl.job.admin.core.route.strategy;
|
||||||
|
|
||||||
|
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuxueli on 17/3/10.
|
||||||
|
*/
|
||||||
|
public class ExecutorRouteRound extends ExecutorRouter {
|
||||||
|
|
||||||
|
private static ConcurrentHashMap<Integer, Integer> routeCountEachJob = new ConcurrentHashMap<Integer, Integer>();
|
||||||
|
private static int count(int jobId) {
|
||||||
|
Integer count = routeCountEachJob.get(jobId);
|
||||||
|
count = (count==null)?0:++count;
|
||||||
|
routeCountEachJob.put(jobId, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String route(int jobId, ArrayList<String> addressList) {
|
||||||
|
return addressList.get(count(jobId)%addressList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
<result column="author" property="author" />
|
<result column="author" property="author" />
|
||||||
<result column="alarm_email" property="alarmEmail" />
|
<result column="alarm_email" property="alarmEmail" />
|
||||||
|
|
||||||
|
<result column="executor_route_strategy" property="executorRouteStrategy" />
|
||||||
<result column="executor_handler" property="executorHandler" />
|
<result column="executor_handler" property="executorHandler" />
|
||||||
<result column="executor_param" property="executorParam" />
|
<result column="executor_param" property="executorParam" />
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
t.update_time,
|
t.update_time,
|
||||||
t.author,
|
t.author,
|
||||||
t.alarm_email,
|
t.alarm_email,
|
||||||
|
t.executor_route_strategy,
|
||||||
t.executor_handler,
|
t.executor_handler,
|
||||||
t.executor_param,
|
t.executor_param,
|
||||||
t.glue_switch,
|
t.glue_switch,
|
||||||
|
@ -83,6 +85,7 @@
|
||||||
update_time,
|
update_time,
|
||||||
author,
|
author,
|
||||||
alarm_email,
|
alarm_email,
|
||||||
|
executor_route_strategy,
|
||||||
executor_handler,
|
executor_handler,
|
||||||
executor_param,
|
executor_param,
|
||||||
glue_switch,
|
glue_switch,
|
||||||
|
@ -98,6 +101,7 @@
|
||||||
NOW(),
|
NOW(),
|
||||||
#{author},
|
#{author},
|
||||||
#{alarmEmail},
|
#{alarmEmail},
|
||||||
|
#{executorRouteStrategy},
|
||||||
#{executorHandler},
|
#{executorHandler},
|
||||||
#{executorParam},
|
#{executorParam},
|
||||||
#{glueSwitch},
|
#{glueSwitch},
|
||||||
|
@ -125,6 +129,7 @@
|
||||||
update_time = NOW(),
|
update_time = NOW(),
|
||||||
author = #{author},
|
author = #{author},
|
||||||
alarm_email = #{alarmEmail},
|
alarm_email = #{alarmEmail},
|
||||||
|
executor_route_strategy = #{executorRouteStrategy},
|
||||||
executor_handler = #{executorHandler},
|
executor_handler = #{executorHandler},
|
||||||
executor_param = #{executorParam},
|
executor_param = #{executorParam},
|
||||||
glue_switch = #{glueSwitch},
|
glue_switch = #{glueSwitch},
|
||||||
|
|
Loading…
Reference in New Issue