日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

發布時間:2023/12/4 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

 一般拿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集群部署【附源码】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。