本期将提供quartz集群能力

  • 集群案例分析: 
    上一期的邮件发送功能,若在服务需要部署多节点,但定时任务不支持集群,因此,多节点定时任务势必会同时运行, 
    若向用户发送邮件通知,这种情况下会向用户发送两次一模一样的邮件,N个节点会发送N次邮件,严重不符合业务场景, 
    若提供集群能力,则多节点间应分担邮件发送的工作而不是各节点做重复的工作,因此在部署多节点的时候定时任务也需要提供集群能力。
  • 个人见解: 
    1. quartz集群分为水平集群和垂直集群,水平集群即将定时任务节点部署在不同的服务器,水平集群最大的问题就是时钟同步问题, 
      quartz集群强烈要求时钟同步,若时钟不能同步,则会导致集群中各个节点状态紊乱,造成不可预知的后果,请自行搜索服务器时钟同步
      若能保证时钟同步,水平集群能保证服务的可靠性,其中一个节点挂掉或其中一个服务器宕机,其他节点依然正常服务;垂直集群则是集群各节点部署在同一台服务器, 
      时钟同步自然不是问题,但存在单点故障问题,服务器宕机会严重影响服务的可用性。因此,要结合实际情况来考虑集群方案
    2. 由于集群中强烈要求时钟同步,因此不管是垂直集群还是水平集群,本地开发决不能连接线上环境(本地也是集群模式),这样的话势必会破坏集群,但本地若是非集群模式, 
      则可以依情况来连接线上环境。
    3. quartz集群和redis这样的集群实现方式不一样,redis集群需要节点之间通信,各节点需要知道其他节点的状况,而quartz集群的实现 
      方式在于11张表,集群节点相互之间不通信,而是通过定时任务持久化加锁的方式来实现集群。
    4. 破坏集群后果一般是死锁或者状态紊乱每个节点都不可用或其中某些节点能用部分或全部的定时任务

1. 创建集群需要的11张表

t_b_qrtz_blob_triggers
t_b_qrtz_calendars
t_b_qrtz_cron_triggers
t_b_qrtz_fired_triggers
t_b_qrtz_job_details
t_b_qrtz_locks
t_b_qrtz_paused_trigger_grps
t_b_qrtz_scheduler_state
t_b_qrtz_simple_triggers
t_b_qrtz_simprop_triggers
t_b_qrtz_triggers
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. 集群建表sql

