类型

消息是否会重复

消息是否会丢失

优势

劣势

使用场景

最多一次



生产端发送消息后不用等待和处理服务端响应,消息发送速度会很快

网络或服务端有问题会造成消息的丢失

消息系统吞吐量大且对消息的丢失不敏感。例如,日志收集、用户行为收集等场景

最少一次



生产端发送消息后需要等待和处理服务端响应,如果失败会重试

吞吐量较低,有重复发送的消息

消息系统吞吐量一般,但是绝不能丢消息,对于重复消息不敏感

有且仅有一次



消息不重复,消息不丢失,消息可靠性很好

吞吐量较低

对消息的可靠性要求较高,同时可以忍受较小的吞吐量

如何判断一个副本属于ISR还是属于OSR?
maxLagMs 参数 默认为十秒,如果Follower和Leader的数据时间差大于10s,则该副本属于OSR,否则该副本属于ISR。

如何做到消息不丢失
生产端:

  1. 使用带回调函数方法的API,根据回调函数得知消息是否发送成功
Future<RecordMetadata> send(ProducerRecord<K, V> var1, Callback var2);
  1. 设置参数 acks=-1, 当ISR中的所有副本全部收到消息时,生产者才会认为消息生产成功了
  2. 设置参数 retries=3, 设置重试次数
  3. 设置参数 =300, 消息生产超时或失败或重试的间隔时间(单位毫秒)

服务端:

  1. 设置 replication.factor > 1, 分区副本个数
  2. 设置 min.insync.replicas > 1, ISR最少副本数
  3. 设置 unclean.leader.election.enable = false, 是否把非ISR集合中的副本选举为leader副本
  4. 设置是否自动提交 enable.auto.commit = false, 是否自动提交。如果设置为true,消息偏移量是由消费端自动提交,由异步线程完成,业务线程无法控制。

如何消息不重复
生产端不重复生产消息:

  1. 每个生产端生成一个唯一的ID,在每条消息中生成一个sequence num进行消息去重(只对一个生产端内生产的消息有效)。
  2. 如果是两个生产端的话可以设置一个全局ID,全局ID可以存放在远程缓存或者数据库里,判断是否已经发送过了。

消费端不重复消费消息:

  1. 设置 enable.auto.commit = false, 然后设置先提交偏移量再处理消息,这样不会重复消费消息,但是有可能丢失消息。