kafka学习笔记(五) --- 无消息丢失配置怎么做?

kafka在什么情况下才能保证消息不丢失?

首先一句话概括为,kafka只对已提交消息做有限度的持久化保证。

已提交消息:当kafka的若干个broker接收到消息并成功写入日志文件后,他们会告诉生产者程序已成功提交。为什么是若干个broker,就取决于你对“已提交”的定义。可以选择只要有一个broker成功保存消息就算已提交,也可以是所有broker都成功保存该消息就算已提交。

有限度的持久化保证:kafka不丢消息是有前提条件的。假如你的消息保存在N个kafka broker上,那么这个前提条件就是这N个broker中至少有1个存活。

“消息丢失”案例:加引号说明很多时候消息丢失并不是kafka本身造成 的消息丢失。

生产者程序丢失数据:在程序中调用了不带回调参数的send API,这种方式发送出去的消息,不管成功与否,对于发送端都是已成功发送的消息。这种情况下消息丢失的原因很多的,例如网络抖动,导致消息就没有发送到broker端;或者消息本身不合格导致broker端拒收(比如消息太大,超过broker承受能力)。至此,这些个情况,kafka都不认为消息已提交,也就没有消息丢失一说。这种情况的解决方法,producer端永远要调用带有回调通知的send API,即不要使用producer.send(msg),而要使用producer.send(msg, callback)。当然,如果在极端情况下,所有broker宕机,无论producer怎么重试都会失败,这种情况,kafka也依然不认为消息已提交,故不做持久化保证。

消费程序丢失数据:consumer端数据丢失,一般主要体现体现在要消费的消息不见了,这里consumer端有个位移的概念表示的是consumer当前消费到topic分区的位置。一种情况的消息丢失是因为消费顺序和更新位移顺序颠倒,所有要保证先消费再更新位移,但是这种情况可能会导致重复消费消息,这种情况后面在讨论。

另外一种消息丢失场景是:consumer端从kafka获取消息后开启多线程异步处理消息,而consumer端自动向前更新位移。加入其中的线程运行失败了。它负责的消息没有被处理,但位移已经更新了,那么这条消息对于consumer而言就丢失。这种情况就不要开启自动提交位移。但是,单个consumer程序使用多线程处理消息,避免消息丢失很容易,但是极易出现消息消费多次的情况。

还有一种消息丢失的场景,增加主题分区。当增加主题分区后,在某段不凑巧的时间间隔后,producer先于consumer感知到增加的分区,而consumer设置成“从最新位移处”开始读消息,那么在consumer感知到新增分区之前,producer发送的消息就全部“丢失”。

下面分享一个无消息丢失的配置:

1. 不要使用producer.send(msg),而要使用producer.send(msg, callback)。

2. 设置acks = all。acks是producer的参数,代表对已提交消息的定义。如果设置成all,则表明所有副本broker都要接收到消息,才算已提交。

3. 设置retries为一个较大值,也是producer端参数,对应produce端的自动重试。当网络出现抖动,消息发送可能会失败,此时配置retries>0的producer能够自动重试消息发送,避免消息丢失。

4. 设置unclean.leader.election.enable = false,broker端参数,它控制的是那些broker有资格竞选分区leader。如果一个broker落后原先leader太多,那么它一旦成为新leader,必然造成消息丢失。一般情况设置为false。

5. 设置replicator.factor >= 3,broker端参数。这里表述的是最好将消息多保存几份,目前防止消息丢失的主要机制就是冗余。

6. 设置min.insync.replicas > 1,broker端参数。控制的是消息至少要被写入到多少个副本才算已提交。

7. 确保replicator.factor > min.insync.replicas。如果两者相等,那么只要有一个副本挂机,整个分区都无法正常工作。不仅要改善消息持久性,防止丢失,还要在不降低可用性上完成。推荐设置成replicator.factor = min.insync.replicas + 1.

8. 确保消息消费完成再提交,设置enable.auto.commit = false,手动提交位移。

 

标注:这个系列文章是本人在极客时间专栏---kafka核心技术与实战中的学习笔记

    https://time.geekbang.org/column/article/101171

Kafka 中,Producer 是用来发送消息Kafka 集群的组件。在本篇文章中,我们将介绍如何使用 Kafka 的 Java 客户端 API 来编写一个简单的 Producer。 1. 引入 Kafka 依赖 首先,需要在 Maven 或 Gradle 构建中引入 Kafka 客户端依赖: ```xml <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.8.0</version> </dependency> ``` 2. 创建 Producer 实例 接下来,在 Java 代码中创建一个 KafkaProducer 实例: ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ``` 其中,bootstrap.servers 是必须设置的属性,用于指定 Kafka 集群中至少一个 Broker 的地址。key.serializer 和 value.serializer 用于指定消息的键和值的序列化器。这里我们使用的是 StringSerializer,也可以使用其他序列化器实现自定义序列化逻辑。 3. 发送消息 一旦创建了 KafkaProducer 实例,就可以使用它来发送消息到指定的 Kafka 主题: ```java ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); ``` 这里的 ProducerRecord 构造函数中,第一个参数是要发送消息的主题名称,第二个参数是消息的键,第三个参数是消息的值。send() 方法用于将 ProducerRecord 发送到 Kafka 集群。 4. 关闭 Producer 在使用完 Producer 后,需要关闭它以释放资源: ```java producer.close(); ``` 完整代码示例: ```java import org.apache.kafka.clients.producer.*; import java.util.Properties; public class KafkaProducerExample { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); producer.close(); } } ``` 这就是一个简单的 Kafka Producer 的使用示例。在实际应用中,还可以根据需要设置其他属性,例如消息的分区策略、消息的压缩方式等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值