TBSchedule源码学习笔记-线程组任务调度

本文深入探讨了TBSchedule的线程组任务调度,解释了OwnSign在环境隔离中的作用,以及调度服务信息在任务管理中的重要性。详细分析了TBScheduleManager的构造过程,包括加载任务配置、清除过期信息、注册到调度中心客户端等步骤。此外,还讨论了zk节点的结构、调度服务数据的存储与更新,以及Sleep和NotSleep模式的区别。
摘要由CSDN通过智能技术生成

根据上文的启动过程,找到了线程组的实现。com.taobao.pamirs.schedule.taskmanager.TBScheduleManager

/**
 * 1、任务调度分配器的目标:    让所有的任务不重复,不遗漏的被快速处理。
 * 2、一个Manager只管理一种任务类型的一组工作线程。
 * 3、在一个JVM里面可能存在多个处理相同任务类型的Manager,也可能存在处理不同任务类型的Manager。
 * 4、在不同的JVM里面可以存在处理相同任务的Manager 
 * 5、调度的Manager可以动态的随意增加和停止
 * 
 * 主要的职责:
 * 1、定时向集中的数据配置中心更新当前调度服务器的心跳状态
 * 2、向数据配置中心获取所有服务器的状态来重新计算任务的分配。这么做的目标是避免集中任务调度中心的单点问题。
 * 3、在每个批次数据处理完毕后,检查是否有其它处理服务器申请自己把持的任务队列,如果有,则释放给相关处理服务器。
 *  
 * 其它:
 *   如果当前服务器在处理当前任务的时候超时,需要清除当前队列,并释放已经把持的任务。并向控制主动中心报警。
 * 
 * @author xuannan
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
abstract class TBScheduleManager implements IStrategyTask {
    //.......//
}

这个类的构造方法是这样的

TBScheduleManager(TBScheduleManagerFactory aFactory,String baseTaskType,String ownSign ,IScheduleDataManager aScheduleCenter) throws Exception{
        //.......//
    }  

这里发现有两个老朋友,aFactory就是那个调度服务器对象,baseTaskType是设置的平台类型,aScheduleCenter调度配置中心客户端接口,那么ownSign是什么?
以下取自官方文档:

OwnSign环境区域
是对运行环境的划分,进行调度任务和数据隔离。例如:开发环境、测试环境、预发环境、生产环境。
不同的开发人员需要进行数据隔离也可以用OwnSign来实现,避免不同人员的数据冲突。缺省配置的环境区域OwnSign=’BASE’。
例如:TaskType=’DataDeal’,配置的队列是0、1、2、3、4、5、6、7、8、9。缺省的OwnSign=’BASE’。
此时如果再启动一个测试环境,则Schedule会动态生成一个TaskType=’DataDeal-Test’的任务类型,环境会作为一个变量传递给业务接口,
由业务接口的实现类,在读取数据和处理数据的时候进行确定。业务系统一种典型的做法就是在数据表中增加一个OWN_SIGN字段。
在创建数据的时候根据运行环境填入对应的环境名称,在Schedule中就可以环境的区分了。

com.taobao.pamirs.schedule.taskmanager.IScheduleDataManager 这个接口要好好看下,定义的方法有点多,但是一眼看下来更多的方法是为控制台页面提供服务了,例如创建任务。诸如任务和任务相等信息的维护和查询都在这个接口中定义。

那么TBScheduleManager 这个构造函数就用到了一个,继续打开构造函数看

TBScheduleManager(TBScheduleManagerFactory aFactory,String baseTaskType,String ownSign ,IScheduleDataManager aScheduleCenter) throws Exception{
        this.factory = aFactory;
        //private static int nextSerialNumber = 0; 生成用户标志不同的线程序号,用于区分不同的线程组
        this.currentSerialNumber = serialNumber();
        this.scheduleCenter = aScheduleCenter;
        //按照任务类型加载调度任务信息
        this.taskTypeInfo = this.scheduleCenter.loadTaskTypeBaseInfo(baseTaskType);
        log.info("create TBScheduleManager for taskType:"+baseTaskType);
        //清除已经过期1天的TASK,OWN_SIGN的组合。超过一天没有活动server的视为过期
        //为什么要清除?如果任务确实能跑一天怎么办
        this.scheduleCenter.clearExpireTaskTypeRunningInfo(baseTaskType,ScheduleUtil.getLocalIP() + "清除过期OWN_SIGN信息",this.taskTypeInfo.getExpireOwnSignInterval());
        //通过调度服务器提供的方法获得对应的bean
        Object dealBean = aFactory.getBean(this.taskTypeInfo.getDealBeanName());
        if (dealBean == null) {
            throw new Exception( "SpringBean " + this.taskTypeInfo.getDealBeanName() + " 不存在");
        }
        //如果没有实现调度器对外的基础接口,肯定不能用啊
        if (dealBean instanceof IScheduleTaskDeal == false) {
            throw new Exception( "SpringBean " + this.taskTypeInfo.getDealBeanName() + " 没有实现 IScheduleTaskDeal接口");
        }
        this.taskDealBean = (IScheduleTaskDeal)dealBean;
        //任务的配置校验,为什么要大于5倍 出发点是什么
        if(this.taskTypeInfo.getJudgeDeadInterval() < this.taskTypeInfo.getHeartBeatRate() * 5){
            throw new Exception("数据配置存在问题,死亡的时间间隔,至少要大于心跳线程的5倍。当前配置数据:JudgeDeadInterval = "
                    + this.taskTypeInfo.getJudgeDeadInterval() 
                    + ",HeartBeatRate = " + this.taskTypeInfo.getHeartBeatRate());
        }
        //这个currenScheduleServer是类"com.taobao.pamirs.schedule.taskmanager.ScheduleServer"的实例,存储了当前调度服务的信息
        this.currenScheduleServer = ScheduleServer.createScheduleServer(this.scheduleCenter,baseTaskType,ownSign,this.taskTypeInfo.getThreadNumber());
        this.currenScheduleServer.setManagerFactoryUUID(this.factory.getUuid());
        //向调度中心客户端注册调度服务信息
        scheduleCenter.registerScheduleServer(this.currenScheduleServer);
        this.mBeanName = "pamirs:name=" + "schedule.ServerMananger." +this.currenScheduleServer.getUuid();
        //又启动了一个定时任务,看这名字就知道是心跳
        this.heartBeatTimer = new Timer(this.currenScheduleServer.getTaskType() +"-" + this.currentSerialNumber +"-HeartBeat");
        this.heartBeatTimer.schedule(new HeartBeatTimerTask(this),
                new java.util.Date(System.currentTimeMillis() + 500),
                this.taskTypeInfo.getHeartBeatRate());
        //对象创建时需要做的初始化工作,模版方法。
        initial();
    }  

目前能观察到的这个构造函数流程

1.按照任务名称加载任务配置
2.清除过期OWN_SIGN信息
3.检查任务配置是否正确
4.将调度服务信息注册到调度中心客户端
5.其他初始化操作

记录一下tbschedule对任务配置的存储方式(控制台页面”任务管理”)
控制台:
这里写图片描述
zk节点:
这里写图片描述

节点内容格式化之后

{
    "baseTaskType": "commonSyncAdvertiserTask",
    "heartBeatRate": 5000,
    "judgeDeadInterval": 60000,
    "sleepTimeNoData": 500,
    "sleepTimeInterval": 0,
    "fetchDataNumber": 500,
    "executeNumber": 10,
    "threadNumber": 5,
    "processorType": "SLEEP",
    "permitRunStartTime": "0 * * * * ?",
    "expireOwnSignInterval": 1,
    "dealBeanName": "commonSyncAdvertiserTask",
    "taskParameter": "3",
    "taskKind": "static",
    "taskItems": [
        "0",
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9"
    ],
    "maxTaskItemsOfOneThreadGroup": 0,
    "version": 0,
    "sts": "resume"
}

第4步主要包含以下代码行

//这个currenScheduleServer是类"com.taobao.pamirs.schedule.taskmanager.ScheduleServer"的实例,存储了当前调度服务的信息
this.currenScheduleServer = ScheduleServer.createScheduleServer(this.scheduleCenter,baseTaskType,ownSign,this.taskTypeInfo.getThreadNumber());
        this.currenScheduleServer.setManagerFactoryUUID(this.factory.getUuid());
        //向调度中心客户端注册调度服务信息
        scheduleCenter.registerScheduleServer(this.currenScheduleServer);

当前调度服务信息都包含什么,有什么是状态量,向调度中心客户端注册的意图是什么?打开ScheduleServer.createScheduleServer(this.scheduleCenter,baseTaskType,ownSign,this.taskTypeInfo.getThreadNu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值