Spring+Quartz集群环境下定时调度的解决方案
集群环境可能出现的问题
在上一篇博客我们介绍了如何在自己的项目中从无到有的添加了Quartz定时调度引擎,其实就是一个Quartz 和Spring的整合过程,很容易实现,但是我们现在企业中项目通常都是部署在集群环境中的,这样我们之前的定时调度就会出现问题了,因为我们的定时任务都加载在内存中的,每个集群节点中的调度器都会去执行,这就会存在重复执行和资源竞争的问题,那么如何来解决这样的问题呢,往下面看吧...
解决方案
在一般的企业中解决类似的问题一般都是在一个note上部署Quartz其他note不部署(或者是在其他几个机器加IP地址过滤),但是这样集群对于定时任务来说就没有什么意义了,而且存在着单点故障的隐患,也就是这台部署着Quartz的机器一旦挂了,我们的定时任务就停止服务了,这绝对不是我们想要的。
Quartz本身是支持集群的,我们通过Quartz的集群方式来解决这样的问题。
Quartz集群
虽然单个 Quartz 实例能给予你很好的 Job调度能力,但它不能令典型的企业需求,如可伸缩性、高可靠性满足。假如你需要故障转移的能力并能运行日益增多的 Job,Quartz 集群势必成为你方言的一部分了,并且即使是其中一台机器在最糟的时间崩溃了也能确保所有的 Job 得到执行。 QuartzJob Scheduling Framework
了解了Quartz集群的好处,接下来就对我们之前的工程进行改造,增加Quartz集群特性。
Quartz集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群
所以我们集群的第一步就是建立Quartz所需要的12张表:
1、建表
在quartz核心包里面通过quartz提供的建表语句建立相关表结构
生成的表结构如下
这几张表是用于存储任务信息,触发器,调度器,集群节点等信息
详细解释:
QRTZ_CRON_TRIGGERS 存储Cron Trigger,包括Cron 表达式和时区信息
QRTZ_PAUSED_TRIGGER_GRPS 存储已暂停的Trigger 组的信息
QRTZ_LOCKS 存储程序的非观锁的信息(假如使用了悲观锁)
QRTZ_JOB_LISTENERS 存储有关已配置的JobListener 的信息
QRTZ_BLOG_TRIGGERS Trigger 作为Blob 类型存储(用于Quartz 用户用JDBC 创建他们自己定制的Trigger 类型,JobStore并不知道如何存储实例的时候)
QRTZ_TRIGGERS 存储已配置的Trigger 的信息
所有的表默认以前缀QRTZ_开始。可以通过在quartz.properties配置修改(org.quartz.jobStore.tablePrefix= QRTZ_)。
共12张表的SQL脚本
# # Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar # # In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# DROP TABLE IF EXISTS QRTZ_JOB_LISTENERS; DROP TABLE IF EXISTS QRTZ_TRIGGER_LISTENERS; DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; DROP TABLE IF EXISTS QRTZ_LOCKS; DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; DROP TABLE IF EXISTS QRTZ_TRIGGERS; DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; DROP TABLE IF EXISTS QRTZ_CALENDARS; CREATE TABLE QRTZ_JOB_DETAILS
(
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_VOLATILE VARCHAR(1) NOT NULL,
IS_STATEFUL VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (JOB_NAME,JOB_GROUP)
); CREATE TABLE QRTZ_JOB_LISTENERS
(
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
JOB_LISTENER VARCHAR(200) NOT NULL,
PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER),
FOREIGN KEY (JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
); CREATE TABLE QRTZ_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
IS_VOLATILE VARCHAR(1) 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 (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
); CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
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 (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
); CREATE TABLE QRTZ_CRON_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
); CREATE TABLE QRTZ_BLOB_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
); CREATE TABLE QRTZ_TRIGGER_LISTENERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
TRIGGER_LISTENER VARCHAR(200) NOT NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
); CREATE TABLE QRTZ_CALENDARS
(
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (CALENDAR_NAME)
); CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (TRIGGER_GROUP)
); CREATE TABLE QRTZ_FIRED_TRIGGERS
(
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
IS_VOLATILE VARCHAR(1) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_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_STATEFUL VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (ENTRY_ID)
); CREATE TABLE QRTZ_SCHEDULER_STATE
(
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (INSTANCE_NAME)
); CREATE TABLE QRTZ_LOCKS
(
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (LOCK_NAME)
); INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS'); INSERT INTO QRTZ_LOCKS values('JOB_ACCESS'); INSERT INTO QRTZ_LOCKS values('CALENDAR_ACCESS'); INSERT INTO QRTZ_LOCKS values('STATE_ACCESS'); INSERT INTO QRTZ_LOCKS values('MISFIRE_ACCESS'); commit;
---------------------
作者:默默同学
来源:CSDN
原文:https://blog.csdn.net/u012909738/article/details/74454810
2、编写quartz.properties文件
建立 quartz.properties文件把它放在工程的 src 目录下,内容如下:
1 #============================================================================
2
3 # Configure Main Scheduler Properties
4
5 #============================================================================
6
7
8
9 org.quartz.scheduler.instanceName = Mscheduler
10
11 org.quartz.scheduler.instanceId = AUTO
12
13 org.quartz.jobStore.clusterCheckinInterval=20000
14
15
16
17 #============================================================================
18
19 # Configure ThreadPool
20
21 #============================================================================
22
23
24
25 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
26
27 org.quartz.threadPool.threadCount = 3
28
29 org.quartz.threadPool.threadPriority = 5
30
31
32
33 #============================================================================
34
35 # Configure JobStore
36
37 #============================================================================
38
39
40
41 #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
42
43
44
45 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
46
47 #org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
48
49 org.quartz.jobStore.useProperties = true
50
51 #org.quartz.jobStore.dataSource = myDS
52
53 org.quartz.jobStore.tablePrefix = QRTZ_
54
55 org.quartz.jobStore.isClustered = true
56
57 org.quartz.jobStore.maxMisfiresToHandleAtATime=1
58
59 #============================================================================
60
61 # Configure Datasources
62
63 #============================================================================
64
65
66
67 #mysql
68
69 #org.quartz.dataSource.myDS.driver = com.ibm.db2.jcc.DB2Driver
70
71 #org.quartz.dataSource.myDS.URL = jdbc:db2://localhost:50000/db
72
73 #org.quartz.dataSource.myDS.user = db2
74
75 #org.quartz.dataSource.myDS.password = db2
76
77 #org.quartz.dataSource.myDS.maxConnections = 5
78
79
80
81 #oracle
82
83 #org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
84
85 #org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@localhost:1521:orcl
86
87 #org.quartz.dataSource.myDS.user = scott
88
89 #org.quartz.dataSource.myDS.password = shao
90
91 #org.quartz.dataSource.myDS.maxConnections = 5
92
93
94
95 #For Tomcat
96
97 org.quartz.jobStore.driverDelegateClass =org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
98
99 #For Weblogic & Websphere
100
101 #org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.WebLogicDelegate
102
103 org.quartz.jobStore.useProperties = false
104
105 org.quartz.jobStore.dataSource = myDS
106
107
108
109
110
111 #JNDI MODE
112
113 #For Tomcat
114
115 org.quartz.dataSource.myDS.jndiURL=java:comp/env/jdbc/oracle
116
117 #For Weblogic & Websphere
118
119 #org.quartz.dataSource.myDS.jndiURL=jdbc/oracle
120
121
122
123
124
125 #============================================================================
126
127 # Configure Plugins
128
129 #============================================================================
130
131
132
133 #org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
134
135
136
137 #org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
138
139 #org.quartz.plugin.jobInitializer.fileNames = jobs.xml
140
141 #org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
142
143 #org.quartz.plugin.jobInitializer.failOnFileNotFound = true
144
145 #org.quartz.plugin.jobInitializer.scanInterval = 10
146
147 #org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
红色加粗部分是集群需要的配置
核心配置解释如下:
org.quartz.jobStore.class 属性为JobStoreTX,
将任务持久化到数据中。因为集群中节点依赖于数据库来传播Scheduler实例的状态,你只能在使用JDBC JobStore 时应用Quartz 集群。
org.quartz.jobStore.isClustered 属性为true,通知Scheduler实例要它参与到一个集群当中。
org.quartz.jobStore.clusterCheckinInterval
属性定义了Scheduler实例检入到数据库中的频率(单位:毫秒)。
Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;
这能指出一个失败的Scheduler 实例,且当前Scheduler 会以此来接管任何执行失败并可恢复的Job。
通过检入操作,Scheduler也会更新自身的状态记录。clusterChedkinInterval越小,Scheduler节点检查失败的Scheduler 实例就越频繁。默认值是 20000 (即20 秒)
3、修改spring-time.xml文件
1 <?xmlversion="1.0"encoding="UTF-8"?>
2 <!DOCTYPEbeansPUBLIC"-//SPRING//DTD BEAN//EN"
3 "http://www.springframework.org/dtd/spring-beans.dtd">
4 <beans>
5
6 <!-- 调度器lazy-init='false'那么容器启动就会执行调度程序 -->
7 <beanid="startQuertz"lazy-init="false"autowire="no"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
8 <property name="dataSource" ref="dataSource"/>
9 <property name="configLocation" value="classpath:quartz.properties" />
10 <propertyname="triggers">
11 <list>
12 <refbean="doTime"/>
13 </list>
14 </property>
15 <!-- 允许在Quartz上下文中使用Spring实例工厂 -->
16 <propertyname="applicationContextSchedulerContextKey"value="applicationContext"/>
17 </bean>
18
19 <!-- 触发器 -->
20 <beanid="doTime"class="org.springframework.scheduling.quartz.CronTriggerBean">
21 <propertyname="jobDetail"ref="jobtask"></property>
22 <!-- cron表达式 -->
23 <propertyname="cronExpression"value="10,15,20,25,30,35,40,45,50,55 * * * * ?"></property>
24 </bean>
25
26 <!-- 任务 -->
27 <beanid="jobtask"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
28 <propertyname="targetObject"ref="synUsersJob"></property>
29 <propertyname="targetMethod"value="execute"></property>
30 </bean>
31
32 <!-- 要调用的工作类 -->
33 <beanid="synUsersJob"class="org.leopard.core.quartz.job.SynUsersJob"></bean>
34
35 </beans>
增加红色加粗部分代码,注入数据源和加载quartz.properties文件
OK Quartz集群的配置只有这几步,我们来启动项目。。。
我们启着启着….报错了!
17:00:59,718 ERROR ContextLoader:215 - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'startQuertz' defined in class path resource [config/spring/spring-time.xml]: Invocation of init method failed; nested exception is org.quartz.JobPersistenceException:Couldn't store job: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean [See nested exception: java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean] |
我们主要来看红色部分,主要原因就是这个MethodInvokingJobDetailFactoryBean 类中的 methodInvoking 方法,是不支持序列化的,因此在把 quartz 的 task 序列化进入数据库时就会抛这个serializable的错误
4、解决serializable错误解决方案
网上查了一下,解决这个问题,目前主要有两种方案:
4.1.修改Spring的源码
博客地址:http://jira.springframework.org/browse/SPR-3797
作者重写了MethodInvokingJobDetailFactoryBean
4.2.通过AOP反射对Spring源码进行切面重构
博客地址:http://blog.csdn.net/lifetragedy/article/details/6212831
根据 QuartzJobBean 来重写一个自己的类,然后使用 SPRING 把这个重写的类(我们就名命它为: MyDetailQuartzJobBean )注入 appContext 中后,再使用 AOP 技术反射出原有的 quartzJobx( 就是开发人员原来已经做好的用于执行 QUARTZ 的 JOB 的执行类 ) 。
两种方式我都进行了测试,都可以解决问题,我们这里先通过第二种方式解决这个bug,没有修改任何Spring的源码
4.2.1、增加MyDetailQuartzJobBean.Java
1 package org.leopard.core.quartz;
2
3 import java.lang.reflect.Method;
4
5 import org.apache.commons.logging.Log;
6 import org.apache.commons.logging.LogFactory;
7 import org.quartz.JobExecutionContext;
8 import org.quartz.JobExecutionException;
9 import org.springframework.context.ApplicationContext;
10 import org.springframework.scheduling.quartz.QuartzJobBean;
11
12 /**
13 * 解决Spring和Quartz整合bug
14 *
15 */
16 public class MyDetailQuartzJobBean extends QuartzJobBean {
17 protected final Log logger = LogFactory.getLog(getClass());
18
19 private String targetObject;
20 private String targetMethod;
21 private ApplicationContext ctx;
22
23 protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
24 try {
25
26 logger.info("execute [" + targetObject + "] at once>>>>>>");
27 Object otargetObject = ctx.getBean(targetObject);
28 Method m = null;
29 try {
30 m = otargetObject.getClass().getMethod(targetMethod, new Class[] {});
31
32 m.invoke(otargetObject, new Object[] {});
33 } catch (SecurityException e) {
34 logger.error(e);
35 } catch (NoSuchMethodException e) {
36 logger.error(e);
37 }
38
39 } catch (Exception e) {
40 throw new JobExecutionException(e);
41 }
42
43 }
44
45 public void setApplicationContext(ApplicationContext applicationContext) {
46 this.ctx = applicationContext;
47 }
48
49 public void setTargetObject(String targetObject) {
50 this.targetObject = targetObject;
51 }
52
53 public void setTargetMethod(String targetMethod) {
54 this.targetMethod = targetMethod;
55 }
56
57 }
5、再次修改spring-time.xml文件解决serializable问题
修改后的spring-time.xml文件内容如下:
1 <?xmlversion="1.0"encoding="UTF-8"?>
2 <!DOCTYPEbeansPUBLIC"-//SPRING//DTD BEAN//EN"
3 "http://www.springframework.org/dtd/spring-beans.dtd">
4 <beans>
5
6 <!-- 调度器lazy-init='false'那么容器启动就会执行调度程序 -->
7 <beanid="startQuertz"lazy-init="false"autowire="no"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
8 <propertyname="dataSource"ref="dataSource"/>
9 <propertyname="configLocation"value="classpath:quartz.properties"/>
10 <propertyname="triggers">
11 <list>
12 <refbean="doTime"/>
13 </list>
14 </property>
15 <!--这个是必须的,QuartzScheduler延时启动,应用启动完后 QuartzScheduler再启动-->
16 <propertyname="startupDelay"value="30"/>
17 <!--这个是可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了-->
18 <propertyname="overwriteExistingJobs"value="true"/>
19 <!-- 允许在Quartz上下文中使用Spring实例工厂 -->
20 <propertyname="applicationContextSchedulerContextKey"value="applicationContext"/>
21 </bean>
22
23 <!-- 触发器 -->
24 <beanid="doTime"class="org.springframework.scheduling.quartz.CronTriggerBean">
25 <propertyname="jobDetail"ref="jobtask"></property>
26 <!-- cron表达式 -->
27 <propertyname="cronExpression"value="10,15,20,25,30,35,40,45,50,55 * * * * ?"></property>
28 </bean>
29
30 <!-- 任务 -->
31 <beanid="jobtask"class="org.springframework.scheduling.quartz.JobDetailBean">
32 <propertyname="jobClass">
33 <value>org.leopard.core.quartz.MyDetailQuartzJobBean</value>
34 </property>
35 <propertyname="jobDataAsMap">
36 <map>
37 <entrykey="targetObject"value="synUsersJob"/>
38 <entrykey="targetMethod"value="execute"/>
39 </map>
40 </property>
41 </bean>
42
43 <!-- 要调用的工作类 -->
44 <beanid="synUsersJob"class="org.leopard.core.quartz.job.SynUsersJob"></bean>
45
46 </beans>
主要看红色加粗部分...
测试
Ok 配置完成,我们把oa_ssh部署到两台tomcat上面,分别启动。
可以看到我们先启动的tomcat控制台打印出日志
另外一台没有打印日志
这时我们把执行定时任务的那台tomcat停止,可以看到等了一会之后,我们的另外一台tomcat会把之前tomcat执行的定时任务接管过来继续执行,我们的集群是成功的。
参考网址:
https://www.cnblogs.com/yinfengjiujian/p/8670026.html
https://blog.csdn.net/u012909738/article/details/74454810
Spring+Quartz集群环境下定时调度的解决方案的更多相关文章
- 集群环境下定时调度的解决方案之Quartz集群
集群环境可能出现的问题 在上一篇博客我们介绍了如何在自己的项目中从无到有的添加了Quartz定时调度引擎,其实就是一个Quartz 和Spring的整合过程,很容易实现,但是我们现在企业中项目通常都是 ...
- spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】
最近做了一个spring boot 整合 quartz 实现 动态定时任务配置,在集群环境下运行的 任务.能够对定时任务,动态的进行增删改查,界面效果图如下: 1. 在项目中引入jar 2. 将需要 ...
- Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群
Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群 >>>>>>>>>>>>>> ...
- quartz在集群环境下的最终解决方案
在集群环境下,大家会碰到一直困扰的问题,即多个 APP 下如何用 quartz 协调处理自动化 JOB . 大家想象一下,现在有 A , B , C3 台机器同时作为集群服务器对外统一提供 SERVI ...
- 在tomcat集群环境下redis实现分布式锁
上篇介绍了redis在集群环境下如何解决session共享的问题.今天来讲一下如何解决分布式锁的问题 什么是分布式锁? 分布式锁就是在多个服务器中,都来争夺某一资源.这时候我们肯定需要一把锁是不是 , ...
- Spring+quartz集群解决多服务器部署定时器重复执行的问题
一.问题描述 Spring自带的Task虽然能很好使用定时任务,只需要做些简单的配置就可以了.不过如果部署在多台服务器上的时候,这样定时任务会在每台服务器都会执行,造成重复执行. 二.解决方案 Spr ...
- 分布式集群环境下,如何实现session共享五(spring-session+redis 实现session共享)
这是分布式集群环境下,如何实现session共享系列的第五篇.在上一篇:分布式集群环境下,如何实现session共享四(部署项目测试)中,针对nginx不同的负载均衡策略:轮询.ip_hash方式,测 ...
- Redis集群环境下的键值空间监听事件实现方案
一直想记录工作中遇到的问题和解决的方法,奈何没有找到一方乐土,最近经常反思,是否需要记录平时的点滴,后台还是决定下定决心记录一些,以便以后用到的时候找不着,实现这样的一个功能主要也是业务所需要的. 需 ...
- 【SpringBoot】spring-session-data-redis 解决集群环境下session共享
为什么会产生Session共享问题 集群情况下,session保存在各自的服务器的tomcat中,当分发地址至不同服务时,导致sesson取不到,就会产生session共享问题. 解决方案 负载均 ...
随机推荐
- jmeter向ActiveMQ发送消息_广播/订阅(Topics 队列)
问题描述:测试中需要模拟大量设备的消息上报到平台,但是实际测试中没有那么多设备,所以采取用jmeter直接往ActiveMQ模拟发送设备消息 解决思路:获取平台采取的是Queues还是Topics : ...
- GNU C和C99标准中的可变参数宏(variadic macros)
用可变参数宏(variadic macros)传递可变参数表你可能很熟悉在函数中使用可变参数表,如: void printf(const char* format, …); 直到最近,可变参数表还是只 ...
- WebApp的自动测试工具: Jenkins
一.下载并安装(msi)https://jenkins.io/download/thank-you-downloading-windows-installer-stable/ 在安装过程这, 需要从p ...
- 个人简介HTML
码云链接:https://gitee.com/lengxiaoyixuan222/codes/z4dxnvr0ce2blpkihsg7985 源代码: <!doctype html> &l ...
- supersocket 遇到的Failed to initialize 和 log4net用法
使用Bootstrap来通过配置启动SuperSocket的时候总是显示Failed to initialize! , 官网配置中 <superSocket> <servers&g ...
- 微服务架构基础之Service Mesh
ServiceMesh(服务网格) 概念在社区里头非常火,有人提出 2018 年是 ServiceMesh 年,还有人提出 ServiceMesh 是下一代的微服务架构基础. 那么到底什么是 Serv ...
- Celery异步的分布式任务调度理解
什么是Celery呢? Celery是一个用Python开发的异步的分布式任务调度模块. Celery本身不包含消息服务,使用第三方消息服务,也就是Broker,来传递任务,目前支持的有Rebbimq ...
- expdp/impdp数据泵分区表导入太慢了。添加不检查元数据参数提高效率:ACCESS_METHOD=DIRECT_PATH
分区表数据泵导入太慢,达不到客户的迁移要求导出语句如下:(10G单节点)userid='/ as sysdba'directory=milk_dirdumpfile=mon_%U.dmplogfile ...
- [转]Python 的列表解析式,集合解析式,字典解析式
Python 的列表解析式,集合解析式,字典解析式 这三种都是 python 里面的语法糖. 语法糖,Syntactic Sugar,就是为了写程序时候少出错,发明的一些简便的方法,但不影响这个语法的 ...
- IntelliJ IDEA 集成 SVN
在idea中使用subversion提交代码需要使用SVN SVN下载官网:https://tortoisesvn.net/downloads.html 可以根据自己电脑下载相应的版本,如果安装了的需 ...