轻量级分布式延时任务处理组件easyTask-L-入门篇
今天给大家介绍一款新武器。我自研的一个java组件easyTask-L。这个是做啥的呢?我之前研发了一款单机版本的easyTask,这次是要介绍另外一款easyTask-L。区别就是后者支持分布式环境,任务数据支持多个备份,具备了真正意义上的高可用。同时它又是轻量级的分布式应用,原因是因为它还不是一个独立的中间件,它需要一个宿主程序才能使用。做成独立的中间件是我后面要继续做的一个版本。
组件开源地址:https://github.com/liuche51/easyTask-L
废话不多说,先来介绍下easyTask-L组件的特性。

高可用:因为我们是分布式leader-follow集群,每个任务多有多个备份数据,所以可靠性非常高
秒级触发:我们是采用时钟秒级分片的数据结构,支持秒级触发任务。不早也不迟
分布式:组件支持分布式
高并发:支持多线程同时提交任务,支持多线程同时执行任务
数据一致性:使用TCC事务机制,保障数据在集群中的强一致性
海量任务:节点可以存储非常多的任务,只要内存和磁盘足够。触发效率也是极高。需要配置好分派任务线程池和执行任务线程池大小即可
开源:组件完全在GitHub上开源。任何人都可以随意使用,在不侵犯著作权情况下
易使用:无需独立部署集群,嵌入式开发。不过多的依赖于第三方中间件,除了zookeeper。
easyTask-L组件的整体架构如下:

整体采用分布式设计,leader-follow风格。集群中每一个节点都是leader,同时也可能是其他某个节点的follow。每个leader都有若干个follow。leader上提交的新任务都会强制同步到follow中,删除任务同时也会强制删除follow中的备份任务。集群中所有节点都会在zookeeper中注册并维持心跳。
easyTask-L组件的核心“环形队列”的设计架构如下:

环形队列在之前单机版的easyTask中也讲过,原理都是类似的。客户端提交任务,服务端先将任务进行持久化,再添加上环形队列这个数据结构中去,等待时间片轮询的到来。不同的是这里的持久化机制,改成了分布式存储了。不仅leader自己存储起来,还要同步存储到其follow中去。删除一个任务也是类似的过程。
任务添加时会计算其触发所属的时间分片槽,等环形队列的始终秒针到达时会判断任务是否可以被执行了。如果可以执行了,则分派任务线程池将其丢入执行任务线程池等待执行。只要执行任务线程池线程数足够,任务将立即得到执行。
大概的原理清晰了,接下来就是写个HelloWorld程序了!
easyTask-L不是一个中间件,所以需要一个宿主程式。建议在微服务框架如:dubbo、spring-cloud中使用此组件,并建立一个独立的专门用于处理延时任务的服务模块。这样可以使服务尽可能少的频繁更新重启。保持集群的稳定性。下面我将以一个springboot应用为例来给大家演示如何使用easyTask-L组件
第一步:引入jar包
如果你是Maven项目,可以使用如下方式配置引入jar包。这可以让项目自动引入easyTask-L中依赖的其他第三方jar包。最新版本请在maven中央仓库中查询。请在pom.xml中加入以下引用
<dependency>
<groupId>com.github.liuche51</groupId>
<artifactId>easyTask-L</artifactId>
<version>1.0.1</version>
</dependency>
第二步:配置启动环形队列
这里以springboot应用为例,在application.yml中做如下配置
server:
port: 8081
spring:
application:
name: easyTask-L
easyTaskL:
zkAddress: 127.0.0.1:2181
taskStorePath: C:/db/node1
serverPort: 2021
sQLlitePoolSize: 5
backupCount: 2
dispatchPool:
corePoolSize: 5
maximumPoolSize: 50
workPool:
corePoolSize: 5
maximumPoolSize: 50
新建一个启动配置类EasyTaskLConf.java

