java quartz 性能_[译]如何优化Quartz调度器性能

java quartz 性能_[译]如何优化Quartz调度器性能译文由杰微刊兼职译者刘晓冬翻译,杰微刊审校及发布。Quartz是一个流行的Java应用开源作业调度库。eBay在自己的很多项目中用它来调度作业。Quartz在低负载时运行良好,但在高负载时会遇到问题。许多触发器会失效,导致执行线程无法得到任务,大量作业阻塞在触发器表中。所以我们必须进行性能调优。本章描述我们是如何逐步解决问题并优化Quartz的。问题在哪?1.Quartz作业不能被调度和执行。2….

大家好,又见面了,我是你们的朋友全栈君。

译文由杰微刊兼职译者刘晓冬翻译,杰微刊审校及发布。

Quartz是一个流行的Java应用开源作业调度库。eBay在自己的很多项目中用它来调度作业。

Quartz在低负载时运行良好,但在高负载时会遇到问题。许多触发器会失效,导致执行线程无法得到任务,大量作业阻塞在触发器表中。

所以我们必须进行性能调优。本章描述我们是如何逐步解决问题并优化Quartz的。

问题在哪?

1.Quartz作业不能被调度和执行。

2.许多作业在simple_triggers表中等待执行,但一些作业在fired_triggers中。这些简单触发器应当设置REPEAT_INTERVAL,表明它们是重复作业。

TIMES_TRIGGERED表示该作业被触发的次数

3a6f4d7c54a043abcc283f0f3db26c61.png

3.日志文件中有大量的“Handling the first 20 triggers that missed their scheduled fire-time …”(处理错过调度触发时间点的前20个触发器)

5c12cbaffef663ebc8926323b95ed279.png

4.数据库session增加,许多session等待在“SELECT * FROM qrtz_LOCKS WHERE SCHED_NAME = ‘{SCHED_NAME}‘ AND LOCK_NAME = ‘TRIGGER_ACCESS’ FOR UPDATE”。

什么是触发器失效?

在我们能理解为什么发生之前,先来看看触发器失效。这是来自Quartz官方网站的解释:

触发器失效发生在一致性触发器,因为调度器关闭而错过触发时间点,或者因为Quartz线程池中没有可执行作业的线程时。不同的触发器类型有不同的失效指令。默认地,他们使用一种“智能策略”指令—该指令拥有基于触发器类型和配置的动态行为。当触发器开始时,它搜索失效的一致性触发器,并根据配置的失效指令更新每一个触发器。当你开始在自己的项目中使用Quartz时,你应该先熟悉那些给定类型定义的失效指令,并在JavaDoc中给予解释。关于失效指令更详细的信息将会在每一个触发器类型的辅导中给出。

例如,有一个10秒间隔的触发器,以“0秒”为时间戳。在第“0秒”,它通过QuartzSchedulerThread把自己传递给ExecuteThread执行,并把NEXT_FIRE_TIME设定为“10秒”。不幸的是它耗时超过60秒,没有在10秒之内完成,于是错过了“10秒”,“20秒”,“60秒”等触发点。

“70秒”后,MisfireHandler发现它失败了,所以NEXT_FIRE_TIME应该被设置为“80秒”。这就是重复简单触发器的“智能策略”指令。

4e96957e01bdb655808f4545156c94d4.png

为什么要触发器访问锁?

Quartz支持集群,所以我们可以在集群中配置多实例。它需要使用数据库锁来协调在triggers和fire_triggers表中的更新。Quartz使用MySQL中标准行级锁“SELECT * FROM … FOR UPDATE”。

图片有助于理解触发器访问锁。

1、如果一个新作业要在triggers表中存储,它必须在LockOnInsert 为真(默认值)时获得TRIGGER_ACCESS。

2、QuartzSchedulerThread 也需要在它得到触发器并触发后拿到锁。

3、MisfiredHandler拿到TRIGGER_ACCESS用以恢复失效触发器并为失效触发器更新NEXT_FIRE_TIME。

d298a7f2710b294a94a43419fbe25295.png

当大量触发器失效时,系统会恶化

我们在产品中多次目睹这样的问题。以下是细节:

1.一个实例只有几个执行的作业。

2.一旦失效发生,减少实例数量可以帮助系统恢复。

基于日志和数据库信息,我们通过以下几步在本地复现了问题:

1.在本地安装MySQL数据库。

2.我们从Quartz的使用案例中复制MisfireExample

3.我们改变了配置以使Quartz使用MySQL数据库。

4.我们修改MisfireExample支持多实例,以便于我们可以在本地运行多实例。

5.我们将系统设置为每500毫秒生成一些触发器重复执行3秒间隔的触发器5遍。

做了这些更改后运行MisfireExample实例更容易复现问题。下面我们可以看到和产品中一样的问题。

1.大量触发器在simple_triggers表中堆积。

7ce130d963ea3b2a87ef6b82b80da816.png

2.一些作业在fired_triggers表中触发。

48062c88c70ada40f2a07273bcb332b4.png

3.大量失效信息打印在控制台。

7b8e28da7874d20cdcdc372d4f99c2be.png

4.许多MySQL sessions 等待在“SELECT * FROM qrtz_LOCKS WHERE SCHED_NAME = ‘SCHED_NAME’ AND LOCK_NAME = ‘TRIGGER_ACCESS’ FOR UPDATE”.

5.停止新触发器的存储无助于恢复触发器

6.停止3或4个实例增加了有效触发器。系统将在执行更多作业时恢复正常。

在第5步中,作业生成器在每个实例中每分钟只生成两个触发器。即使生成频率很低,系统也没有恢复。这意味着StoreJobAndTriggers在改场景中不是关键因素。问题在于MisfireHandler和QuartzSchedulerThread竞争TRIGGER_ACCESS锁。每一个实例都有一个MisfireHandler和QuartzSchedulerThread。

