基于数据库版本的分布式定时任务调度中心

2023-11-04

github调度中心源码地址:https://github.com/yomea/timer-task-scheduler
github业务端源码地址:https://github.com/yomea/task-scheduler-starter

gitee调度中心源码地址:https://gitee.com/yomea/timer-task-scheduler
gitee业务端源码地址:https://gitee.com/yomea/task-scheduler-starter

一、需求

构建一个统一的调度系统,用于触发定时任务的调度。

二、方案设计

2.1 方案1:快速迭代方案-基于数据库的集群调度

编写一个基于数据库锁(定时任务 id 做唯一键)与公司rpc框架相结合的轻量级定时任务调度中心

2.2 方案2:基于master选举的分布式定时任务调度方案

(可使用开源项目框架,但目前基本都是ZK的,受限与公司现状,可自行开发redis版本) -》分布式任务调度:https://blog.csdn.net/qq_27785239/article/details/120578171?spm=1001.2014.3001.5502

注意:定时任务调度任务唯一标识:任务id

三、架构设计

根据公司现状与简化开发工作量,我们选择方案1,方案1的大体架构如下:

image

从架构上看,架构总体分为 调度中心(只调度,不做具体业务处理)与业务中心(把用户的机器当作worker处理任务),从技术选型上来看它只使用了MySql,rpc框架,这对于一个互联网公司来说是标配。

它有以下几个优点:

  • 只需要MySql,RPC框架(dubbo,springCloud等都行)。
  • 调度中心与worker机器的通信可通过rpc框架来支撑
  • 负载均衡与worker机器的下线上线,心跳全由rpc框架处理
  • 采用数据库锁控制调度中心集群对任务的唯一调度
  • 如果任务支持分片,那么可以实现任务分片回调,通过rpc框架获取到的机器地址进行分发

缺点:

  • 基于数据库锁,如果调度中心集群比较大,会给数据库造成压力。

四、业务流程图

调度中心某节点大致内部流程

在这里插入图片描述

五、数据库表设计

5.1 核心表设计

  • 调度任务分布式锁

用于调度中心集群触发任务时的分布式锁,避免同时调度

