Quartz-1.8.6 任務調度延遲(未能按時調度)

1、問題描述

? ? 用集群方式使用quartz-1.8.6,部署2個節(jié)點,約1200個定時任務,每個任務執(zhí)行耗時100毫秒,線程池大小設置為25,數(shù)據(jù)庫連接池大小設置的為30,任務調度并發(fā)上不去(只能達到100的TPS),導致某些時間節(jié)點上任務不能按時調度(整點整分上問題更突出,原因是配置cron表達式式,多數(shù)任務配置的為整點整分整秒執(zhí)行,導致該時間點上待啟動的任務過多,無法按時調度)。

2、嘗試解決

2.1? 擴線程池大小、連接池大小

沒有改善,通過線程dump看,quartz的工作線程很空閑,但是并發(fā)依然只能在100TPS。

"DataScheduler_QuartzSchedulerThread" prio=10 tid=0x00007f4158802800 nid=0xec runnable [0x00007f4188a54000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:100)
at
com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:143)
at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:173)
- locked <0x00000000a642a270> (a com.mysql.jdbc.util.ReadAheadInputStream)
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2911)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3337)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3327)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2530)
- locked <0x00000000a64232b8> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1907)
- locked <0x00000000a64232b8> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2030)
- locked <0x00000000a64232b8> (a com.mysql.jdbc.JDBC4Connection)
at sun.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.bill99.inf.jdbc.ext.proxy.PStatementProxy.invoke(PStatementProxy.java:22)
at com.sun.proxy.$Proxy24.executeQuery(Unknown Source)
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectTrigger(StdJDBCDelegate.java:2112)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1553)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1547)at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2767)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$36.execute(JobStoreSupport.java:2732)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3763)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2728)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:264)

"DataScheduler_Worker-25" prio=10 tid=0x00007f41587d5000 nid=0xeb in Object.wait() [0x00007f4188b55000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:543)
- locked <0x00000000aa2db760> (a org.quartz.simpl.SimpleThreadPool$WorkerThread)

2.2? 擴節(jié)點

? ? 沒有改善,反而出現(xiàn)了MySQL 獲取悲觀鎖超時的錯誤。

3 繼續(xù)深挖

? ? 通過觀察MySQL的query日志,反向看Quartz是如何通過quartz的表來執(zhí)行的。
1、可以看出來quartz集群下運行時通過悲觀鎖來控制任務同一時間點只能被一個節(jié)點調度;
2、設置SQL_SELECT_LIMIT來控制每次查詢接下來5個待執(zhí)行的Trigger;
此時,我們猜測是5設置的過小,導致并發(fā)上不去,修改quartz-1.8.6源碼改成50,測試,并發(fā)依然上不去!繼續(xù)看源碼,發(fā)現(xiàn)Quartz取5個或者50個,最終只取第1個Trigger交給ThreadPool執(zhí)行!QuartzSchedulerThread該線程無限循環(huán)每次只取1個Trigger!

4 結論

? ? Quartz同一時間點只能由一個節(jié)點的QuartzSchedulerThread線程搶占到排他鎖,并查詢出1個Trigger,交給工作線程運行,如果一次查詢耗時10ms,無論幾個節(jié)點并發(fā)都會在100TPS。不是工作線程不夠、不是數(shù)據(jù)庫連接不夠;擴節(jié)點也沒用!

? ? 查閱quartz文檔,文檔中也指出,如果你的任務運行時間較長,分鐘級的,擴節(jié)點是有好處的。如果你的任務都是短時間運行就結束的,秒級、毫秒級的,有成千上萬的這樣的任務的話,你應該采用多個Scheduler實例,多套Quartz表來提升性能。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容