drop table if exists t_b_qrtz_fired_triggers;
drop table if exists t_b_qrtz_paused_trigger_grps;
drop table if exists t_b_qrtz_scheduler_state;
drop table if exists t_b_qrtz_locks;
drop table if exists t_b_qrtz_simple_triggers;
drop table if exists t_b_qrtz_simprop_triggers;
drop table if exists t_b_qrtz_cron_triggers;
drop table if exists t_b_qrtz_blob_triggers;
drop table if exists t_b_qrtz_triggers;
drop table if exists t_b_qrtz_job_details;
drop table if exists t_b_qrtz_calendars; create table t_b_qrtz_job_details(
sched_name varchar(120) not null,
job_name varchar(200) not null,
job_group varchar(200) not null,
description varchar(250) null,
job_class_name varchar(250) not null,
is_durable varchar(1) not null,
is_nonconcurrent varchar(1) not null,
is_update_data varchar(1) not null,
requests_recovery varchar(1) not null,
job_data blob null,
primary key (sched_name,job_name,job_group))
engine=innodb; create table t_b_qrtz_triggers (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
job_name varchar(200) not null,
job_group varchar(200) not null,
description varchar(250) null,
next_fire_time bigint(13) null,
prev_fire_time bigint(13) null,
priority integer null,
trigger_state varchar(16) not null,
trigger_type varchar(8) not null,
start_time bigint(13) not null,
end_time bigint(13) null,
calendar_name varchar(200) null,
misfire_instr smallint(2) null,
job_data blob null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,job_name,job_group)
references t_b_qrtz_job_details(sched_name,job_name,job_group))
engine=innodb; create table t_b_qrtz_simple_triggers (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
repeat_count bigint(7) not null,
repeat_interval bigint(12) not null,
times_triggered bigint(10) not null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group)
references t_b_qrtz_triggers(sched_name,trigger_name,trigger_group))
engine=innodb; create table t_b_qrtz_cron_triggers (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
cron_expression varchar(120) not null,
time_zone_id varchar(80),
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group)
references t_b_qrtz_triggers(sched_name,trigger_name,trigger_group))
engine=innodb; create table t_b_qrtz_simprop_triggers
(
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
str_prop_1 varchar(512) null,
str_prop_2 varchar(512) null,
str_prop_3 varchar(512) null,
int_prop_1 int null,
int_prop_2 int null,
long_prop_1 bigint null,
long_prop_2 bigint null,
dec_prop_1 numeric(13,4) null,
dec_prop_2 numeric(13,4) null,
bool_prop_1 varchar(1) null,
bool_prop_2 varchar(1) null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group)
references t_b_qrtz_triggers(sched_name,trigger_name,trigger_group))
engine=innodb; create table t_b_qrtz_blob_triggers (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
blob_data blob null,
primary key (sched_name,trigger_name,trigger_group),
index (sched_name,trigger_name, trigger_group),
foreign key (sched_name,trigger_name,trigger_group)
references t_b_qrtz_triggers(sched_name,trigger_name,trigger_group))
engine=innodb; create table t_b_qrtz_calendars (
sched_name varchar(120) not null,
calendar_name varchar(200) not null,
calendar blob not null,
primary key (sched_name,calendar_name))
engine=innodb; create table t_b_qrtz_paused_trigger_grps (
sched_name varchar(120) not null,
trigger_group varchar(200) not null,
primary key (sched_name,trigger_group))
engine=innodb; create table t_b_qrtz_fired_triggers (
sched_name varchar(120) not null,
entry_id varchar(95) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
instance_name varchar(200) not null,
fired_time bigint(13) not null,
sched_time bigint(13) not null,
priority integer not null,
state varchar(16) not null,
job_name varchar(200) null,
job_group varchar(200) null,
is_nonconcurrent varchar(1) null,
requests_recovery varchar(1) null,
primary key (sched_name,entry_id))
engine=innodb; create table t_b_qrtz_scheduler_state (
sched_name varchar(120) not null,
instance_name varchar(200) not null,
last_checkin_time bigint(13) not null,
checkin_interval bigint(13) not null,
primary key (sched_name,instance_name))
engine=innodb; create table t_b_qrtz_locks (
sched_name varchar(120) not null,
lock_name varchar(40) not null,
primary key (sched_name,lock_name))
engine=innodb; create index idx_qrtz_j_req_recovery on t_b_qrtz_job_details(sched_name,requests_recovery);
create index idx_qrtz_j_grp on t_b_qrtz_job_details(sched_name,job_group); create index idx_qrtz_t_j on t_b_qrtz_triggers(sched_name,job_name,job_group);
create index idx_qrtz_t_jg on t_b_qrtz_triggers(sched_name,job_group);
create index idx_qrtz_t_c on t_b_qrtz_triggers(sched_name,calendar_name);
create index idx_qrtz_t_g on t_b_qrtz_triggers(sched_name,trigger_group);
create index idx_qrtz_t_state on t_b_qrtz_triggers(sched_name,trigger_state);
create index idx_qrtz_t_n_state on t_b_qrtz_triggers(sched_name,trigger_name,trigger_group,trigger_state);
create index idx_qrtz_t_n_g_state on t_b_qrtz_triggers(sched_name,trigger_group,trigger_state);
create index idx_qrtz_t_next_fire_time on t_b_qrtz_triggers(sched_name,next_fire_time);
create index idx_qrtz_t_nft_st on t_b_qrtz_triggers(sched_name,trigger_state,next_fire_time);
create index idx_qrtz_t_nft_misfire on t_b_qrtz_triggers(sched_name,misfire_instr,next_fire_time);
create index idx_qrtz_t_nft_st_misfire on t_b_qrtz_triggers(sched_name,misfire_instr,next_fire_time,trigger_state);
create index idx_qrtz_t_nft_st_misfire_grp on t_b_qrtz_triggers(sched_name,misfire_instr,next_fire_time,trigger_group,trigger_state); create index idx_qrtz_ft_trig_inst_name on t_b_qrtz_fired_triggers(sched_name,instance_name);
create index idx_qrtz_ft_inst_job_req_rcvry on t_b_qrtz_fired_triggers(sched_name,instance_name,requests_recovery);
create index idx_qrtz_ft_j_g on t_b_qrtz_fired_triggers(sched_name,job_name,job_group);
create index idx_qrtz_ft_jg on t_b_qrtz_fired_triggers(sched_name,job_group);
create index idx_qrtz_ft_t_g on t_b_qrtz_fired_triggers(sched_name,trigger_name,trigger_group);
create index idx_qrtz_ft_tg on t_b_qrtz_fired_triggers(sched_name,trigger_group); commit;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171

