美文网首页
rabbitmq vs kafka

rabbitmq vs kafka

作者: cloudFans | 来源:发表于2022-09-28 09:34 被阅读0次

消息队列中间件,可以解耦 生产者和消费者,两端独立伸缩

Apache Kafka 不是消息中间件的一种实现。相反,它只是一种分布式流式系统。

不同于基于队列和交换器的 RabbitMQ,Kafka 的存储层是使用分区事务日志来实现的。
Kafka 也提供流式 API 用于实时的流处理以及连接器 API 用来更容易的和各种数据源集成。

Kafka 更优,因为它可以保证按顺序处理消息。RabbitMQ 在这块就相对比较弱。

1、主题
Kafka 没有实现队列这种东西。相应的,Kafka 按照类别存储记录集,并且把这种类别称为主题。
Kafka 为每个主题维护一个消息分区日志。每个分区都是由有序的不可变的记录序列组成,并且消息都是连续的被追加在尾部。
当消息到达时,Kafka 就会把他们追加到分区尾部。默认情况下,Kafka 使用轮询分区器(partitioner)把消息一致的分配到多个分区上。
Kafka 可以改变创建消息逻辑流的行为。例如,在一个多租户的应用中,我们可以根据每个消息中的租户 ID 创建消息流。IoT 场景中,我们可以在常数级别下根据生产者的身份信息(identity)将其映射到一个具体的分区上。确保来自相同逻辑流上的消息映射到相同分区上,这就保证了消息能够按照顺序提供给消费者。

2、消费者
消费者通过维护分区的偏移(或者说索引)来顺序的读出消息,然后消费消息。
值得特别注意的是,Kafka 是按照预先配置好的时间保留分区中的消息,而不是根据消费者是否消费了这些消息。这种保留机制可以让消费者自由的重读之前的消息。另外,开发者也可以利用 Kafka 的存储层来实现诸如事件溯源和日志审计功能。
尽管有时候 RabbitMQ 和 Kafka 可以当做等价来看,但是他们的实现是非常不同的。所以我们不能把他们当做同种类的工具来看待;一个是消息中间件,另一个是分布式流式系统。

小结: RabbitMQ 和 Kafka 的显著差异
RabbitMQ 是一个消息代理,但是 Apache Kafka 是一个分布式流式系统。好像从语义上就可以看出差异,但是它们内部的一些特性会影响到我们是否能够很好的设计各种用例。

例如,Kafka 最适用于数据的流式处理,但是 RabbitMQ 对流式中的消息就很难保持它们的顺序。
另一方面,RabbitMQ 内置重试逻辑和死信(dead-letter)交换器,但是 Kafka 只是把这些实现逻辑交给用户来处理。

1、保证消息顺序处理

对于发送到队列或者交换器上的消息,RabbitMQ 不保证它们的顺序。尽管消费者按照顺序处理生产者发来的消息看上去很符合逻辑,但是这有很大误导性。
RabbitMQ 文档中有关于消息顺序保证的说明:
“发布到一个通道(channel)上的消息,用一个交换器和一个队列以及一个出口通道来传递,那么最终会按照它们发送的顺序接收到。”
——RabbitMQ 代理语义(Broker Semantics)
换话句话说,只要我们是单个消费者,那么接收到的消息就是有序的。然而,一旦有多个消费者从同一个队列中读取消息,那么消息的处理顺序就没法保证了。
由于消费者读取消息之后可能会把消息放回(或者重传)到队列中(例如,处理失败的情况),这样就会导致消息的顺序无法保证。

由于资源有可能处理失败,如果放回了,下次再拿出来消息的顺序可能就乱了,就会导致资源处理的先后顺序出现错误,比如游戏事件,先进攻,再撤退,可能导致最后的执行顺序和原来的消息顺序是反的,导致全军覆没。

当然,我们可以通过限制消费者的并发数等于 1 来保证 RabbitMQ 中的消息有序性。更准确点说,限制单个消费者中的线程数为 1,因为任何的并行消息处理都会导致无序问题。

不过,随着系统规模增长,单线程消费者模式会严重影响消息处理能力。所以,我们不要轻易的选择这种方案。

对于 Kafka 来说,它在消息处理方面提供了可靠的顺序保证。Kafka 能够保证发送到相同主题分区的所有消息都能够按照顺序处理。

小结: Kafka 可以保证按顺序处理消息。RabbitMQ 在这块就相对比较弱。

  1. 消息路由
    RabbitMQ 可以基于定义的订阅者 “路由规则” 路由消息给一个消息交换器上的订阅者。
    一个主题交换器可以通过一个叫做 routing_key 的特定头来路由消息。

另一方面,Kafka 在处理消息之前是不允许消费者过滤一个主题中的消息。一个订阅的消费者在没有异常情况下会接受一个分区中的所有消息。
作为一个开发者,你可能使用 Kafka 流式作业(job),它会从主题中读取消息,然后过滤,最后再把过滤的消息推送到另一个消费者可以订阅的主题。但是,这需要更多的工作量和维护,并且还涉及到更多的移动操作。