create table ts_task_lock (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
	`smc_start_time` bigint(20) NOT NULL COMMENT '开始执行时间,msg',
	`smc_def_id` bigint(20) not null COMMENT '任务定义id',
	`smc_def_pid` bigint(20) default -1 COMMENT '父任务定义id',
	`smc_time_out` bigint(20) not null default -1  COMMENT '任务执行超时时间,超时时需要释放锁',
	`smc_ip` varchar(16) not null COMMENT '调度的机器ip',
	`smc_status` int not null COMMENT '执行状态,-1:失败,1:执行中,2:执行超时,3:执行完成',
  	PRIMARY KEY (`id`),
	unique uk_did_tt(smc_def_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
  • 任务定义

用于记录该任务如何调度

create table ts_task_def (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
	`smc_def_pid` bigint(20) default -1 COMMENT '父任务定义id',
	`smc_top_pid` bigint(20) default -1 COMMENT '顶级父任务定义id',
	`smc_task_name` varchar(512) not null COMMENT '任务名称',
	`app_service_name` varchar(64) not null COMMENT '注册到注册中心的服务名',
	`api_service_name` varchar(64) not null COMMENT '接口服务名',
	`api_method_name` varchar(64) not null COMMENT '接口方法名,为了简单明了,方法不要重载',
	`smc_conf_flag` int default 0 COMMENT '配置标记,预留字段',
	`smc_timeout` bigint(20) not null default -1 COMMENT '任务执行超时时间,单位ms,超时将视为执行失败,会重跑,-1表示永不超时',
	`smc_status` int not null default 1 COMMENT '任务是否启动,1:启动,-1:禁用',
	`smc_has_child` tinyint not null default 0 COMMENT '是否存在子节点,1:有,0:没有',
		
  	PRIMARY KEY (`id`),
	key idx_top_pid(smc_top_pid)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
  • 任务定时器

配置任务的定时器,每个任务可以有多个定时器,根据时间段来启动

create table ts_task_timer (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
    `smc_def_id` bigint not null COMMENT '任务定义ID',
	`smc_timer_type` int  default 1 COMMENT '1:cron, 2: 固定定时,3:固定延时,4:一次延时',
	`smc_init_delay` bigint default 0 COMMENT '初始延时时间',
	`smc_once_delay` bigint default 0 COMMENT '延时时间',
	`smc_start_day` datetime COMMENT '定时器有效开启时间',
	`smc_end_day` datetime COMMENT '定时器有效结束时间',
	`smc_period` bigint COMMENT '定时周期',
	`smc_cron` varchar(16) COMMENT 'cron表达式',
	`smc_status` int default 1 COMMENT '状态,-1:禁用,1:启动',
		
  	PRIMARY KEY (`id`),
	key idx_did_set(`smc_def_id`,`smc_start_day`,`smc_end_day`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
  • 任务记录

每个任务的触发记录,按月份分表

create table ts_task_record (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
	`smc_stime` datetime COMMENT '执行开始时间',
	`smc_etime` datetime COMMENT '执行结束时间',
    `smc_def_id` bigint  not null COMMENT '任务定义ID',
	`smc_task_name` varchar(512) not null COMMENT '任务名称',
	`smc_timeout` bigint(20) not null default -1 COMMENT '任务执行超时时间,超时将视为执行失败,会重跑',
	`smc_status` int not null COMMENT '任务状态,-1:失败,1:执行中,2:执行超时,3:执行完成',
	`smc_error` varchar(1024) COMMENT '失败原因',
	`smc_desc` varchar(1024) COMMENT '描述',
	`smc_ip` varchar(16) not null COMMENT '调度的机器ip',
  	PRIMARY KEY (`id`),
	key idx_def_id(smc_def_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

  • 更新消息表

用于任务新增,更新和删除时,对对应的定时任务做cancel处理,uk_id_ct 唯一索引用于获取某机器的消费进度

create table ts_task_msg (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
    `smc_def_id` bigint  not null COMMENT '任务定义ID',
	`smc_action` int not null COMMENT '操作类型,0:新增,1:修改,2:删除',
  	PRIMARY KEY (`id`),
	unique uk_id_ct(`id`,`gmt_create`),
	key idx_gc(`gmt_create`),
	key idx_def_id(smc_def_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

  • 消费进度

当发生定时任务的更新与删除时,每个机器需要更新自身任务,比如取消,删除等操作

create table ts_consume_progress (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `gmt_create` datetime NOT NULL COMMENT '创建时间',
  	`gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
    `smc_ip` varchar(32) not null COMMENT '消费机器ip',
	`smc_msg_id` bigint(20) not null COMMENT '消费进度id',
  	PRIMARY KEY (`id`),
	unique uk_ip(smc_ip)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

六、快速开始

  • springboot worker端自动装配 jar 工程 git地址:https://gitee.com/yomea/task-scheduler-starter
  • 调度中心 git地址:https://gitee.com/yomea/timer-task-scheduler

代码中使用的rpc框架为本人自己写的rpc框架(https://gitee.com/yomea/hanggu-rpc),原理与外边开源的rpc框架是一样的

6.1 引入jar

<dependency>
	<groupId>com.xxx.task</groupId>
  <artifactId>task-scheduler-starter</artifactId>
  <version>1.0.0-SNAPSHOT</version>
</dependency>

6.2 application.yml

task:
  scheduler:
    enable: true # 开启定时任务调度
    app-service-name: ${app.name} # 应用服务名,调度中心通过该服务名获取应用所在机器地址,将该机器当作worker处理任务
    task-deal-core-thread-num: 20 # worker处理任务的核心线程数
    task-deal-max-thread-num: 20 # worker处理任务的最大线程数
    task-deal-max-queue-size: 10000 # 处理任务的最大队列长度

如果任务处理比较慢, 可适当增加 task-deal-max-queue-size 的大小,如果处理不过来,可适当
横向扩展机器

6.3 任务实现

@TaskScheduleService(apiServiceName="xxx")
public interface Ixxx {
	
	//返回值为void,如果调用完成不抛出错误,即任务任务执行成功
	@TaskScheduleMethod(name="task1")
	void task1(TaskContext taskContext);
	
	//返回值为int,使用枚举,返回0为成功
	int task2();
	
	//返回success为成功
	ApiResult task2(TaskContext taskContext);
	
	ApiResult task3(TaskContext taskContext);
}

如果参数中有 TaskContext 参数,那么会把此次调用的任务id传过来,用于业务方进行幂等性校验等操作
注意:注解需要标注在接口上才生效

6.4 任务新增或修改

  • rpc 接口: com.xxx.task.hangu.impl.TaskSchedulerFacade#submitTimerTask

代码演示:

@Resource
private TaskSchedulerFacade taskSchedulerFacade;

public void test() {
	TimerTaskRequest timerTaskRequest = TimerTaskRequest.builder().taskName("测试呀!")
			.timeout(10000L).appServiceName("das-model").apiServiceName("buildModelService")
			.apiMethodName("doBuild").taskDefStatus(TaskStatusEnum.ENABLE.getStatus())
			.addDelayTimerTask(DelayTimerTask.builder().delay(10000L).build())
			.addCronTimerTask(CronTimerTask.builder().cron("0/5 * * * * * ?").startDateTime(new Date()).endDateTime(DateUtils.addDays(new Date(), 10)).build())
									.build();
	ApiResult<Long> apiResult = taskSchedulerFacade.submitTimerTask(timerTaskRequest);
}
  • http 接口:http://localhost:9222/task-scheduler/task/submitTimerTask

http:

{
	"taskInfoConf":{
		"status":TaskStatusEnum.ENABLE.getStatus(),//任务是否启动,1:启动,-1:禁用
		"taskId":123,//如果是新增,这个字段不传,如果是修改请加上这个参数
		"taskName":"xxx",
		"timeout":1000,//超时时间,单位ms
		"appServiceName":"das-sources",//注册到注册中心的服务名
		"apiServiceName":"apiDataSourceGet",//接口服务名
		"apiMethodName":"exec",//接口方法名,为了简单期间,方法不要重载
		"subTaskList":[
			{
			"status":TaskStatusEnum.ENABLE.getStatus(),//任务是否启动,1:启动,-1:禁用
			"taskId":123,//如果是新增,这个字段不传,如果是修改请加上这个参数
			"taskName":"xxx",
			"timeout":1000,//超时时间,单位ms
			"appServiceName":"das-sources",//注册到注册中心的服务名
			"apiServiceName":"apiDataSourceGet",//接口服务名
			"apiMethodName":"exec",//接口方法名,为了简单期间,方法不要重载
			"subTaskList":[
				{
				"status":TaskStatusEnum.ENABLE.getStatus(),//任务是否启动,1:启动,-1:禁用
				"taskId":123,//如果是新增,这个字段不传,如果是修改请加上这个参数
				"taskName":"xxx",
				"timeout":1000,//超时时间,单位ms
				"appServiceName":"das-sources",//注册到注册中心的服务名
				"apiServiceName":"apiDataSourceGet",//接口服务名
				"apiMethodName":"exec"//接口方法名,为了简单期间,方法不要重载
				}
			}
	]
		},
	"taskScheduleConf":{
		"timerList":[
			{
			"timerType":1,
			"cron":"12 12 12 0/2 * *",
			"startDateTime":"2021-08-09",
			"endDateTime":"2021-10-01"
			},
			{
			"timerType":4,
			"delay":10000,//ms
			"startDateTime":"2021-08-09",
			"endDateTime":"2021-10-01"
			}
		]
	}
	
}

响应


{
 "code":200,
 "msg":"",
 "data":{
 	"taskId":112
 }
}

返回一个任务id,这样任务提交方按照自己业务是否需要保存这个任务id,如果有对任务进行操作的需求,那么建议保存

6.5 任务删除

  • rpc:com.xxx.task.hangu.impl.TaskSchedulerFacade#timerTaskDel
  • http:http://localhost:9222/task-scheduler/task/timerTaskDel
{
	"taskId":122
}

6.6 任务禁用

  • rpc:com.xxx.task.hangu.impl.TaskSchedulerFacade#disableTask
  • http:http://localhost:9222/task-scheduler/task/disableTask

参数 taskId

6.7 任务启用

  • rpc:com.xxx.task.hangu.impl.TaskSchedulerFacade#enableTask
  • http:http://localhost:9222/task-scheduler/task/enableTask

参数 taskId

6.8 立即执行某任务

  • rpc:com.xxx.task.hangu.impl.TaskSchedulerFacade#execTaskImmediately
  • http:http://localhost:9222/task-scheduler/task/execTaskImmediately

参数 taskId

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于数据库版本的分布式定时任务调度中心 的相关文章

  • socket.io redis 和内存泄漏

    我的socket io版本是 电子邮件受保护 cdn cgi l email protection and 电子邮件受保护 cdn cgi l email protection 我在 Windows 上 在某些地方 我看到问题已得到解决 我
  • Spring RedisTemplate:8次调用后方法键挂起

    我使用 Spring RedisTemplate spring data redis 1 7 1 与 Redis 进行通信 我需要通过正则表达式获取然后删除键 例如 context user1 我用的方法 RedisTemplate key
  • Node.js 上通过套接字连接 Redis

    由于共享托管 目标主机上的我的 redis 服务器不在端口上运行 而是在非常特定的套接字上运行 可以通过套接字文件连接到该套接字 只有我的用户可以访问 但是 我还没有找到如何通过套接字指定连接node redis and connect r
  • 使用 AWS ElastiCache 请求中的 Airflow CROSSSLOT 密钥未散列到同一插槽错误

    我在 AWS ECS 上运行 apache airflow 1 8 1 并且有一个 AWS ElastiCache 集群 redis 3 2 4 运行 2 个分片 2 个启用多可用区的节点 集群 Redis 引擎 我已经验证气流可以毫无问题
  • PooledRedisClientManager 未释放连接

    我将 json 数据列表存储在 redis 中并使用 ServiceStack c 客户端访问它 我本质上是在管理自己的外键 我在其中存储zrangeid 我使用应用程序内部的接口从zrange然后从 Redis 获取底层 json 对象并
  • 为什么Redis中不建议使用KEYS?

    在Redis中 建议不要使用按键命令 https redis io commands KEYS 为什么会这样呢 是因为它的时间复杂度是 O N 吗 或者是别的什么原因 我做了下面的实验来证明KEYS命令有多么危险 当带有 KEYS 的一个命
  • 是否有可嵌入的 Java 替代 Redis?

    根据这个线程 https stackoverflow com questions 3047010 best redis library for java 如果我想从Java中使用Redis Jedis是最好的选择 然而 我想知道是否有任何库
  • Redis hash写入速度非常慢

    我面临一个非常奇怪的问题 使用 Redis 时 我的写入速度非常糟糕 在理想的情况下 写入速度应该接近 RAM 上的写入速度 这是我的基准 package redisbenchmark import redis clients jedis
  • Caffeine Expiry 中如何设置多个过期标准?

    我正在使用 Caffeine v2 8 5 我想创建一个具有可变到期时间的缓存 基于 值的创建 更新以及 该值的最后一次访问 读取 无论先发生什么都应该触发该条目的删除 缓存将成为三层值解析的一部分 The key is present i
  • redis 阻塞直到 key 存在

    我是 Redis 新手 想知道是否有办法能够await get通过它的键来获取值 直到该键存在 最小代码 async def handler data await self fetch key async def fetch key ret
  • 在 Kubernetes/Openshift 中将客户端-服务器流量保持在同一区域的最佳方法?

    我们运行兼容 Kubernetes OKD 3 11 的本地 私有云集群 其中后端应用程序与用作缓存和 K V 存储的低延迟 Redis 数据库进行通信 新的架构设计将在两个地理上分布的数据中心 区域 之间平均划分工作节点 我们可以假设节点
  • 如何将node.js管道传输到redis?

    我有很多数据要插入 SET INCR 到redis DB 所以我正在寻找pipeline http redis io topics pipelining 质量插入 http redis io topics mass insert通过node
  • Redis Docker compose无法处理RDB格式版本10

    我无法在 docker compose 文件中启动 redis 容器 我知道docker compose文件没问题 因为我的同事可以成功启动项目 我读到有一个删除 dump rdb 文件的解决方案 但我找不到它 我使用Windows机器 任
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • StackExchange.Redis的正确使用方法

    这个想法是使用更少的连接和更好的性能 连接会随时过期吗 对于另一个问题 redis GetDatabase 打开新连接 private static ConnectionMultiplexer redis private static ID
  • 如何使 Redis 缓存中数据层次结构(树)的部分内容无效

    我有一些产品数据 需要在 Redis 缓存中存储多个版本 数据由 JSON 序列化对象组成 获取普通 基本 数据的过程很昂贵 将其定制为不同版本的过程也很昂贵 因此我想缓存所有版本以尽可能进行优化 数据结构看起来像这样 BaseProduc
  • 为什么Redis中没有有序的hashmap?

    Redis 数据类型 http redis io topics data types包括排序集 http redis io topics data types intro sorted sets以及其他用于键值存储的必要数据结构 但我想知道
  • 想要在后台不间断地运行redis-server

    我已经下载了 redis 2 6 16 tar gz 文件并安装成功 安装后我运行 src redis server 它工作正常 但我不想每次都手动运行 src redis server 而是希望 redis server 作为后台进程持续
  • Scala 使用的 Redis 客户端库建议

    我正在计划使用 Scala 中的 Redis 实例进行一些工作 并正在寻找有关使用哪些客户端库的建议 理想情况下 如果存在一个好的库 我希望有一个为 Scala 而不是 Java 设计的库 但如果现在这是更好的方法 那么仅使用 Java 客
  • Laravel 异常队列最大尝试次数超出

    我创建了一个应用程序来向多个用户发送电子邮件 但在处理大量收件人时遇到问题 该错误出现在failed jobs table Illuminate Queue MaxAttemptsExceededException App Jobs ESe

随机推荐

  • 华为OD机试 - 绘图机器(Java)

    题目描述 绘图机器的绘图笔初始位置在原点 0 0 机器启动后按照以下规则来进行绘制直线 1 尝试沿着横线坐标正向绘制直线直到给定的终点E 2 期间可以通过指令在纵坐标轴方向进行偏移 offsetY为正数表示正向偏移 为负数表示负向偏移 给定
  • 第一章 指针仪表识别之仪表检测

    文章目录 一 基于Hough变换的仪表检测 附源码 二 基于SURF模板匹配仪表检测 附源码 三 基于YOLO深度学习的仪表检测 附源码 指针式仪表读数算法主要用于工业变电站环境 变电站环境复杂 仪表类型众多 仪表图像通过巡检机器人的可见光
  • jdk17.0.6的安装配置

    下载资源 官网下载 Java Archive Downloads Java SE 17 oracle com https www oracle com java technologies javase jdk17 archive downl
  • Cuda Streams的概述(一)-- Cuda介绍

    最近在做有关Cuda的一个项目 碰到匪夷所思的问题 在异步的时候发现并没有达到预期的效果 程序没有异步起来 然后在网上找了一个Nvida的有关Cuda Streams的一个ppt 然后照着里面的提示 使程序达到了异步的效果 首先 先回顾一下
  • linux VLAN配置(vconfig)

    1 安装vlan vconfig 和加载8021q模块 aptitude install vlan modprobe 8021q 或 yum install vconfig modprobe 8021q lsmod grep i 8021q
  • AndroidStudio编译构建报错 Task ‘wrapper‘ not found in project ‘:xxx‘

    在项目 app 中找不到的任务 包装器 Task wrapper not found in project xxx 的问题 原因 build gradle 文件没有包装器任务 解决步骤 将此代码添加到 build gradle task w
  • PO、VO、DAO、BO、DTO、POJO 能分清吗?

    一 PO persistant object 持久对象 可以看成是与数据库中的表相映射的java对象 使用Hibernate来生成PO是不错的选择 二 VO value object 值对象 通常用于业务层之间的数据传递 和PO一样也是仅仅
  • vue中的h函数与JSX语法

    vue不仅像react一样实现了jsx 而且还借助jsx发挥了javascript动态画的优势 了解学习jsx可以让你更灵活的开发需求 一 h函数 在聊vue中的JSX之前 需要简单介绍一下 h 函数 理解了 h 函数 会更好的理解JSX
  • 华为OD机试 - 士兵过河(Java)

    题目描述 一支N个士兵的军队正在趁夜色逃亡 途中遇到一条湍急的大河 敌军在T的时长后到达河面 没到过对岸的士兵都会被消灭 现在军队只找到了1只小船 这船最多能同时坐上2个士兵 当1个士兵划船过河 用时为 a i 0 lt i lt N 当2
  • mybatis更新和插入语句报错的原因和解决方法

    做一个小项目时 想实现添加和修改用户的功能 发现以下语句程序报错 INSERT INTO hrm user NAME PASS WORD STATUS DESC role createDATE createUSER VALUES 1 2 3
  • WorldEdit 指令大全 & 开发记录

    文章目录 服务端 客户端 运行配置 通用指令 好用刷子 圆球刷 Brush Sphere br sp 地板刷子 Brush Cyl br cyl 树木刷子 tree 服务端 客户端 运行配置 服务端 Spigot 1 14 4 插件版本 W
  • word页面上方有横线选不中删不掉

    依次点击 设计 页面边框 选择无
  • 批处理文件命名(简单有效且粗暴!)

    批处理文件命名 简单有效且粗暴 方法 方法一 方法二 方法 网上的方法层出不穷 但是真正有效的几乎没有 本文罗列外加自己领悟 给出了两个真实且有效的方法 方法一 直接下载粗暴且有效的工具 Totao commander 这是官网的简介 To
  • Apache -poi

    Busy Developers Guide to Features Want to use HSSF and XSSF read and write spreadsheets in a hurry This guide is for you
  • 添加了@LoadBalanced注解,即可实现负载均衡功能,这是什么原理呢?

    SpringCloud01 认识微服务 任何架构都离不开服务的拆分 微服务的拆分和远程调用你会吗 Eureka学习 搭建eureka server 将user service注册到eureka server中 Ribbon负载均衡 上一节中
  • json/xml/schema

    JSON JSON是JavaScript Object Notation的缩写 是一种轻量级的数据交换格式 是理想的接口数据交换语言 官网 https www json org json en html 工作json请求体 json字符串
  • docker cp拷贝文件_Docker - A焕然一新

    Docker的基本组成 镜像 容器 仓库 镜像 image 就像是一个模板 可以通过这个模板来创建容器服务 通过镜像可以创建多个容器 最终服务运行或者项目运行就在容器中 容器 container Docker利用容器技术 独立运行一个或者一
  • [附源码]java毕业设计网上博物馆设计

    项目运行 环境配置 Jdk1 8 Tomcat7 0 Mysql HBuilderX Webstorm也行 Eclispe IntelliJ IDEA Eclispe MyEclispe Sts都支持 项目技术 SSM mybatis Ma
  • 基于wsl2在windows下使用docker应用

    wsl2重启 管理员权限打开powershell 然后执行下面命令 powershell切换为管理员权限 Start Process powershell Verb runAs 关闭服务 net stop LxssManager 重启服务
  • 基于数据库版本的分布式定时任务调度中心

    github调度中心源码地址 https github com yomea timer task scheduler github业务端源码地址 https github com yomea task scheduler starter g