用Apache Kafka替换RabbitMQ来消除任务处理中断 - DoorDash


扩展后端基础架构以处理超增长是在DoorDash工作的众多令人兴奋的挑战之一。在2019年中期,我们面临着重大的扩展挑战,涉及CeleryRabbitMQ的频繁停机,这两种技术为系统处理异步工作提供了支持,从而实现了平台的关键功能,包括订单结账和Dasher分配。 
我们使用基于Apache Kafka的简单异步任务处理系统迅速解决了该问题,该系统停止了停机,同时我们继续迭代一个可靠的解决方案。
 
RabbitMQ和Celery是我们基础架构的关键任务,可以在DoorDash上支持900多种不同的异步任务,包括订单结帐,商户订单传输和Dasher位置处理。DoorDash面临的问题是RabbitMQ由于负载过大而经常关闭。如果任务处理失败,DoorDash实际上会失败并且订单无法完成,从而给我们的商人和Dashers造成收入损失,并给我们的消费者带来糟糕的体验。我们在以下方面面临问题:

  • 可用性:由于需求导致的中断降低了可用性。 RabbitMQ由于负载,过多的连接中断和其他原因而崩溃。订单将被暂停,我们必须重新启动系统,有时甚至需要启动一个全新的代理并手动进行故障转移,以便从中断中恢复。
  • 可扩展性:RabbitMQ无法随着我们业务的增长而扩展。 
  • 可观察性:RabbitMQ提供的指标有限,而Celery工人不透明。 
  • 运营效率:重新启动这些组件是一个耗时的手动过程。 

针对上述问题,我们考虑了以下解决方案:
  • 将Celery经纪人从RabbitMQ更改为Redis或Kafka。这将使我们能够继续使用Celery,并使用另一个可能更可靠的备份数据存储。

  • 在我们的Django应用程序中添加多经纪人支持,以便消费者可以根据我们想要的逻辑,发布给N个不同的经纪人。任务处理将在多个代理之间进行分片,因此每个代理将承受一部分初始负载。

  • 升级到更新版本的Celery和RabbitMQ。希望新版本的Celery和RabbitMQ能够解决可靠性问题,因为我们已经从Django整体中并行提取组件,这为我们节省了时间。

  • 迁移到由Kafka支持的自定义解决方案。与我们列出的其他选项相比,此解决方案需要付出更多的努力,但也有更大的潜力来解决传统解决方案遇到的每个问题。

切换到Kafka代表了我们堆栈中的一项重大技术更改,但非常需要此更改。由于传统的RabbitMQ解决方案的不稳定,我们每周都在亏损,因此我们没有时间浪费时间。我们的首要任务是创造一个最低限度的可行产品(MVP),为我们带来临时稳定性,并为我们迭代和准备更广泛采用的更全面解决方案所需的空间。

总而言之,我们达到了扩展RabbitMQ的能力的上限,因此不得不寻找替代方案。我们采用的替代方法是基于Kafka的自定义解决方案。尽管使用Kafka有一些弊端,但如上所述,我们发现了许多解决方法。
当关键工作流程严重依赖异步任务处理时,确保可伸缩性至关重要。遇到类似问题时,请随时从我们的策略中汲取灵感,该策略使我们以20%的努力获得了80%的结果。一般而言,此策略是一种战术方法,可以快速缓解可靠性问题并购买迫切需要的时间以提供更强大且更具战略性的解决方案。