性能(单台) | 语言 | 多语言支持客户端 | 优缺点 | |
RocketMQ | 十万级 | java | java |
|
Kafka | 百万级 | 服务端scala,客户端java | 主流语言均支持 |
|
Kafka 采用的是发布 - 订阅模型。
RocketMQ 的消息模型和 Kafka 基本是完全一样的。唯一的区别是 Kafka 中没有队列这个概念,与之对应的是 Partition(分区)。
Kafka 为分区(Partition)引入了多副本(Replica)机制。
分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。生产者和消费者只与leader副本做交互。
Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢?
Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data(数据) 4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同一个 key 的消息可以保证只发送到同一个 partition,这个我们可以采用表/对象的 id 来作为 key 。
生产者消息是如何丢失的?
生产者调用send方法发送消息之后【异步操作】,消息可能因为网络原因没有发出去
为了确定消息发送是否成功,需要判断消息发送的结果。
一般采用如下做法,采用回调函数获取消息发送的状态,并且为生产者设置重试次数和重试间隔,一般为3
@Slf4j
public class KafkaDemo {
@Autowired
KafkaTemplate kafkaTemplate;
public void sendMessage(String topic,Object o) throws ExecutionException, InterruptedException {
ListenableFuture> future= kafkaTemplate.send(topic,o);
future.addCallback(new ListenableFutureCallback>() {
@Override
public void onFailure(Throwable ex) {
log.error("生产者发送消息:{} 失败,原因:{}", o.toString(), ex.getMessage());
}
@Override
public void onSuccess(SendResult result) {
log.info("生产者成功发送消息到topic:{} partition:{}的消息",result.getProducerRecord().value().toString());
}
});
}
}
消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。偏移量(offset)表示 Consumer 当前消费到的 Partition(分区)的所在的位置。Kafka 通过偏移量(offset)可以保证消息在分区内的顺序性。
消费者消息是如何丢失的?
当消费者拉取到了分区的某个消息之后,消费者会自动提交了 offset。自动提交的话会有一个问题,试想一下,当消费者刚拿到这个消息准备进行真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被自动提交了。
解决方案:
关闭自动提交offset,每次在真正消费完消息之后再手动提交offset。
但是这样也会带来重复消费的情况,比如,消费了一半还没提交offset突然挂掉,那么这个消息理论上会被消费两次,这种情况怎么办?【保证幂等性】
kafka是如何丢失消息的?【多副本机制】
假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失。
1)acks=all 所有副本全部收到消息时,生产者才会接收到来自服务器的响应
2) replication.factor >= 3 每个分区至少有3个副本
3) min.insync.replicas > 1 消息至少被写入2个副本,才算是被成功发送
4)unclean.leader.election.enable = false 当leader副本发生故障时不会从followers副本中和leader副本同步程度达不到要求的副本中选出leader,降低了消息丢失的可能性。
kafka出现重复消费的原因?
1)消费者已经消费了的消息没有正确提交offset(根本原因)
2)kafka侧因为服务端业务处理时间过长或者网络连接等原因,让kafka认为服务假死,触发了分区rebalance
解决方案
kafka消费者默认配置下最多重试10次,每次时间间隔0,即立即重试。如果在 10 次重试后仍然无法成功消费消息,则不再进行重试,消息将被视为消费失败。
生产者组中的生产者会向主题发送消息,而 主题中存在多个队列,生产者每次生产消息之后是指定主题中的某个队列发送消息的。
RocketMQ
通过使用在一个 Topic
中配置多个队列并且每个队列维护每个消费者组的消费位置 实现了 主题模式/发布订阅模式
RocketMQ在topic上是无序的,只有在队列层面才能保证是有序的。
【把同一主题消息放入相同的队列】
顺序需要由3个阶段去保障:
消费者端做幂等
产生原因:生产者生产消息过快or消费者消费消息太慢
生产者限流降级,增加多个消费者实例。