你可能也注意到打印的失效信息,约每秒打印一次。这说明它每次更新20行约耗时1秒。

另一个事实是每次QuartzSchedulerThread拿到TRIGGER_ACCESS锁后获取一个触发器。和MisfireHandler的速度比起来,它是一种高速操作。

下图表明了为什么少实例比多实例在遇到失效问题时更好。

更少的实例意味着QuartzSchedulerThread有更多的机会拿到锁。

5d2906b1e854b0f881099d4ff73cf3c4.png

如何优化?

659c3f12b52600d3e783a452d8e4a287.png

上图展示了优化结果。我们生成500个enable/disable流量作业,开启两个Quartz实例处理。使用原始代码大约需要270分钟完成所有作业,而使用Quartz批量模式则只需要36分钟。

使用批量模式

Quartz支持批量模式。在批量模式中,QuartzSchedulerThread可以获得基于活跃执行线程数的作业。当我们在这种模式下配置时,触发器可以更快的执行,有效触发器数和所有实例的总线程数相等。

这段代码是创建Quartz调度器的方法。我们可以设置maxBatchSize和batchTimeWindow来影响批量模式。

我们把maxBatchSize设置成和执行线程数一样。batchTimeWindow应该基于特定时间段内的任务触发数。代码中我们设置成1秒。

2332b017c0e454cb7c430a80d0d2c988.png

改变作业完成顺序

让更新作业数据任务在拿到锁之前执行。Quartz执行线程需要在一个阶段完成后拿到TRIGGER_ACCESS锁。它在拿到锁后更新Job Data和触发器表中的状态。更新作业数据耗费大量时间因为作业数据需要序列化并存储到作业明细表中。通常只有一个执行线程更新作业数据。所以不需要锁。

当我们把“updating job data”这一步搬到自己的代码中,它降低了锁的时间。这样,耗时27分钟就完成所有的500个作业。如图

f7904a0e3b49266313a1aef9b9f4ee2f.png

减少上下文切换;尽可能多的执行不同阶段

我们的作业有许多阶段。一个阶段可以独立的运行在任何实例上。作业数据应该永久存储在数据库中。它也需要在每一个阶段完成后更新触发器状态。在一个执行线程上执行所有阶段并降低锁的使用是一个很好的改良。

d51d667c798ccf192b429f3eb08aa67f.png

摘要

Quartz在集群环境下使用数据库锁。常规配置的作业在高负载下堆叠。批量模式可以改善性能,减少锁次数也会有所帮助。

相关:https://www.cnblogs.com/daxin/category/483763.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159186.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月14日 上午6:46
下一篇 2022年7月14日 上午6:46


相关推荐

  • Java集合篇:ArrayList详解

    Java集合篇:ArrayList详解

    2021年10月4日
    45
  • django动态路由_路由器和转换器的区别

    django动态路由_路由器和转换器的区别自定义路径转换器有时候上面的内置的url转换器并不能满足我们的需求,因此django给我们提供了一个接口可以让我们自己定义自己的url转换器django内置的路径转换器源码解析在我们自定义路由转

    2022年7月30日
    9
  • 奇怪的现象:touchesBegan: 与UITapGestureRecognizer手势没有人响应 以及set方法的妙用

    奇怪的现象:touchesBegan: 与UITapGestureRecognizer手势没有人响应 以及set方法的妙用本打算实现一个点击按钮弹出一个landKindView然后点击屏幕其他部分时移除这个VIew,没想到的是,出了诸多不可思议的问题。在给这个控制器的View添加手势时,然后居然拦截不到,touchesbegin方法,然后又试了下添加tapGesture,依旧是没有反应。然后我试着在touchesBegin方法中 实现[supertouchesBegins….];依旧是没有任

    2022年7月25日
    12
  • cas 认证流程[通俗易懂]

    cas 认证流程[通俗易懂]一 配置实例应用场景: cas 服务部署在192.168.7.115 ,是一个web 应用,访问地址为:https://cas.mycompany.com:8443/cas/ 。web1 应用位于192.168.7.90 ,访问地址为:http://192.168.7.90:8081/web1 ,web2 应用位于192.168.7.90 ,访问地址为:http://192.168.7.90:

    2025年8月19日
    8
  • Pycharm中无解释器interpreter的解决方法

    Pycharm中无解释器interpreter的解决方法存在问题 Pycharm 和 Anaconda 安装好后 运行 Pycharm 程序时显示缺少 interpreter 解释器 解决方案 Pycharm 中依次点击 file setting 弹框中列表 ProjectInter 右侧小齿轮图标 选择 python exe 所在路径即可 注 如果安装了 Anaconda 则默认自带安装 python 在根目录下找到 python exe 即可 如果未安装 Anaconda 安装的是 python 那就在相应目录 同样找到 python exe 即可

    2026年3月27日
    3
  • SQL Server2008安装详细教程[通俗易懂]

    SQL Server2008安装详细教程[通俗易懂]1.将光盘文件解压成文件夹格式,(解压过程比较慢,请耐心等待);2.打开开始菜单的设置;3.打开设置后,点击更新和安全,然后进入;4.在Windows安全中心,将其关闭(注意我这里已经关闭了);5.然后再到安装包文件夹目录,找到setup.exe文件,右击,以管理员身份运行;6.右击运行后,会出来这个页面(如果没有出现这个页面,请直接跳转至第14步),然后点击下载并安装此功能,进入下一步;7.进入下一个页面后,你会发现它会出来一个正在下载所需的文件的页面,然后等待就行;8

    2022年6月23日
    53

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号