今天给大家介绍一款新武器。我自研的一个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-入门篇的更多相关文章

  1. 新一代分布式实时流处理引擎Flink入门实战之先导理论篇-上

    @ 目录 概述 定义 为什么使用Flink 应用行业和场景 应用行业 应用场景 实时数仓演变 Flink VS Spark 架构 系统架构 术语 无界和有界数据 流式分析基础 分层API 运行模式 作 ...

  2. .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)

    在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下FluentValidation验证组件.那里只是概述了一下,并没有对其使用和强大功能做深入研究 ...

  3. 轻量级分布式 RPC 框架

    @import url(/css/cuteeditor.css); 源码地址:http://git.oschina.net/huangyong/rpc RPC,即 Remote Procedure C ...

  4. 【转】轻量级分布式 RPC 框架

    第一步:编写服务接口 第二步:编写服务接口的实现类 第三步:配置服务端 第四步:启动服务器并发布服务 第五步:实现服务注册 第六步:实现 RPC 服务器 第七步:配置客户端 第八步:实现服务发现 第九 ...

  5. .NET轻量级DBHelpers数据访问组件

    一.摘要 一说到ADO.NET大家可能立刻想到的就是增.删.改.查(CRUD)操作,然后再接就想到项目中的SQLHelper.没错本课分享课阿笨给大家带来的是来源于github上开源的DAO数据库访问 ...

  6. NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(转载)

    原文地址:http://www.cnblogs.com/asxinyu/p/dotnet_Opensource_project_FluentValidation_1.html 阅读目录 1.基本介绍 ...

  7. 轻量级分布式 RPC 框架(转)

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Servi ...

  8. ZeroMQ——一个轻量级的消息通信组件

    ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件".ZeroMQ是一个传输层API库, 更关 ...

  9. ZeroMQ——一个轻量级的消息通信组件 C#

    ZeroMQ——一个轻量级的消息通信组件 ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件" ...

随机推荐

  1. 小师妹学JVM之:JIT中的PrintCompilation

    目录 简介 PrintCompilation 分析PrintCompilation的结果 总结 简介 上篇文章我们讲到了JIT中的LogCompilation,将编译的日志都收集起来,存到日志文件里面 ...

  2. msf stagers开发不完全指北(二)

    采用 Golang 开发stagers 上一篇文章 msf stagers开发不完全指北(一)中我们谈到如何采用 c 进行 msf 的 stagers 开发,这篇文章我们探讨一下如何使用 Golang ...

  3. vue全家桶(4.1)

    5.状态管理 5.1.兄弟组件之间共享数据的问题? 首先,我们需要了解下兄弟组件之间如何共享数据的问题 完成下列需求: 1.点击按钮,改变商品数量 2.点击加入购物车,在购物车的这个div盒子里需要显 ...

  4. could not resolve property(无法解析属性)

    could not resolve property(无法解析属性) 顾名思义在写hql语句的时候,属性写错了! 请检查大小写,是实体类的,不是数据库表的! 一个一个检查,仔细看!

  5. 调用微信内置的方法及wx.config的配置问题

    首先请看网址: https://www.w3cschool.cn/weixinkaifawendang/h8ap1qe5.html 重点说下怎么配置wx.config(为了安全,所有的参数都在服务端获 ...

  6. docker 在centos7中设置 DOCKER_OPTS

    不同于Ubuntu目录 /etc/default/docker. 在 CentOS7中Docker默认配置的路径在 /usr/lib/systemd/system/docker.service [例如 ...

  7. Javascript 中 数组遍历 forin和forof 的区别

    定义一个数组 let array = [1, 2, 3, 4]; for (let a in array){ console.log("遍历a的值 "+a+"”,数组中的 ...

  8. Apache DolphinScheduler(海豚调度) - 1.3 系列核心表结构剖析

    Apache DolphinScheduler 是一个分布式去中心化,易扩展的可视化 DAG 工作流任务调度系统.致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数据处理流程中开箱即用. 近日 ...

  9. Sta,题解

    题目: 分析: 这个有点过于简单,两次Dfs处理出Dp[i],Son[i],Deep[i],Val[i](分别表示以1为根时i所有子树的深度之和,以1为根时i子树节点个数,以1为根时i深度,以i为根时 ...

  10. dotNetCore阅读源码-CreateDefaultBuilder及ConfigureWebHostDefaults内部

    版本:DotNetCore 3.1 CreateDefaultBuilder内部源码: public static IHostBuilder CreateDefaultBuilder(string[] ...