该点其实是服务端过滤和客户端过滤的区别,服务端过滤可以节省链路开销,
rabbitmq可以基于“路由规则”来更灵活的过滤,但是kafka只能全盘接收再过滤。

小结: 在路由规则上,rabbitmq更胜一筹。

  1. 消息时序
    在测定发送到一个队列的消息时间方面,RabbitMQ提供了多种能力:
    3.1 消息存活时间
    发送到 RabbitMQ 的每条消息都可以关联一个 TTL 属性。发布者可以直接设置 TTL 或者根据队列的策略来设置。
    系统可以根据设置的 TTL 来限制消息的有效期。如果消费者在预期时间内没有处理该消息,那么这条消息会自动的从队列上被移除(并且会被移到死信交换器上,同时在这之后的消息都会这样处理)。
    TTL 对于那些有时效性的命令特别有用,因为一段时间内没有处理的话,这些命令就没有什么意义了。

3.2 延迟/预定消息送达的时间

RabbitMQ 可以通过插件的方式来支持延迟或者预定的消息。

当这个插件在消息交换器上启用的时候,生产者可以发送消息到 RabbitMQ 上,然后这个生产者可以延迟 RabbitMQ 路由这个消息到消费者队列的时间。

这个功能允许开发者调度将来(future)的命令,也就是在那之前不应该被处理的命令。例如,当生产者遇到限流规则时,我们可能会把这些特定的命令延迟到之后的一个时间执行。

小结: 由于kafka是一种追加模式的事务日志。 所以他不能处理消息时间。 所有rabbitmq在限流的时候可以更灵活。

3.3 消息留存

一旦消费,rabbitmq就会删除消息,而kafka 会给每一个消息配置超时时间。
我感觉这个应该是业务需求前置, 你需要这个功能就只能上kafka,上了rabbitmq可能要自己去用另外一种机制来搞,比如审计消息。

  1. 消息重试
    rabbitmq 本身支持消息重试:
    在 RabbitMQ 中我们需要记住最重要的事情是当一个消费者正在处理或者重试某个消息时(即使是在把它返回队列之前),其他消费者都可以并发的处理这个消息之后的其他消息。

当某个消费者在重试处理某条消息时,作为一个整体的消息处理逻辑不会被阻塞。所以,一个消费者可以同步地去重试处理一条消息,不管花费多长时间都不会影响整个系统的运行。

和 RabbitMQ 相反,Kafka 没有提供这种开箱即用的机制。在 Kafka 中,需要我们自己在应用层提供和实现消息重试机制。
另外,我们需要注意的是当一个消费者正在同步地处理一个特定的消息时,那么同在这个分区上的其他消息是没法被处理的。

由于消费者不能改变消息的顺序,所以我们不能够拒绝和重试一个特定的消息以及提交一个在这个消息之后的消息。你只要记住,分区仅仅是一个追加模式的日志。

小结: rabbitmq在消息重试的问题上,有提供可靠的机制,开箱即用。

  1. 伸缩
    从 Kafka 使用分区的架构上看,它在横向扩展上会优于 RabbitMQ,当然 RabbitMQ 在纵向扩展上会有更多的优势。
    Pivotal 记录了一个 Kafka 集群每秒处理一百万条消息的例子;但是,它是在一个有着 30 个节点集群上做的,并且这些消息负载被优化分散到多个队列和交换器上。
    在大规模消息处理场景,最好还是用kafka。
  1. 消费者处理逻辑的复杂度
    RabbitMQ 使用的是智能代理和傻瓜式消费者模式。消费者注册到消费者队列,然后 RabbitMQ 把传进来的消息推送给消费者。RabbitMQ 也有拉取(pull)API;不过,一般很少被使用。
    RabbitMQ 管理消息的分发以及队列上消息的移除(也可能转移到 DLX)。消费者不需要考虑这块。

根据设计,RabbitMQ 就是为了傻瓜式消费者而构建的。所以这轮 RabbitMQ 获胜。

如何选择:
优先选择 RabbitMQ 的条件:

高级灵活的路由规则;
消息时序控制(控制消息过期或者消息延迟);
高级的容错处理能力,在消费者更有可能处理消息不成功的情景中(瞬时或者持久);
更简单的消费者实现。

优先选择 Kafka 的条件:

严格的消息顺序;
延长消息留存时间,包括过去消息重放的可能;
传统解决方案无法满足的高伸缩能力。

大部分情况下这两个消息平台都可以满足我们的要求

参考: https://xie.infoq.cn/article/7577289323449da236cd0f127

相关文章

网友评论

      本文标题:rabbitmq vs kafka

      本文链接:https://www.haomeiwen.com/subject/igztartx.html