一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz强大的集群机制,可以采用基于

sqlserver,mysql的集群方案,当然还可以在第三方插件的基础上实现quartz序列化到热炒的mongodb,redis,震撼力可想而知,接下来本篇就和大家聊

一聊怎么搭建基于sqlserver的quartz集群,实现这么一种双机热备的强大功能。

一:下载sqlserver版的建表脚本

    首先大家可以通过github上搜索quartz的源代码,在源码项目的/database/tables目录下,可以找到firebird,oracle,mysql,sqlserver等建库脚本,

本篇只需拿取sqlserver版本即可。 https://github.com/quartznet/quartznet/tree/master/database/tables  如下图所示

从上面的截图中可以看到,我接下来要做的事情就是增加一个你需要创建的database名字,这里取为:【quartz】

二:配置quartz的集群参数

当我们写var scheduler = StdSchedulerFactory.GetDefaultScheduler()这段代码的时候,如果大家看过源码的话,会知道这个GetScheduler的

过程中有一个初始化方法【Instantiate】方法,此方法中你会发现在做DBProvider的时候会需要几个参数来初始化DB的,比如下面看到的几个标红属性。

IList<string> dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix);

foreach (string dataSourceName in dsNames)

{

string datasourceKey = "{0}.{1}".FormatInvariant(PropertyDataSourcePrefix, dataSourceName);

NameValueCollection propertyGroup = cfg.GetPropertyGroup(datasourceKey, true);

PropertiesParser pp = new PropertiesParser(propertyGroup);

Type cpType = loadHelper.LoadType(pp.GetStringProperty(PropertyDbProviderType, null));

// custom connectionProvider...

if (cpType != null)

{

IDbProvider cp;

try

{

cp = ObjectUtils.InstantiateType<IDbProvider>(cpType);

}

catch (Exception e)

{

initException = new SchedulerException("ConnectionProvider of type '{0}' could not be instantiated.".FormatInvariant(cpType), e);

throw initException;

}

try

{

// remove the type name, so it isn't attempted to be set

pp.UnderlyingProperties.Remove(PropertyDbProviderType);

ObjectUtils.SetObjectProperties(cp, pp.UnderlyingProperties);

cp.Initialize();

}

catch (Exception e)

{

initException = new SchedulerException("ConnectionProvider type '{0}' props could not be configured.".FormatInvariant(cpType), e);

throw initException;

}

dbMgr = DBConnectionManager.Instance;

dbMgr.AddConnectionProvider(dataSourceName, cp);

}

else

{

string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null);

string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null);

string dsConnectionStringName = pp.GetStringProperty(PropertyDataSourceConnectionStringName, null);

if (dsConnectionString == null && !String.IsNullOrEmpty(dsConnectionStringName))

{

ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[dsConnectionStringName];

if (connectionStringSettings == null)

{

initException = new SchedulerException("Named connection string '{0}' not found for DataSource: {1}".FormatInvariant(dsConnectionStringName, dataSourceName));

throw initException;

}

dsConnectionString = connectionStringSettings.ConnectionString;

}

if (dsProvider == null)

{

initException = new SchedulerException("Provider not specified for DataSource: {0}".FormatInvariant(dataSourceName));

throw initException;

}

if (dsConnectionString == null)

{

initException = new SchedulerException("Connection string not specified for DataSource: {0}".FormatInvariant(dataSourceName));

throw initException;

}

try

{

DbProvider dbp = new DbProvider(dsProvider, dsConnectionString);

dbp.Initialize();

dbMgr = DBConnectionManager.Instance;

dbMgr.AddConnectionProvider(dataSourceName, dbp);

}

catch (Exception exception)

{

initException = new SchedulerException("Could not Initialize DataSource: {0}".FormatInvariant(dataSourceName), exception);

throw initException;

}

}

}

接下来的问题就是这几个属性是如何配置进去的,仔细观察上面代码,你会发现所有的配置的源头都来自于cfg变量,ok,接下来你可以继续翻看代码,相信

你会看到有一个Initialize方法就是做cfg变量的初始化,如下代码所示:

public void Initialize()

