在上一期中,我们讨论了使用消息队列的好处。然后,我们回顾了消息队列产品的历史。现在看来,当我们需要在项目中使用消息队列时,Kafka 是首选产品。但是,当我们考虑特定要求时,它并不总是最佳选择。
数据库支持的队列
让我们再次使用我们的星巴克示例。最重要的两个要求是:
-
异步处理,因此收银员无需等待即可接受下一个订单。
-
坚持不懈,以便在出现问题时不会错过客户的订单。
消息订购在这里并不重要,因为咖啡机经常制作成批的相同饮料。可扩展性也不那么重要,因为队列仅限于每个星巴克门店。
星巴克队列可以在数据库表中实现。下图显示了它是如何工作的:
当收银员接受订单时,将在数据库支持的队列中创建一个新订单。然后,收银员可以接受另一个订单,而咖啡机则分批接取新订单。订单完成后,咖啡机会在数据库中将其标记为完成。然后,顾客在柜台领取咖啡。
内务管理作业可以在每天结束时运行,以删除已完成的订单(即那些状态为"完成"的订单)。
对于星巴克的用例,一个简单的数据库队列就可以满足要求,而不需要 Kafka。具有 CRUD(创建-读取-更新-删除)操作的订单表工作正常。
Redis支持的队列
数据库支持的消息队列仍然需要开发工作来创建队列表并从中读取/写入。对于预算有限且已经使用 Redis 进行缓存的小型初创公司,Redis 还可以用作消息队列。
有 3 种方法可以将 Redis 用作消息队列:
1.Pub/Sub 发布/订阅
2.List 列表
3.Stream 流
下图显示了它们的工作原理。
Pub/Sub 很方便,但有一些交付限制。当生产者将数据发布到同一密钥时,消费者订阅密钥并接收数据。限制是数据最多传递一次。如果使用者关闭且未收到已发布的数据,则该数据将丢失。此外,数据不会保留在磁盘上。如果 Redis 出现故障,则所有 Pub/Sub 数据都将丢失。Pub/Sub 适用于可以接受某些数据丢失的指标监控。
Redis 中的 List 数据结构可以构造 FIFO(先进先出)队列。使用者使用 BLPOP 在阻塞模式下等待消息,因此应应用超时。等待同一列表的消费者形成一个消费者组,其中每条消息仅由一个消费者使用。作为 Redis 数据结构,List 可以持久化到磁盘上。
Stream 解决了上述两种方法的限制。使用者选择从何处读取消息 - "$"表示新消息,"id"表示特定消息 ID,"0-0"表示从头开始读取。
总之,数据库支持和 Redis 支持的消息队列易于维护。如果它们不能满足我们的需求,专用的消息队列产品会更好。接下来我们将比较两个流行的选项。
对于需要可靠、可扩展和可维护系统的大型公司,请在以下方面评估消息队列产品:
-
功能性
-
性能
-
可扩展性
-
生态系统
下图比较了两种典型的消息队列产品:RabbitMQ 和 Kafka。
它们是如何工作的
RabbitMQ 的工作方式类似于消息传递中间件 - 它将消息推送给消费者,然后在确认时删除它们。这避免了 RabbitMQ 认为有问题的消息堆积。
Kafka 最初是为大规模日志处理而构建的。它会将消息保留到过期,并允许使用者按照自己的节奏拉取消息。
语言和 API
RabbitMQ 是用 Erlang 编写的,这使得修改核心代码具有挑战性。但是,它提供了非常丰富的客户端 API 和库支持。
Kafka 使用 Scala 和 Java,但也具有适用于 Python、Ruby 和 Node.js 等流行语言的客户端库和 API。
性能和可扩展性
RabbitMQ 每秒处理数万条消息。即使在更好的硬件上,吞吐量也不会高得多。
Kafka 每秒可以处理数百万条消息,具有很高的可扩展性。
生态系统
默认情况下,许多现代大数据和流式处理应用程序都集成了 Kafka。这使得它非常适合这些用例。
Message Queue使用案例
现在我们已经介绍了不同消息队列的功能,让我们看一些如何选择正确产品的示例。
日志处理和分析
对于具有购物车、订单和付款等服务的电子商务网站,我们需要分析日志以调查客户订单。
下图显示了使用"ELK"堆栈的典型体系结构:
-
ElasticSearch - 为全文搜索的日志编制索引
-
LogStash - 日志收集代理
-
Kibana - 用于搜索和可视化日志的 UI
-
Kafka - 分布式消息队列