3. 工程中application.properties添加集群配置

quartz.scheduler.instanceName=CnlmScheduler
org.quartz.dataSource.myDS.driver=com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL=jdbc:mysql://120.77.172.111:3306/touch6?useUnicode=true&characterEncoding=utf8
org.quartz.dataSource.myDS.user=cnlm.me
org.quartz.dataSource.myDS.password=123456
org.quartz.dataSource.myDS.maxConnections=10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 调度工厂配置集群参数支持集群能力,下面是支持集群能力的调度工厂类

package me.cnlm.springboot.quartz.config;

import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean; import java.io.IOException;
import java.util.Properties; @Configuration
public class SchedulerFactoryBeanConfig { @Value("${quartz.scheduler.instanceName}")
private String quartzInstanceName; @Value("${org.quartz.dataSource.myDS.driver}")
private String myDSDriver; @Value("${org.quartz.dataSource.myDS.URL}")
private String myDSURL; @Value("${org.quartz.dataSource.myDS.user}")
private String myDSUser; @Value("${org.quartz.dataSource.myDS.password}")
private String myDSPassword; @Value("${org.quartz.dataSource.myDS.maxConnections}")
private String myDSMaxConnections; /**
* 定时任务集群配置
* 设置属性
*
* @return
* @throws IOException
*/
private Properties quartzProperties() throws IOException {
Properties prop = new Properties();
prop.put("quartz.scheduler.instanceName", quartzInstanceName);
prop.put("org.quartz.scheduler.instanceId", "AUTO");
prop.put("org.quartz.scheduler.skipUpdateCheck", "true");
prop.put("org.quartz.scheduler.jmx.export", "true"); prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
prop.put("org.quartz.jobStore.dataSource", "quartzDataSource");
prop.put("org.quartz.jobStore.tablePrefix", "T_B_QRTZ_");
prop.put("org.quartz.jobStore.isClustered", "true"); prop.put("org.quartz.jobStore.clusterCheckinInterval", "20000");
prop.put("org.quartz.jobStore.dataSource", "myDS");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.misfireThreshold", "120000");
prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE"); prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "10");
prop.put("org.quartz.threadPool.threadPriority", "5");
prop.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true"); prop.put("org.quartz.dataSource.myDS.driver", myDSDriver);
prop.put("org.quartz.dataSource.myDS.URL", myDSURL);
prop.put("org.quartz.dataSource.myDS.user", myDSUser);
prop.put("org.quartz.dataSource.myDS.password", myDSPassword);
prop.put("org.quartz.dataSource.myDS.maxConnections", myDSMaxConnections); prop.put("org.quartz.plugin.triggHistory.class", "org.quartz.plugins.history.LoggingJobHistoryPlugin");
prop.put("org.quartz.plugin.shutdownhook.class", "org.quartz.plugins.management.ShutdownHookPlugin");
prop.put("org.quartz.plugin.shutdownhook.cleanShutdown", "true");
return prop;
} @Bean
public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("sendEmailTrigger") Trigger sendEmailTrigger) throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
//用于quartz集群,加载quartz数据源
//factory.setDataSource(dataSource);
factory.setStartupDelay(10);
// factory.setQuartzProperties(quartzProperties());
factory.setAutoStartup(true);
factory.setApplicationContextSchedulerContextKey("applicationContext");
//注册触发器
factory.setTriggers(
sendEmailTrigger
);
return factory;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

5. 测试验证

略(分别运行两个项目节点,可以发现上述11张表中添加了2个节点的信息和定时任务运行状态,此处可自行验证)

本期已结束,至此项目支持定时任务分布式集群模式

欢迎加入技术交流QQ群566654343
版权声明:2018 Powered by zhuxl (QQ2810010108) https://blog.csdn.net/musuny/article/details/75808044