{

// short-circuit if already initialized

if (cfg != null)

{

return;

}

if (initException != null)

{

throw initException;

}

NameValueCollection props = (NameValueCollection) ConfigurationManager.GetSection(ConfigurationSectionName);

string requestedFile = QuartzEnvironment.GetEnvironmentVariable(PropertiesFile);

string propFileName = requestedFile != null && requestedFile.Trim().Length > 0 ? requestedFile : "~/quartz.config";

// check for specials

try

{

propFileName = FileUtil.ResolveFile(propFileName);

}

catch (SecurityException)

{

log.WarnFormat("Unable to resolve file path '{0}' due to security exception, probably running under medium trust");

propFileName = "quartz.config";

}

if (props == null && File.Exists(propFileName))

{

// file system

try

{

PropertiesParser pp = PropertiesParser.ReadFromFileResource(propFileName);

props = pp.UnderlyingProperties;

Log.Info(string.Format("Quartz.NET properties loaded from configuration file '{0}'", propFileName));

}

catch (Exception ex)

{

Log.Error("Could not load properties for Quartz from file {0}: {1}".FormatInvariant(propFileName, ex.Message), ex);

}

}

if (props == null)

{

// read from assembly

try

{

PropertiesParser pp = PropertiesParser.ReadFromEmbeddedAssemblyResource("Quartz.quartz.config");

props = pp.UnderlyingProperties;

Log.Info("Default Quartz.NET properties loaded from embedded resource file");

}

catch (Exception ex)

{

Log.Error("Could not load default properties for Quartz from Quartz assembly: {0}".FormatInvariant(ex.Message), ex);

}

}

if (props == null)

{

throw new SchedulerConfigException(

@"Could not find <quartz> configuration section from your application config or load default configuration from assembly.

Please add configuration to your application config file to correctly initialize Quartz.");

}

Initialize(OverrideWithSysProps(props));

}

仔细阅读上面的一串代码,你会发现,默认quartz参数配置来源于三个地方。

1. app.config中的section节点。

2. bin目录下的~/quartz.config文件。

3. 默认配置的NameValueCollection字典集合,也就是上一篇博客给大家做的一个演示。

我个人不怎么喜欢通过quartz.config文件进行配置,这样也容易写死,所以我还是喜欢使用最简单的NameValueCollection配置,因为它的数据源可来源于第三方存储结构中,配置代码如下:

//1.首先创建一个作业调度池

var properties = new NameValueCollection();

//存储类型

properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";

//驱动类型

properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz";                //数据源名称

properties["quartz.jobStore.dataSource"] = "myDS";

//连接字符串

properties["quartz.dataSource.myDS.connectionString"] = @"server=.;Initial Catalog=quartz;Integrated Security=True";

//sqlserver版本

properties["quartz.dataSource.myDS.provider"] = "SqlServer-20";

//是否集群

properties["quartz.jobStore.clustered"] = "true";

properties["quartz.scheduler.instanceId"] = "AUTO";

上面的代码配置我都加过详细的注释,大家应该都能看得懂,而且这些配置就是这么定死的,没什么修改的空间,大家记住即可。

三:Job和Trigger定义

在集群中环境下,job和trigger的定义该怎么写的?大家也不要想的太复杂,注意一点就可以了,在Schedule一个Job时候,通过CheckExists判断一下这个Job在Scheduler中是否已经存在了,如果存在,你就不能再次通过Schedule去重复调度一个Job就可以了。。。所以判断的代码也很简单,如下所示:

IScheduler scheduler = factory.GetScheduler();

scheduler.Start();

var jobKey = JobKey.Create("myjob", "group");

if (scheduler.CheckExists(jobKey))

{

Console.WriteLine("当前job已经存在,无需调度:{0}", jobKey.ToString());

}

else

{

IJobDetail job = JobBuilder.Create<HelloJob>()

.WithDescription("使用quartz进行持久化存储")

.StoreDurably()

.RequestRecovery()

.WithIdentity(jobKey)

.UsingJobData("count", 1)

.Build();

ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())

.Build();

scheduler.ScheduleJob(job, trigger);

Console.WriteLine("调度进行中!!!");

}

上面这段代码,大家就可以部署在多台机器中了,是不是很简单?

四:强大的cluster完整演示

所有的初始化工作都做完了,接下来我们copy一份bin文件,同时打开两个console程序,如下所示,可以看到job任务只会被一个console调度,另外

一个在空等待。

然后你肯定很好奇的跑到sqlserver中去看看,是否已经有job和trigger的db存储,很开心吧,数据都有的。。。

好了,一切都是那么完美,接下来可以展示一下quartz集群下的高可用啦,如果某一个console挂了,那么另一台console会把这个任务给接过来,实

现强大的高可用。。。所以我要做的事情就是把console1关掉,再看看console2是不是可以开始调度job了???

完美,这个就是本篇给大家介绍的Quartz的Cluster集群,一台挂,另一台顶住,双机热备,当然这些console你可以部署在多台机器中,要做的就是保持各个server的时间同步,因为quarz是依赖于本机server的时间,好了,本篇就先说到这里吧。

