【问题标题】:ScheduledThreadPoolExecutor - single task/thread running often or multiple threads running less oftenScheduledThreadPoolExecutor - 经常运行的单个任务/线程或不经常运行的多个线程
【发布时间】:2013-07-23 16:50:39
【问题描述】:

我正在尝试设置每 x 分钟/秒/毫秒/任何时间运行一次的作业,并轮询 Amazon SQS 队列以获取要处理的消息。我的问题是最好的方法是什么。我是否应该创建一个具有 x 个线程的 ScheduledThreadPoolExecutor 并使用 scheduleAtFixedRate 方法安排一个任务并经常运行它(如 10 毫秒),以便在需要时使用多个线程,或者,正如我向同事提议的那样,创建一个ScheduledThreadPoolExecutor 具有 x 个线程,然后以稍微偏移的间隔创建多个计划任务,但运行频率较低。在我看来,这听起来像是 STPE 的用途。

我通常使用 Spring/Quartz 来处理这种类型的事情,但现在已经过时了。

那么你的想法是什么?

【问题讨论】:

    标签: java multithreading amazon-sqs threadpoolexecutor


    【解决方案1】:

    我建议您在 SQS 上使用 long polling,这会使您的 ReceiveMessage 调用行为更像是在 BlockingQueue 上对 take 的调用(这意味着您不需要使用计划任务来轮询来自队列 - 你只需要一个线程在无限循环中轮询,如果连接超时重试)

    【讨论】:

    • 唯一的问题是单线程无法跟上队列填满的速度。
    【解决方案2】:

    这取决于任务的频率。如果您只需要按时间间隔轮询并且间隔不是很小,那么ScheduledThreadPoolExecutorscheduleAtFixedRate 是一个不错的选择。

    否则我会推荐使用 netty 的HashedWheelTimer。在繁重的任务下,它提供了最佳性能。 Akka 和 play 使用它来调度。这是因为 STPE 对于每个添加任务都需要 O(log(n))HWT 需要 O(1)

    如果你必须使用STPE,我会推荐一个任务,否则会导致资源过剩。

    【讨论】:

      【解决方案3】:

      长轮询就像一个阻塞队列,最多只有20 seconds,之后调用返回。如果这是轮询周期之间所需的最大延迟,那么长轮询就足够了。除此之外,您还需要一个 scheduleExector。

      线程数实际上取决于您处理接收到的消息的速度。如果您可以非常快速地处理消息,则只需要一个线程。我有如下设置

      1. SingleThreadScheduledExecutorscheduleWithFixedDelay 在上一次完成后 5 分钟执行
      2. 在每次执行中,从 SQS 批量检索消息,直到没有更多消息要处理(记住每个批次最多接收 10 条消息)。
      3. 消息经过处理,然后从队列中删除。

      对于我的场景,单线程就足够了。如果积压工作在增加(例如,每条可能涉及等待的消息都需要进行网络操作),您可能希望使用多个线程。如果一个处理节点变得资源受限,您总是可以启动另一个实例(也许是 EC2)以增加更多容量。

      【讨论】:

      • 所以您不建议在添加更多实例之前先在单个应用中进行扩展?似乎在应用程序中使用单个线程并添加更多实例并不是很好地使用 ec2 实例。
      • 那肯定是对的,我的回答并不建议在利用现有容量之前添加 ec2 实例。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-31
      • 1970-01-01
      • 2020-12-03
      • 2016-06-14
      • 2013-08-13
      相关资源
      最近更新 更多