如何平衡多个消息队列

时间:2019-06-19 22:52:58

标签: algorithm message-queue

我的任务可能长时间运行(几小时)。该任务由从消息队列(在我的情况下为AWS SQS)读取的多个工作程序(在我的情况下为AWS ECS实例)执行。我有多个用户将消息添加到队列中。问题是,如果Bob将5000条消息添加到队列中,足以使工作人员忙3天,那么Alice就会出现并要处理5个任务,Alice将需要等待3天才能开始任何Alice的任务。 / p>

我想在爱丽丝提交任务后立即以相同的速度向爱丽丝和鲍勃传达信息。

我通过在每个上下文中为每个用户(甚至用户提交的每个批次)创建多个队列(子队列),并在消费者请求下一条消息时在所有子队列之间交替来解决了这个问题。

至少在我的世界中,这似乎是一个普遍的问题,我想知道是否有人知道解决该问题的既定方法。

我看不到ActiveMQ的任何解决方案。我对Kafka有所了解,因为它具有在一个主题中循环分区的能力,并且可能起作用。现在,我正在使用Redis实现某些功能。

1 个答案:

答案 0 :(得分:0)

我建议使用Cadence Workflow而不是队列,因为它支持长期运行的操作和状态管理。

在您的情况下,我将为每个用户创建一个工作流实例。每个新任务将通过信号API发送到用户工作流程。然后,工作流实例会将收到的任务排队,并一一执行。

这是实现的概述:

public interface SerializedExecutionWorkflow {

    @WorkflowMethod
    void execute();

    @SignalMethod
    void addTask(Task t);
}

public interface TaskProcessorActivity {
    @ActivityMethod
    void process(Task poll);
}

public class SerializedExecutionWorkflowImpl implements SerializedExecutionWorkflow {

    private final Queue<Task> taskQueue = new ArrayDeque<>();
    private final TaskProcesorActivity processor = Workflow.newActivityStub(TaskProcesorActivity.class);

    @Override
    public void execute() {
        while(!taskQueue.isEmpty()) {
            processor.process(taskQueue.poll());
        }
    }

    @Override
    public void addTask(Task t) {
        taskQueue.add(t);
    }
}

然后通过信号方法将任务排队到工作流中的代码:

private void addTask(WorkflowClient cadenceClient, Task task) {
    // Set workflowId to userId
    WorkflowOptions options = new WorkflowOptions.Builder().setWorkflowId(task.getUserId()).build();
    // Use workflow interface stub to start/signal workflow instance
    SerializedExecutionWorkflow workflow = cadenceClient.newWorkflowStub(SerializedExecutionWorkflow.class, options);
    BatchRequest request = cadenceClient.newSignalWithStartRequest();
    request.add(workflow::execute);
    request.add(workflow::addTask, task);
    cadenceClient.signalWithStart(request);
}

与使用队列进行任务处理相比,Cadence具有许多其他优点。

  • 构建具有无限到期间隔的指数重试
  • 故障处理。例如,它允许执行一个任务,如果在配置的时间间隔内两次更新均未成功,则该任务会通知另一服务。
  • 支持长时间运行的心跳操作
  • 能够实现复杂的任务依赖性。例如,在无法恢复的故障(SAGA)的情况下实现呼叫链或补偿逻辑的链接
  • 完全了解更新的当前状态。例如,当使用队列时,您就会知道队列中是否有某些消息,并且需要其他数据库来跟踪总体进度。使用Cadence可以记录每个事件。
  • 能够取消正在进行的更新。

请参见介绍Cadence编程模型的the presentation