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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式

發(fā)布時(shí)間:2023/12/10 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景:?默認(rèn)情況下,Quartz.Net作業(yè)是持久化在內(nèi)存中的,即 quartz.jobStore.type = "Quartz.Simpl.RAMJobStore, Quartz",這種模式有以下弊端:

① 想在A服務(wù)器上控制B服務(wù)器上已經(jīng)發(fā)布了的job和trigger不方便;

② 很難實(shí)現(xiàn)Web端(寄宿在IIS上)管理作業(yè),客戶端(發(fā)布成服務(wù))的這種模式。

③ 最大弊端就是一旦服務(wù)器宕機(jī)或者重啟,調(diào)度器Schdeuler對(duì)應(yīng)的所有作業(yè)(job、trigger及其對(duì)應(yīng)關(guān)系)將丟失,不得不重新發(fā)布;

?解決方案:

  針對(duì)問題1. 可以借助Remote代理的模式,通過TCP協(xié)議在A服務(wù)器上直接獲取B服務(wù)器上的Scheduler,然后進(jìn)行操作。(詳情點(diǎn)擊)

  針對(duì)問題2. 客戶端作為Server端進(jìn)行調(diào)度的執(zhí)行,Web端通過Remote模式獲取客戶端的中的Scheduler,然后進(jìn)行作業(yè)的管理,問題是一旦客戶端端掛機(jī),Web端是連接不上的

  針對(duì)問題3. 無論代理還是不代理,只要Server端一掛機(jī),保存在內(nèi)存中的作業(yè)都會(huì)丟失,所以這個(gè)時(shí)候,我們需要另辟蹊徑,將作業(yè)持久化進(jìn)行遷移,比如遷移到數(shù)據(jù)庫中,這樣話,即使服務(wù)器宕機(jī),數(shù)據(jù)庫中存儲(chǔ)的作業(yè)信息仍然存在,下次只需要開啟Scheduler即可,無須配置job和trigger了,同時(shí)也解決了上述問題1和問題2,即都可以直接修改數(shù)據(jù)庫即可。

該章節(jié)也是為開篇提出的目標(biāo)三鋪?zhàn)詈笠坏缆?#xff0c;下面著重介紹持久化SQLServer數(shù)據(jù)庫。

步驟1:準(zhǔn)備數(shù)據(jù)庫腳本。

  下載地址為:https://github.com/quartznet/quartznet/blob/master/database/tables/tables_sqlServer.sql,執(zhí)行后的數(shù)據(jù)庫如下圖:

重點(diǎn)介紹一下以上表的含義:

  qrtz_blob_triggers?: 以Blob?類型存儲(chǔ)的觸發(fā)器。?

  qrtz_calendars:存放日歷信息, quartz可配置一個(gè)日歷來指定一個(gè)時(shí)間范圍。?

  qrtz_cron_triggers:存放cron類型的觸發(fā)器。?

  qrtz_fired_triggers:存放已觸發(fā)的觸發(fā)器。?

  qrtz_job_details:存放一個(gè)jobDetail信息。?

  qrtz_job_listeners:job**監(jiān)聽器**。?

  qrtz_locks: 存儲(chǔ)程序的悲觀鎖的信息(假如使用了悲觀鎖)。?

  qrtz_paused_trigger_graps:存放暫停掉的觸發(fā)器。?

  qrtz_scheduler_state:調(diào)度器狀態(tài)。?

  qrtz_simple_triggers:存放簡(jiǎn)單觸發(fā)器的信息。?

  qrtz_trigger_listeners:觸發(fā)器監(jiān)聽器。?

  qrtz_triggers:將Trigger和job進(jìn)行關(guān)聯(lián)的表。

注:cron方式需要用到的4張數(shù)據(jù)表:?qrtz_cron_triggers,qrtz_fired_triggers,qrtz_job_details,qrtz_triggers。

步驟2:代碼進(jìn)行持久化數(shù)據(jù)庫配置

  需要配置的信息有SQLServer版本、數(shù)據(jù)庫連接字符串、存儲(chǔ)類型、數(shù)據(jù)源名稱、驅(qū)動(dòng)類型,代碼如下:

1 var properties = new NameValueCollection();2 //SQLServer版本3 properties.Add("quartz.dataSource.myDS.provider", "SqlServer-20");4 //表名前綴(可有可無)5 //properties.Add("quartz.jobStore.tablePrefix", "QRTZ_");6 //數(shù)據(jù)庫連接字符串7 properties.Add("quartz.dataSource.myDS.connectionString", "Data Source=.;Initial Catalog=quartz;User ID=sa;Password=123456");8 //properties.Add("quartz.dataSource.myDS.connectionString", "Server =.;Database = quartz;Trusted_Connection =True;"); 9 //JobStore設(shè)置(JobStoreTX: 帶有事務(wù);JobStoreCMT:不帶有事務(wù)) 10 //存儲(chǔ)類型 11 properties.Add("quartz.jobStore.type", "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"); 12 //數(shù)據(jù)源名稱 13 properties.Add("quartz.jobStore.dataSource", "myDS"); 14 //驅(qū)動(dòng)類型 15 properties.Add("quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz");

步驟3:向數(shù)據(jù)庫中持久化作業(yè),并開啟調(diào)度。

代碼如下:

1 var factory = new StdSchedulerFactory(properties);2 IScheduler scheduler = factory.GetScheduler();3 var job = JobBuilder.Create<HelloJob4>()4 .WithIdentity("ypfJob1", "ypfJobGroup1")5 .Build();6 var trigger = TriggerBuilder.Create()7 .WithIdentity("ypfTrigger1", "ypfTriggerGroup1")8 .WithCronSchedule("/3 * * * * ?")9 .Build(); 10 if (!scheduler.CheckExists(job.Key)) 11 { 12 scheduler.ScheduleJob(job, trigger); 13 } 14 scheduler.Start();

運(yùn)行結(jié)果為:

?

此時(shí)分析數(shù)據(jù)庫中的數(shù)據(jù):

QRTZ_CRON_TRIGGERS??表:即存放cron類型的trigger

?QRTZ_JOB_DETAILS? 表:即存放job的信息

?

QRTZ_TRIGGERS?表:將Trigger和job進(jìn)行關(guān)聯(lián)的表

?QRTZ_FIRED_TRIGGERS?表:

?

下面做幾個(gè)實(shí)驗(yàn),驗(yàn)證持久化問題:

?實(shí)驗(yàn)1:去掉代碼中job和trigger的創(chuàng)建及關(guān)聯(lián),直接進(jìn)行調(diào)度器的啟動(dòng)。

?

實(shí)驗(yàn)結(jié)果:調(diào)度正常按照每3s執(zhí)行一次,證明作業(yè)持久化數(shù)據(jù)庫成功。

?

實(shí)驗(yàn)2:修改數(shù)據(jù)庫中的cron表達(dá)式為每5s執(zhí)行一次,然后保持實(shí)驗(yàn)1中的代碼注釋,運(yùn)行代碼。

?

實(shí)驗(yàn)結(jié)果:調(diào)度變?yōu)槊扛?s執(zhí)行一次了,證明作業(yè)持久化數(shù)據(jù)庫成功。

?

實(shí)驗(yàn)3:我們?cè)谏厦娴臄?shù)據(jù)庫表中發(fā)現(xiàn)一個(gè)現(xiàn)象,第一個(gè)字段都為Sched_Name,即調(diào)度器的名稱,而且默認(rèn)都為QuartzScheduler,那么如何增加多個(gè)不同名稱的調(diào)度器呢?獲取的時(shí)候又是怎么獲取指定的調(diào)度器呢?都是通過下面的這句代碼配置:

properties.Add("quartz.scheduler.instanceName", "Ypf1Scheduler");

?分享完整代碼:

var properties = new NameValueCollection();//SQLServer版本properties.Add("quartz.dataSource.myDS.provider", "SqlServer-20");//表名前綴(可有可無)//properties.Add("quartz.jobStore.tablePrefix", "QRTZ_");//數(shù)據(jù)庫連接字符串properties.Add("quartz.dataSource.myDS.connectionString", "Data Source=.;Initial Catalog=quartz;User ID=sa;Password=123456");//properties.Add("quartz.dataSource.myDS.connectionString", "Server =.;Database = quartz;Trusted_Connection =True;"); //JobStore設(shè)置(JobStoreTX: 帶有事務(wù);JobStoreCMT:不帶有事務(wù))//存儲(chǔ)類型properties.Add("quartz.jobStore.type", "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz");//數(shù)據(jù)源名稱properties.Add("quartz.jobStore.dataSource", "myDS");//驅(qū)動(dòng)類型properties.Add("quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz");//Scheuler的名稱,用于處理多個(gè)調(diào)度器的情況(指定和獲取都是用這句代碼,如果不指定的話,默認(rèn)均為QuartzScheduler名稱){properties.Add("quartz.scheduler.instanceName", "Ypf1Scheduler");}var factory = new StdSchedulerFactory(properties);IScheduler scheduler = factory.GetScheduler();var job = JobBuilder.Create<HelloJob4>().WithIdentity("ypfJob1", "ypfJobGroup1").Build();var trigger = TriggerBuilder.Create().WithIdentity("ypfTrigger1", "ypfTriggerGroup1").WithCronSchedule("/10 * * * * ?").Build();//Scheduler只要存在相同的job名稱,將不在關(guān)聯(lián) (這里需要根據(jù)實(shí)際要求來處理)if (!scheduler.CheckExists(job.Key)){scheduler.ScheduleJob(job, trigger);}scheduler.Start();