package com.github.liuche51.easyTaskL.config; import com.github.liuche51.easyTask.core.AnnularQueue;
import com.github.liuche51.easyTask.core.EasyTaskConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; @Configuration
public class EasyTaskLConf {
private static Logger log = LoggerFactory.getLogger(EasyTaskLConf.class);
@Value("${easyTaskL.zkAddress}")
private String zkAddress;
@Value("${easyTaskL.taskStorePath}")
private String taskStorePath;
@Value("${easyTaskL.serverPort}")
private int serverPort;
@Value("${easyTaskL.sQLlitePoolSize}")
private int sQLlitePoolSize;
@Value("${easyTaskL.backupCount}")
private int backupCount;
@Value("${easyTaskL.dispatchPool.corePoolSize}")
private int dispatchCorePoolSize;
@Value("${easyTaskL.dispatchPool.maximumPoolSize}")
private int dispatchMaximumPoolSize;
@Value("${easyTaskL.workPool.corePoolSize}")
private int workPoolCorePoolSize;
@Value("${easyTaskL.workPool.maximumPoolSize}")
private int workPoolMaximumPoolSize;
@Bean
public AnnularQueue initAnnularQueue(){
try {
EasyTaskConfig config =new EasyTaskConfig();
config.setTaskStorePath(taskStorePath);
config.setServerPort(serverPort);
config.setSQLlitePoolSize(sQLlitePoolSize);
//config.setBackupCount(backupCount);
config.setZkAddress(zkAddress);
AnnularQueue annularQueue = AnnularQueue.getInstance();
config.setDispatchs(new ThreadPoolExecutor(dispatchCorePoolSize, dispatchMaximumPoolSize, 1000, java.util.concurrent.TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
config.setWorkers(new ThreadPoolExecutor(workPoolCorePoolSize, workPoolMaximumPoolSize, 1000, java.util.concurrent.TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
annularQueue.start(config);
return annularQueue;
}catch (Exception e){
log.error("",e);
return null;
}
} }
EasyTaskLConf.java
第三步:建立延时任务处理类
package com.github.liuche51.easyTaskL.task;
import com.github.liuche51.easyTask.dto.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue; public class CusTask1 extends Task implements Runnable {
private static Logger log = LoggerFactory.getLogger(CusTask1.class);
@Override
public void run() {
Map<String, String> param = getParam();
if (param != null && param.size() > 0) {
log.info("任务1已执行!姓名:{} 生日:{} 年龄:{} 线程ID:{}", param.get("name"), param.get("birthday"), param.get("age"), param.get("threadid"));
}
}
}
第四步:向环形队列中添加任务
新建一个Controller,增加以下Action方法。
@RequestMapping("/once")
@ResponseBody
public String once(@RequestParam("name") String name, @RequestParam("time") int time) {
CusTask1 task1 = new CusTask1();
task1.setEndTimestamp(ZonedDateTime.now().plusSeconds(time).toInstant().toEpochMilli());
Map<String, String> param = new HashMap<String, String>() {
{
put("name", name);
put("birthday", "1996-1-1");
put("age", "28");
put("threadid", String.valueOf(Thread.currentThread().getId()));
}
};
task1.setParam(param);
return AnnularQueue.getInstance().submitAllowWait(task1);
}
完整的demo可以使用Git克隆我的一个开源项目:https://gitee.com/liuche/DubboServer.git 找到子项目easyTask-L-demo即可
轻量级分布式延时任务处理组件easyTask-L-入门篇的更多相关文章
- 新一代分布式实时流处理引擎Flink入门实战之先导理论篇-上
@ 目录 概述 定义 为什么使用Flink 应用行业和场景 应用行业 应用场景 实时数仓演变 Flink VS Spark 架构 系统架构 术语 无界和有界数据 流式分析基础 分层API 运行模式 作 ...
- .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)
在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下FluentValidation验证组件.那里只是概述了一下,并没有对其使用和强大功能做深入研究 ...
- 轻量级分布式 RPC 框架
@import url(/css/cuteeditor.css); 源码地址:http://git.oschina.net/huangyong/rpc RPC,即 Remote Procedure C ...
- 【转】轻量级分布式 RPC 框架
第一步:编写服务接口 第二步:编写服务接口的实现类 第三步:配置服务端 第四步:启动服务器并发布服务 第五步:实现服务注册 第六步:实现 RPC 服务器 第七步:配置客户端 第八步:实现服务发现 第九 ...
- .NET轻量级DBHelpers数据访问组件
一.摘要 一说到ADO.NET大家可能立刻想到的就是增.删.改.查(CRUD)操作,然后再接就想到项目中的SQLHelper.没错本课分享课阿笨给大家带来的是来源于github上开源的DAO数据库访问 ...
- NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(转载)
原文地址:http://www.cnblogs.com/asxinyu/p/dotnet_Opensource_project_FluentValidation_1.html 阅读目录 1.基本介绍 ...
- 轻量级分布式 RPC 框架(转)
RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Servi ...
- ZeroMQ——一个轻量级的消息通信组件
ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件".ZeroMQ是一个传输层API库, 更关 ...
- ZeroMQ——一个轻量级的消息通信组件 C#
ZeroMQ——一个轻量级的消息通信组件 ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件" ...
随机推荐
- 2、尚硅谷_SSM高级整合_创建Maven项目.avi
第一步我们新建立一个web工程 这里首先要勾选上enable的第一个复选框 这里要勾选上add maven support 我们在pom.xml中添加sevlet的依赖 创建java web项目之后, ...
- mysql 出现You can't specify target table for update in FROM clause错误的解决方法
mysql出现You can’t specify target table for update in FROM clause 这个错误的意思是不能在同一个sql语句中,先select同一个表的某些值 ...
- ubuntu无法安装vim、tree等解决办法
rm /etc/apt/sources.list.d/* 删除该目录下所有文件
- (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例)
(私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/1L54VuFwCdKVnQGVc8vD1TQnwmj java手册 Ja ...
- TensorFlow中的显存管理器——BFC Allocator
背景 作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 使用GPU训练时,一次训练任务无论是模型参数还是中间结果都需要占用大量显存.为了 ...
- HTML5(五)Geolocation
HTML5 Geolocation 定位用户的位置 HTML5 Geolocation API 用于获得用户的地理位置. 鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的. 注意 ...
- 一文说清 KubeSphere 容器平台的价值
KubeSphere 作为云原生家族 后起之秀,开源近两年的时间以来收获了诸多用户与开发者的认可.本文通过大白话从零诠释 KubeSphere 的定位与价值,以及不同团队为什么会选择 KubeSphe ...
- Traffic Real Time Query System,题解
题目链接 题意: 问从一条边到另一条边的必经点. 分析: 首先,问必经点,当然是要点双缩点(圆方树)啦,关键是把边映射到哪一点上,其实直接放在某联通分量的方点上就行,但是这个点并不好找,所以我们考虑一 ...
- 14.刚体组件Rigidbody
刚体组件是物理类组件,添加有刚体组件的物体,会像现实生活中的物体一样有重力.会下落.能碰撞. 给物体添加刚体: 选中游戏物体->菜单Component->Physics->Rigid ...
- 12个Visual Studio调试效率技巧
在这篇文章中,我们假定读者了解VS基本的调试知识,如: F5 开始使用调试器运行程序 F9 在当前行设置断点 F10 运行到下一个断点处 F5 从被调试的已停止程序恢复执行 F11 步进到函数内(如果 ...