Kafka、RabbitMQ、RocketMQ比较

81 阅读5分钟

一、如何保证Producer发送的数据可靠性(消息的生产者将消息发送出去以后,消息到底有没有到达服务器)

kafka发送消息有三种模式

只发送、同步、异步

只发送:只负责往kafka发送消息,不关心消息是否正确到达,消息会丢失

异步:send方法本身是异步,一般在send方法里指定一个Callback的回调函数。

同步: send方法返回的Future对象可以使调用方得到返回的结果

Future future = producer.send(record);

链式调用get方法来阻塞等待kafka的响应

生产者参数acks

acks="1",默认值为1,生产者发送消息,只有leader副本成功写入消息

acks="0",默认值为1,生产者发送消息,不需要等待任何服务器响应

acks="-1",默认值为1,生产者发送消息,需要ISR中所有副本都成功写入消息

Rabbit通过事物机制和确认机制

事物机制

确认机制

rocketmq发送消息分为三种实现方式:可靠同步发送、可靠异步发送、单向发送。

二、如何实现消息的投递模式点对点和发布订阅

kafka:

点对点:所有消费者属于同一消费组,消息会被均衡投递给每一个消费者。

发布订阅:消费者属于不同消费组,消息会被广播给所有的得消费者

通过消费组的概念,组内竞争关系,一条消息只能被同一个消费组内一个消费者消费

不同的消费者之间互不影响,一条消息可以同时由多个消费组消费

RabbitMQ:

这个和队列模式有关

1、简单模式

2、工作队列

3、发布订阅 Publish/Subscribe

4、路由 Routing

5、主题 Topics

6、远程过程调用RPC

点对点:只发送到一个队列,一条消息只能被一个消费者获取。

工作队列

c1和c2是竞争关系,c1消费了,c2就不能消费了

发布订阅:同一个消息发送到不同的队列上

发布订阅

c1和c2之间互不影响

不管是哪种对了模式,关键是看一条消息是只能路由到一个队列,还是可以路由到多个队列

生产

->消费->生产

7、发布者确认

Publisher Confirms

对可靠性要求比较高:扣款、退款

RocketMQ:

广播式消费,这种模式下,一个消息会被通知到每一个消费者

集群式消费,这种模式下,一个消息最多只会被投递到一个消费者上进行消费

三、如何保证消息顺序消费

kafka:

构造kafka的消息对象PoducerRecord该对象的topic(主题)和value(消息)必填项还有一个key非必填项,public PoducerRecord(String topic, K key, V value),key是用来分区用的,如果不指定key的话默认采用轮训的方式将消息发送主题内各个分区,如果key不为null分区器会对key进行hash根据hash值来进行分区。那么只要保证key值一样,数据一定会被分发到同一个partition 中去,而且这个 partition 中的数据一定是有顺序的

RocketMQ:

RockeMQ采用了这种实现方案:对于相同订单号的消息,通过一定的策略,将其放置在一个 queue队列中,然后消费者再采用一定的策略(一个线程独立处理一个queue,保证处理消息的顺序性),能够保证消费的顺序性

kafka:主题+分区+位移确定一个消息位置

Rabbit;一个Producer,一个Queue,多个Consumer的情况下是无法保证顺

RocketMQ:主题+队列+位移确定一个消息位置

其实队列本身是有顺序的,但是生产环境服务实例一般都是集群,当消费者是多个实例时,队列中的消息会分发到所有实例进行消费(同一个消息只能发给一个消费者实例),这样就不能保证消息顺序的消费,因为你不能确保哪台机器执行消费端业务代码的速度快

所以对于需要保证顺序消费的业务,我们可以只部署一个消费者实例,然后设置 RabbitMQ 每次只推送一个消息,再开启手动 ack 即可,配置如下

四、如何防止重复消费

幂等性

消息丢失问题

消费者弄丢了消息

a、丢失的原因:如果RabbitMQ成功的把消息发送给了消费者,那么RabbitMQ的ack机制会自动的返回成功,表明发送消息成功,下次就不会发送这个消息。但如果就在此时,消费者还没处理完该消息,然后宕机了,那么这个消息就丢失了。

b、解决的办法:简单来说,就是必须关闭 RabbitMQ 的自动 ack,可以通过一个 api 来调用就行,然后每次在自己代码里确保处理完的时候,再在程序里 ack 一把。这样的话,如果你还没处理完,不就没有 ack了?那 RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把这个消费分配给别的 consumer 去处理,消息是不会丢的。