發(fā)現(xiàn)數(shù)據(jù)中上述的幾張表中多了一條數(shù)據(jù):

?

?

  PS:前面有博友【?搵中求勝】給我留言提示集群的問題,這里借助他的話給大家一個(gè)提醒:

  在使用?Quartz.Impl.AdoJobStore?做集群時(shí),一旦出現(xiàn)連接超時(shí)或者底層的SQL錯(cuò)誤,這個(gè)Job將徹底堵住,即使數(shù)據(jù)庫連接恢復(fù)該JOB也得不到恢復(fù),繼承自IJob的Execute方法將不會(huì)被調(diào)用。

因此,必須有一個(gè)Timer對(duì)這些超時(shí)未執(zhí)行的Job做重置或者移除再加入(切誤參考網(wǎng)上DEMO做一個(gè)Manager繼承IJob,因?yàn)镸anager也被堵住了)

?

二. 雙機(jī)熱備的集群模式

集群的兩種形式:

  1.讀寫分離:即master - slave,在SQLServer通過“發(fā)布-訂閱”來實(shí)現(xiàn),寫是落庫到master,讀從slave中,一個(gè)主多個(gè)從。

  2.雙機(jī)熱備:即一主多備,高可用,主掛掉了,備會(huì)自動(dòng)頂上去, Quartz.Net集群采用的就是這種形式(備用服務(wù)啟動(dòng),最短大約需要7.5s)。

配置代碼在持久化的基礎(chǔ)上多了兩句:

  properties["quartz.jobStore.clustered"] = "true";
  properties["quartz.scheduler.instanceId"] = "AUTO";

?下面分享完成的一段代碼:

1 var properties = new NameValueCollection();2 3 properties["quartz.dataSource.sqlserver.provider"] = "SqlServer-20";4 properties["quartz.dataSource.sqlserver.connectionString"] = @"Data Source=.;Initial Catalog=quartz;User ID=sa;Password=123456";5 properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";6 //注意這個(gè)名字改為了sqlserver,上面的都要跟著改,也可以改為別的名7 properties["quartz.jobStore.dataSource"] = "sqlserver";8 properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz";9 10 //cluster 集群指定 11 properties["quartz.jobStore.clustered"] = "true"; 12 properties["quartz.scheduler.instanceId"] = "AUTO"; 13 14 //Scheuler的名稱,用于處理多個(gè)調(diào)度器的情況(指定和獲取都是用這句代碼,如果不指定的話,默認(rèn)均為QuartzScheduler名稱) 15 { 16 properties.Add("quartz.scheduler.instanceName", "QuartzSchoolScheduler"); 17 } 18 19 var factory = new StdSchedulerFactory(properties); 20 var scheduler = factory.GetScheduler(); 21 var job = JobBuilder.Create<HelloJob4>() 22 .WithIdentity("job3", "jobGroup3") 23 .Build(); 24 //trigger 2s執(zhí)行一次 25 var trigger = TriggerBuilder.Create() 26 .WithIdentity("trigger3", "triggerGroup3") 27 .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever()) 28 .Build(); 29 var isExists = scheduler.CheckExists(job.Key); 30 if (!isExists) 31 { 32 //開始調(diào)度 33 scheduler.ScheduleJob(job, trigger); 34 } 35 scheduler.Start();

數(shù)據(jù)庫表的變化:

?QRTZ_SIMPROP_TRIGGERS 表: ?(與cron的trigger存放的位置不同)

?QRTZ_JOB_DETAILS 表:

?

?QRTZ_TRIGGERS 表:

?QRTZ_FIRED_TRIGGERS 表:

?

運(yùn)行結(jié)果:

?  生成一下代碼,直接在bin文件里打開,然后再打開一個(gè),發(fā)現(xiàn)第一個(gè)正常運(yùn)行,第二個(gè)不運(yùn)行。

?

  關(guān)閉第一個(gè)客戶端,7.5s后發(fā)現(xiàn)第二個(gè)正常啟動(dòng)運(yùn)行,驗(yàn)證雙機(jī)熱備。

?

?

?

總結(jié)

以上是生活随笔為你收集整理的第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。