Springboot quartz集群(3) — 多节点发送邮件的更多相关文章

  1. springboot+mysql实现quartz集群搭建

    一.基本概念 Quartz核心的概念:scheduler任务调度.Job任务.Trigger触发器.JobDetail任务细节. scheduler任务调度: 是最核心的概念,需要把JobDetail ...

  2. Quartz集群

    为什么选择Quartz: 1)资历够老,创立于1998年,比struts1还早,但是一直在更新(27 April 2012: Quartz 2.1.5 Released),文档齐全. 2)完全由Jav ...

  3. 项目中使用Quartz集群分享--转载

    项目中使用Quartz集群分享--转载 在公司分享了Quartz,发布出来,希望大家讨论补充. CRM使用Quartz集群分享  一:CRM对定时任务的依赖与问题  二:什么是quartz,如何使用, ...

  4. Quartz集群配置

    先看看quartz的持久化基本介绍: 引用 1 大家都清楚quartz最基本的概念就是job,在job内调用具体service完成具体功能,quartz需要把每个job存储起来,方便调度,quartz ...

  5. Quartz集群原理及配置应用

    1.Quartz任务调度的基本实现原理 Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于Java实现.作为一个优秀的开源调度框架,Quartz具有以下特点: (1) ...

  6. quartz集群调度机制调研及源码分析---转载

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  7. (4) Spring中定时任务Quartz集群配置学习

    原 来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运 行,没有任何错误日志,于是从jar包.JDK版本. ...

  8. (1)quartz集群调度机制调研及源码分析---转载

    quartz2.2.1集群调度机制调研及源码分析 原文地址:http://demo.netfoucs.com/gklifg/article/details/27090179 引言quartz集群架构调 ...

  9. 使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】

    一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz强大的序列化机制,可以序列到 sqlserver,mysql,当然还可以在 ...

随机推荐

  1. 7.2-5 usermod

    7.2 usermod:修改用户信息 usermod 命令用于修改系统已经存在的用户的账号信息.   -c comment         修改用户password文件中用户的说明栏,同useradd ...

  2. 若依框架前端使用antd,IE11浏览器无法正常显示问题

    话不多说,直接上才艺,找到vue.config.js,把第11行的 mock 删除掉就 IE11就正常显示了, 然而项目还是不支持IE10 以及以下版本,哪位小伙伴有解决方法,可以留言交流下

  3. 在 Visual Studio 里一秒打开 ILSpy,并反编译当前项目

    下载 ILSpy(如果已有 ILSpy,忽略此步骤) 1.打开官方git 仓库 - https://github.com/icsharpcode/ILSpy 2.点击右侧的 Releases 最新版, ...

  4. CAP 5.1 版本发布通告 - 你期待的 Redis 来了

    前言 今天,我们很高兴宣布 CAP 发布 5.1 版本正式版,在这个版本里我们同样引入了更多令人激动的新特性和改进,同时也得到越来越多人的喜爱. 得益于社区的反馈和贡献者的支持,在过去的两个月里,我们 ...

  5. Symbol类型的应用

    应用场景1:使用Symbol来作为对象属性名(key) 在这之前,我们通常定义或访问对象的属性时都是使用字符串,比如下面的代码: let obj = { abc: 123, "hello&q ...

  6. Google Pixel 超分辨率--Super Resolution Zoom

    Google Pixel 超分辨率--Super Resolution Zoom Google 的Super Res Zoom技术,主要用于在zoom时增强画面细节以及提升在夜景下的效果. 文章的主要 ...

  7. MPC算法

    MPC算法 一.    引言 在工程技术方面,MPC全称可指Model Predictive Control模型预测控制(又称RHC, Receding Horizon  ). 模型预测控制算法 一种 ...

  8. NVIDIA深度学习Tensor Core性能解析(下)

    NVIDIA深度学习Tensor Core性能解析(下) DeepBench推理测试之RNN和Sparse GEMM DeepBench的最后一项推理测试是RNN和Sparse GEMM,虽然测试中可 ...

  9. NVIDIA TensorRT高性能深度学习推理

    NVIDIA TensorRT高性能深度学习推理 NVIDIA TensorRT 是用于高性能深度学习推理的 SDK.此 SDK 包含深度学习推理优化器和运行时环境,可为深度学习推理应用提供低延迟和高 ...

  10. 最短路径问题,BFS,408方向,思路与实现分析

    最短路径问题,BFS,408方向,思路与实现分析 继上回挖下的坑,不知道大家有没有认真看最小生成树呢?很简单,这回也讲讲正常难度的,看不懂就来这里看看,讲的很好~~ 最短路径问题 说起这个问题,先说个 ...