今天给大家介绍一款新武器。我自研的一个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. 【面试篇】寒冬求职之你必须要懂的Web安全

    https://segmentfault.com/a/1190000019158228 随着互联网的发展,各种Web应用变得越来越复杂,满足了用户的各种需求的同时,各种网络安全问题也接踵而至.作为前端 ...

  2. Win8.1安装配置64位Oracle Database 11g的详细图文步骤记录

    在开始Oracle数据安装之前建议:1.关闭本机的病毒防火墙.2.断开互联网. 这样可以避免解压缩丢失文件和安装失败. Step1 Oracle官网下载好Windows系统64位的安装包,下载速度慢的 ...

  3. 深入理解RocketMQ(一)---阅读源码准备

    本文主要描述使用Idea获取rocketMQ源码及源码的读取. 在演示搭建源码环境前,先简要描述一下RocketMQ的设计目标. 1.架构模式 和大多数消息中间件一样,采用的是发布订阅模式,基本组件包 ...

  4. 一.前后端分离及drf实现序列化的原理

     为什么要进行前后端分离 可pc.app.pad多端适应 SPA开发模式的流行--单页web应用(只有一html页面) 可实现前后端开发职责清(不分离时,前端是通过后端给的变量并渲染出来方式拿到数据! ...

  5. return zero,or ,return non-zero

    it may return a value to its caller, which is in effect the environment in which the program was exe ...

  6. Netty 源码解析(八): 回到 Channel 的 register 操作

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  7. 前端开发,页面加载速度性能优化,如何提高web页面加载速度

    一个网页访问速度的快慢,  不仅看它服务器的配置,这里除去你空间主机配置很烂的情况以外,我们从网站开发方面来探讨,前端技术需要从哪些方面提高访问的速度,需要用到哪些技术手段. 文件的加载 图标的加载: ...

  8. 关于npm和yarn 安装vue脚手架

    第一篇博客有点小紧张.轻喷~ 第一步:安装node.js       地址 --------https://nodejs.org/en/ 详细步骤这里就不写了    可以去看     地址 ----- ...

  9. 云小课 | “VPC连接”知多少

    摘要:华为云提供了丰富的网络服务,可满足多种网络互连场景. 同Region的两个VPC怎么连通?” “跨Region的两个VPC又怎么连通?” “VPC内的ECS搭建了一个应用,需要访问Interne ...

  10. day17 生成器, 面向过程, 三元表达式, 生成式

    1. 生成器 生成器:就是一种自定义的迭代器,是用来返回多次值自定义迭代器的好处:节省内存 return只能返回一次值,函数就立即结束了yield 1.可以挂起函数,保存函数的运行状态 2.可以用来返 ...