RabbitMQ和Kafka的显著差异
RabbitMQ 是一个消息代理,但是 Apache Kafka 是一个分布式流式系统。好像从语义上就可以看出差异,但是它们内部的一些特性会影响到我们是否能够很好的设计各种用例。
例如,Kafka 最适用于数据的流式处理,但是 RabbitMQ 对流式中的消息就很难保持它们的顺序。
另一方面,RabbitMQ内置重试逻辑和死信(dead-letter)交换器,但是 Kafka 只是把这些实现逻辑交给用户来处理。
这部分主要强调在不同系统之间它们的主要差异。
消息顺序
对于发送到队列或者交换器上的消息,RabbitMQ不保证它们的顺序。尽管消费者按照顺序处理生产者发来的消息看上去很符合逻辑,但是这有很大误导性。
只要我们是单个消费者,那么接收到的消息就是有序的。然而,一旦有多个消费者从同一个队列中读取消息,那么消息的处理顺序就没法保证了。
由于消费者读取消息之后可能会把消息放回(或者重传)到队列中(例如,处理失败的情况),这样就会导致消息的顺序无法保证。
对于Kafka来说,它在消息处理方面提供了可靠的分区顺序保证。Kafka能够保证发送到相同主题分区的所有消息都能够按照顺序处理。
消息时序(timing)
在测定发送到一个队列的消息时间方面,RabbitMQ提供了多种能力:
消息存活时间(TTL)
发送到RabbitMQ的每条消息都可以关联一个TTL属性。发布者可以直接设置TTL或者根据队列的策略来设置。
系统可以根据设置的TTL来限制消息的有效期。如果消费者在预期时间内没有处理该消息,那么这条消息会自动的从队列上被移除(并且会被移到死信交换器上,同时在这之后的消息都会这样处理)。
延迟/预定的消息
RabbitMQ可以通过插件的方式来支持延迟或者预定的消息。当这个插件在消息交换器上启用的时候,生产者可以发送消息到RabbitMQ上,然后这个生产者可以延迟RabbitMQ路由这个消息到消费者队列的时间。
这个功能允许开发者调度将来(future)的命令,也就是在那之前不应该被处理的命令。例如,当生产者遇到限流规则时,我们可能会把这些特定的命令延迟到之后的一个时间执行。
Kafka没有提供这些功能。它在消息到达的时候就把它们写入分区中,这样消费者就可以立即获取到消息去处理。
Kafka也没用为消息提供TTL的机制,不过我们可以在应用层实现。
不过,我们必须要记住的一点是Kafka分区是一种追加模式的事务日志。所以,它是不能处理消息时间(或者分区中的位置)。
消息留存(retention)
当消费者成功消费消息之后,RabbitMQ就会把对应的消息从存储中删除。这种行为没法修改。它几乎是所有消息代理设计的必备部分。
相反,Kafka会给每个主题配置超时时间,只要没有达到超时时间的消息都会保留下来。在消息留存方面,Kafka仅仅把它当做消息日志来看待,并不关心消费者的消费状态。
容错处理
RabbitMQ会给我们提供诸如交付重试和死信交换器(DLX)来处理消息处理故障。根据合适的配置信息自动地把路由失败的消息发送到DLX,并且在交换器上根据规则来进一步的处理,比如异常重试,重试计数以及发送到“人为干预”的队列
Kafka没有提供这种开箱即用的机制。在Kafka中,需要我们自己在应用层提供和实现消息重试机制。
伸缩
- Kafka通常被认为比RabbitMQ有更优越的性能。
- Kafka使用顺序磁盘I / O来提高性能。
- 从Kafka使用分区的架构上看,它在横向扩展上会优于RabbitMQ,当然RabbitMQ在纵向扩展(多消费者)上会有更多的优势
消费者复杂度
- RabbitMQ结构的设计,当负载增加的时候,一个队列上的消费者组可以有效的从仅仅一个消费者扩展到多个消费者,并且不需要对系统做任何的改变。
- Kafka使用的是傻瓜式代理和智能消费者模式。消费者组中的消费者需要协调他们之间的主题分区租约。要新建分区
选择
优先选择RabbitMQ的条件:
- 高级灵活的路由规则
- 消息时序控制(控制消息过期或者消息延迟)
- 高级的容错处理能力,在消费者更有可能处理消息不成功的情景中(瞬时或者持久)
- 更简单的消费者实现
优先选择Kafka的条件:
- 严格的消息顺序
- 延长消息留存时间,包括过去消息重放的可能
- 传统解决方案无法满足的高伸缩能力
对比表格
参考
http://www.easemob.org/news/4248