java, quartz 和特定时间触发的多个任务保存在数据库中
java, quartz and multiple tasks triggered at certain times saved in a database
我正在构建一个系统,用户可以在其中设置日历中的未来日期(精确到小时和分钟)。在那个日期,触发器调用特定任务,对每个用户都是唯一的。
每个用户都可以设置不同的日期。系统一开始会有10k+,一个用户可以创建多个触发器。
所以假设我有 10k 个用户,每个用户平均创建 3 个触发器 => 30k 个触发器,有 30k 个不同的日期。
所有日期都保存在数据库中。
我是 quartz 的新手,能否以更优化的方式完成此操作?
我正在考虑每分钟创建一个任务 运行 以获取下一个小时内假设 运行 的任务并将它们从数据库中删除。
你有什么更好的主意吗?有没有人把quartz用于大量的触发器。
正如 Sam 所指出的,有一些很好的主题可以解决同样的问题:
- Quartz Performance
- Quartz FAQ
在上述系统中,处理这么多触发器应该不是问题。但根据我的经验,创建 "JobChecker" 之类的东西是更好的方法。如果你允许你的用户创建自己的触发器,在某些情况下它真的会破坏 Quartz。例如,如果 5000 个用户在同一时间创建一个事件,Quartz 将很难正确处理它们。 (这种情况不太可能经常发生,但有可能,因为您的规范并未排除这种情况。)只有在同时触发大量触发器时,Quartz 才会遇到困难。
我对这个问题的建议是在每个 hour/minute 等中创建一个 运行 的作业,并且应该处理每个用户设置的事件。这种方式类似于 bash
中的 cron
作业。通过这种处理,即使 "triggers" 的数量急剧增加,您的系统也会非常稳定。如果您追求可扩展性,基本上您的思路是正确的。
我完全不明白你为什么需要这里的石英。据我所知,quartz 最好用于调度后端内部进程,而不是从 db 获取的用户定义任务。
只需在触发器创建时对其进行处理,根据触发器将 tasks
table 行保存到您的 tasks
table 中,并且每秒 select 所有未完成的任务使用 start_date
< 系统日期。如果作业重复,则计算下一次执行时间并相应地插入新任务行/更新之前的任务。
您已在数据库中备份了时间表。如果我理解这个想法 - 你希望石英加载所有即将到来的任务以在将来执行它们。
这是有问题的方法:
同步问题:我假设用户可以编辑、删除和向数据库添加新任务。您将不得不定期要求数据库刷新石英作业的状态、删除一些作业、编辑其他作业等。这可能不是微不足道的。程序的状态将是一个长期存在的缓存,需要经常同步。
性能和可扩展性问题:即使提出的解决方案可能适用于 30K 任务,但 可能 不适用于 70k 或 700k 任务。在您的方法中,扩展并不容易——添加新机器需要额外的同步层——哪台机器应该实际执行哪个作业(因为它们都有所有任务)。
我的建议是:
- 将 "stage" 添加到任务 table(新、排队、运行正在、完成、失败)
- 将您的解决方案分成几个部分。 (最初他们可以 运行 在一台机器上,但它很容易扩展)
组件:
任务查找器:定期执行(每隔几秒执行一次)。扫描数据库以查找 "new" 和即将 到期的任务。将找到的任务发送到 Message Queue,并在数据库中将任务标记为 "queued"。标记为 "queued" 必须小心,因为可以有多个 "task finders"。 (作为补充,它可能会发现 N 分钟前标记为 "queued" 或 "running" 且既不是 "finished" 也不是 "canceled" 的任务 - 可能需要重新运行这些)
Message Queue:Taks Finder 和 Task Executor 之间的连接器.
任务执行器:侦听消息队列并处理它接收到的任务。最初将任务标记为 "running",稍后标记为 "finished" 或 "failed"。
通过这种方法,您可以:
- 多台机器上的多个任务执行器
- 多台机器上的多个任务计划程序
- 即使其中一个任务计划程序或执行程序失败,它也不会是单点故障。一些任务会延迟,但会被拾起,然后运行。
这可能无法解决所有情况,但会是一个很好的起点。
我正在构建一个系统,用户可以在其中设置日历中的未来日期(精确到小时和分钟)。在那个日期,触发器调用特定任务,对每个用户都是唯一的。
每个用户都可以设置不同的日期。系统一开始会有10k+,一个用户可以创建多个触发器。
所以假设我有 10k 个用户,每个用户平均创建 3 个触发器 => 30k 个触发器,有 30k 个不同的日期。
所有日期都保存在数据库中。
我是 quartz 的新手,能否以更优化的方式完成此操作?
我正在考虑每分钟创建一个任务 运行 以获取下一个小时内假设 运行 的任务并将它们从数据库中删除。
你有什么更好的主意吗?有没有人把quartz用于大量的触发器。
正如 Sam 所指出的,有一些很好的主题可以解决同样的问题:
- Quartz Performance
- Quartz FAQ
在上述系统中,处理这么多触发器应该不是问题。但根据我的经验,创建 "JobChecker" 之类的东西是更好的方法。如果你允许你的用户创建自己的触发器,在某些情况下它真的会破坏 Quartz。例如,如果 5000 个用户在同一时间创建一个事件,Quartz 将很难正确处理它们。 (这种情况不太可能经常发生,但有可能,因为您的规范并未排除这种情况。)只有在同时触发大量触发器时,Quartz 才会遇到困难。
我对这个问题的建议是在每个 hour/minute 等中创建一个 运行 的作业,并且应该处理每个用户设置的事件。这种方式类似于 bash
中的 cron
作业。通过这种处理,即使 "triggers" 的数量急剧增加,您的系统也会非常稳定。如果您追求可扩展性,基本上您的思路是正确的。
我完全不明白你为什么需要这里的石英。据我所知,quartz 最好用于调度后端内部进程,而不是从 db 获取的用户定义任务。
只需在触发器创建时对其进行处理,根据触发器将 tasks
table 行保存到您的 tasks
table 中,并且每秒 select 所有未完成的任务使用 start_date
< 系统日期。如果作业重复,则计算下一次执行时间并相应地插入新任务行/更新之前的任务。
您已在数据库中备份了时间表。如果我理解这个想法 - 你希望石英加载所有即将到来的任务以在将来执行它们。
这是有问题的方法:
同步问题:我假设用户可以编辑、删除和向数据库添加新任务。您将不得不定期要求数据库刷新石英作业的状态、删除一些作业、编辑其他作业等。这可能不是微不足道的。程序的状态将是一个长期存在的缓存,需要经常同步。
性能和可扩展性问题:即使提出的解决方案可能适用于 30K 任务,但 可能 不适用于 70k 或 700k 任务。在您的方法中,扩展并不容易——添加新机器需要额外的同步层——哪台机器应该实际执行哪个作业(因为它们都有所有任务)。
我的建议是:
- 将 "stage" 添加到任务 table(新、排队、运行正在、完成、失败)
- 将您的解决方案分成几个部分。 (最初他们可以 运行 在一台机器上,但它很容易扩展)
组件:
任务查找器:定期执行(每隔几秒执行一次)。扫描数据库以查找 "new" 和即将 到期的任务。将找到的任务发送到 Message Queue,并在数据库中将任务标记为 "queued"。标记为 "queued" 必须小心,因为可以有多个 "task finders"。 (作为补充,它可能会发现 N 分钟前标记为 "queued" 或 "running" 且既不是 "finished" 也不是 "canceled" 的任务 - 可能需要重新运行这些)
Message Queue:Taks Finder 和 Task Executor 之间的连接器.
任务执行器:侦听消息队列并处理它接收到的任务。最初将任务标记为 "running",稍后标记为 "finished" 或 "failed"。
通过这种方法,您可以:
- 多台机器上的多个任务执行器
- 多台机器上的多个任务计划程序
- 即使其中一个任务计划程序或执行程序失败,它也不会是单点故障。一些任务会延迟,但会被拾起,然后运行。
这可能无法解决所有情况,但会是一个很好的起点。