互联网科技程序猿阵线联盟-汇总各类技术干货

聊聊MQ——Kafka vs. RabbitMQ

2019-06-30  本文已影响1人  shysheng

在分布式系统中,MQ的身影随处可见,它常用于异步处理、系统解耦、流量削峰等场景。常用的中间件也很多,比如Kafka、RabbitMQ、RocketMQ、NSQ等等。介绍这些中间件的书籍和资料已汗牛充栋,因此本文不打算深入MQ的各种细节,仅从宏观层面的几个关键点来看下Kafka和RabbitMQ的设计思想:

push or pull

消费消息的推拉模式各有优缺点,具体到Kafka,消费者采用pull模式消费消息。Kafka官网对此也有专门介绍push vs. pull.

而RabbitMQ同时支持push和pull两种消息消费方式,两种方式通过不同的api来进行区分。

消息投递模式

常用的消息投递模式有两种:

Kafka同时支持这两种消息投递模式,当所有消费者属于同一个消费者组时,每条消息只会被一个消费者消费,这就相当于是P2P模式;当所有消费者属于不同组时,每条消息会被广播给所有消费者,此时就相当于是Pub/Sub模式。

RabbitMQ通过一定的规则将消息经过交换器路由后存储在队列中,根据交换器类型的不同,同一条消息可以被路由给不同的队列,消费者最终消费的是队列中存储的消息。

从交换器层面上来说,RabbitMQ可以支持P2P模式和Pub/Sub模式,但从队列层面,RabbitMQ只支持P2P模式。

消息投递语义

消息中间件的消息投递语义常见的有三个层级:

Kafka生产端支持最少一次投递语义。

由于多副本机制的存在,只要消息写入了broker就不会丢失,如果传输过程发生异常,生产者可以进行重试以确保消息正确提交。

Kafka消费端则同时支持最多一次和最少一次。

如果消费者先处理消息后提交位移,那么可能导致重复消费,也就是最少一次;如果小提交位移后处理消息,则可能导致消息丢失,也就是最多一次。

另外,通过引入幂等和事务这两个特性,Kafka还在生产端和消费端同时实现了恰好一次的投递语义。

Kafka官网对此也有专门介绍:Kafka message delivery semantics

RabbitMQ目前只支持最多一次和最少一次的投递语义。为了支持最少一次的语义,RabbitMQ的生产端需要开启事务机制或者生产者确认机制,确保消息可以被传输到RabbitMQ中,同时消息和队列都需要进行持久化处理。

消息存储

消息存储无非就是内存还是磁盘,而Kafka选择了直接将消息存储到磁盘中。这似乎与我们印象中的Kafka性能很高而磁盘速度极慢的事实相矛盾。对此,Kafka官网也进行了深入分析并提供了数据支撑:Kafka persistence

总结下来大概是这么个意思:

RabbitMQ将消息保存在队列中,但其存储略为复杂,它分为持久化的消息和非持久化的消息,且两者都可以写入磁盘。随着系统负载的变化,保存在队列中的消息还可能会经过4种状态:

消息顺序性

Kafka通过消息在分区中的offset来保证消息的分区有序,但是因为offset并不跨越分区,因此无法保证主题有序。

另外在生产端异步发送场景下,Kafka也通过回调函数来保证分区有序。

但是,生产者重试场景,可能会破坏消息的分区有序性。因此,在需要严格保证消息有序性的场景下,可以将参数max.in.flight.requests.per.connection(该参数用来设置每个连接最多缓存的请求数)设置为1,此时即使生产者重试,也能保证消息的分区有序。

RabbitMQ则无法保证消息的顺序性。

消息可靠性

Kafka在保证消息可靠性上使用了以下几种手段:

RabbitMQ引入了镜像队列机制来保证消息可靠性。顾名思义,镜像队列可以将队列镜像到集群中的其它broker中去。针对每一个配置了镜像的队列,会包含一个master节点和若干个slave节点。

事务

Kafka中的事务可以将生产消息、消费消息、提交消费位移等操作当做原子操作来处理,也正是由于这个特性,Kafka实现了大多数消息中间件所不支持的恰好一次语义。

RabbitMQ支持事务机制,但只能保证消息被写入broker,无法保证消息被正确消费。因此,即使同样支持事务机制,但是RabbitMQ依然无法像Kafka一样提供恰好一次的投递语义。

更多技术文章,咱们公众号见,我在公众号里等你~

image.png
上一篇 下一篇

猜你喜欢

热点阅读