类型 | 消息是否会重复 | 消息是否会丢失 | 优势 | 劣势 | 使用场景 |
最多一次 | 否 | 是 | 生产端发送消息后不用等待和处理服务端响应,消息发送速度会很快 | 网络或服务端有问题会造成消息的丢失 | 消息系统吞吐量大且对消息的丢失不敏感。例如,日志收集、用户行为收集等场景 |
最少一次 | 是 | 否 | 生产端发送消息后需要等待和处理服务端响应,如果失败会重试 | 吞吐量较低,有重复发送的消息 | 消息系统吞吐量一般,但是绝不能丢消息,对于重复消息不敏感 |
有且仅有一次 | 否 | 否 | 消息不重复,消息不丢失,消息可靠性很好 | 吞吐量较低 | 对消息的可靠性要求较高,同时可以忍受较小的吞吐量 |
如何判断一个副本属于ISR还是属于OSR?
maxLagMs 参数 默认为十秒,如果Follower和Leader的数据时间差大于10s,则该副本属于OSR,否则该副本属于ISR。
如何做到消息不丢失
生产端:
- 使用带回调函数方法的API,根据回调函数得知消息是否发送成功
Future<RecordMetadata> send(ProducerRecord<K, V> var1, Callback var2);
- 设置参数 acks=-1, 当ISR中的所有副本全部收到消息时,生产者才会认为消息生产成功了
- 设置参数 retries=3, 设置重试次数
- 设置参数 =300, 消息生产超时或失败或重试的间隔时间(单位毫秒)
服务端:
- 设置 replication.factor > 1, 分区副本个数
- 设置 min.insync.replicas > 1, ISR最少副本数
- 设置 unclean.leader.election.enable = false, 是否把非ISR集合中的副本选举为leader副本
- 设置是否自动提交 enable.auto.commit = false, 是否自动提交。如果设置为true,消息偏移量是由消费端自动提交,由异步线程完成,业务线程无法控制。
如何消息不重复
生产端不重复生产消息:
- 每个生产端生成一个唯一的ID,在每条消息中生成一个sequence num进行消息去重(只对一个生产端内生产的消息有效)。
- 如果是两个生产端的话可以设置一个全局ID,全局ID可以存放在远程缓存或者数据库里,判断是否已经发送过了。
消费端不重复消费消息:
- 设置 enable.auto.commit = false, 然后设置先提交偏移量再处理消息,这样不会重复消费消息,但是有可能丢失消息。