原文地址:http://www.cnblogs.com/huangxincheng/p/6916246.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】相关推荐

  1. 使用sqlserver搭建高可用双机热备的Quartz集群部署

    一般拿 Timer 和 Quartz 相比较的,简直就是对 Quartz 的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz强大的集群机制,可以采用基于sqlserver,mysql的集 ...

  2. 浅入浅出keepalived+nginx实现高可用双机热备

    对应用keepalived+nginx技术实现nginx高可用进行简单的分析,下面是通过对keepalived添加校验nginx存活脚本,监控nginx的状态,应用keepalived的主备模式实现n ...

  3. ACS 5.4高可用——双机热备

    ACS 5.4高可用--双机热备 一.安装 安装ACS_v5.4.0.46.0a.iso 1.过程等同于安装Centos,安装完成后输入setup按提示进行acs相关基础配置. 2.配置完成服务会重启 ...

  4. 双机热备_什么是高可用双机热备?双机热备概念原理详解

    双机热备是什么意思?为什么要用双机热备?双机热备有哪些种类?包含了哪些双机热备软件?下面就来简单地说说. 什么是双机热备? 从广义上讲,就是对于重要的服务,使用两台服务器,互相备份,共同执行同一服务. ...

  5. rhcs套件conga实现高可用nginx+httpd集群,fence双机热备, clvm集群

    红帽套件集群 HA( 高可用,双机热备,对外只有一个主机,但是两个主机都活着 ) luci: 提供了管理 rhcs 集群的 web 界面, luci 管理集群主要是通过跟 ricci 通信来完成的. ...

  6. 5双机配置_CentOS 7 高可用双机热备实现

    一.服务器准备 两个linux版本为 CentOS7 x64, mysql 版本为 5.5.31 , 详细安装步骤参考: CentOS7 环境 编译安装mysql源码 二. Mysql 建立主-从服务 ...

  7. Nginx+keepalived 高可用双机热备(主从模式/双主模式)

    基础介绍 负载均衡技术对于一个网站尤其是大型网站的web服务器集群来说是至关重要的!做好负载均衡架构,可以实现故障转移和高可用环境,避免单点故障,保证网站健康持续运行. 关于负载均衡介绍,可以参考:l ...

  8. 搭建高可用的分布式hadoop2.5.2集群  HDFS HA

    HA: High Available(高可用集群) 本次安装的hadoop2.5.2是64bit的,如果需要请在我之前的博文中 规划节点数:(仅考虑HDFS 的HA) HDFS的节点分配: 两个NN ...

  9. 【Nginx】如何基于主从模式搭建Nginx+Keepalived双机热备环境?这是最全的一篇了!!

    写在前面 最近出版了<海量数据处理与大数据技术实战>,详情可以关注 冰河技术 微信公众号,查看<我的<海量数据处理与大数据技术实战>出版啦!>一文. 也有不少小伙伴 ...

最新文章

  1. rhel5.5安装xwindow
  2. 71 mac boook pro 无 gpu 下caffe 安装
  3. 在MVC控制器里面使用dynamic和ExpandoObject,实现数据转义的输出
  4. 理解tcp关闭连接中的time_wait状态
  5. svd奇异值分解_NCL专辑 | 奇异值分解(SVD)
  6. 2021中国到店消费新趋势洞察报告
  7. 学生社团管理系统java_基于JavaEE的学生社团管理系统的设计与实现
  8. android 应用分析,分析 Android 应用
  9. html获取location,通过定义JS窗口对象获取url地址location.search部分的参数值
  10. 30个实用的 Photoshop 动作《免费下载》
  11. mybatis的trim标签
  12. 《Javascript秘密花园》学习笔记(下)
  13. 【jvm jdk】锁状态位之偏向锁
  14. linux tar 命令安装,Linux tar 命令 command not found tar 命令详解 tar 命令未找到 tar 命令安装 - CommandNotFound ⚡️ 坑否...
  15. SPI通信协议详解(四)
  16. win10添加惠普hp laserjet 1010HB打印机
  17. [转载] 网络硬件发展史
  18. 倾听社区的声音,但别被他们牵着鼻子走
  19. 为什么我们的代码难以维护(草稿)
  20. 记录一次canvas小白做相册功能的过程

热门文章

  1. window 效率神器:Wox
  2. 20150203一些移动端H5小bug解决
  3. php如何读出xml的节点内容 两个例子
  4. 送给“苦逼”的IT人系列1:IT人的“钱”景以及收入的两道坎
  5. selenium webdirver之ruby-开发ide安装
  6. Blazor University (5)组件 — 字面量、表达式和指令
  7. 在 Azure Functions 上使用不同的路由前缀
  8. 巧用ActionFilter的AOP特性,为返回的数据增加返回码和消息
  9. 总是想得太简单?试试我的方法
  10. 网络知识 | 《图解TCP/IP》读书笔记(上)