kafka应答原理
-
0:生产者发送过来的数据,不需要等数据落盘应答
如下图,生产者发送了信息之后,不需要等待kafka回复,如果kafka上的节点挂了后,这个消息就丢失了。
-
1:生产者发送过来的数据,Leader收到数据后应答。
如下图,可能leader收到消息后,还没同步leader挂了,消息丢失了
-
-1(all):生产者发送过来的数据,Leader和ISR队列里面的所有节点收齐数据后应答。
如下图,需要等leader和ISR队列中的所有follower都收到后才应答。
什么是ISR队列?
ISR队列中有Leader保持同步的Follower+Leader集合,如果Follower长时间未向Leader发送通信请求或同步数据,则该Follower将被踢出ISR。该时间阈值由replica.lag.time.max.ms参数设定,默认30s。这样保证了不会因为某个follower没有收到而一直等待。
数据完全可靠条件 = ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
数据重复分析
- 生产者发送过来的数据,Leader和ISR队列里面的所有节点收齐数据后准备应答,此时leader挂了,follower节点们重新选举出一个leader,由于刚刚发的Hello消息没收到,所以生产者会重试,但是此时的follower其实已经收到了,这样就会导致重复。如下图:
代码中配置ack
// 设置 acks
properties.put(ProducerConfig.ACKS_CONFIG, "all");
// 重试次数 retries,默认是 int 最大值,2147483647
properties.put(ProducerConfig.RETRIES_CONFIG, 3);
数据去重
对于一些非常重要的信息,比如和钱相关的数据,要求数据既不能重复也不丢失。Kafka 0.11版本以后,引入了一项重大特性:幂等性和事务。
幂等性
幂等性就是指Producer不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复。
精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2) 。
重复数据的判断标准:
具有<PID, Partition, SeqNumber>相同主键的消息提交时,Broker只会持久化一条。其中PID是Kafka每次重启都会分配一个新的;Partition 表示分区号;Sequence Number是单调自增的。
所以幂等性只能保证的是在单分区单会话内不重复。
如何使用幂等性
开启参数 enable.idempotence,默认为 true,false 关闭。
kafka事务
幂等性只能解决单个会话内消息不重复,一旦生产者挂了后,无法保证消息不重复。kafka事务就是为了实现跨分区跨会话的消息不重复。
**原理:**它引入了一个全局唯一的TransactionID,并且将producer获得pid和TransactionID绑定,这样当producer重启后就可以通过正在运行的TransactionID获得原来的pid。
为了管理Transaction,Kafka引入了事务协调器Transaction Coordinator,Producer通过Transaction Coordinator交互得到transactionid对应的任务状态。
Transaction Coordinator还负责将事务所有写入一个kafka内部的topic,这样即使服务重启,运行中的事务也能得到恢复,从而继续运行。
在代码中使用方法
// 设置事务 id(必须),事务 id 任意起名
properties.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "transaction_id_0");
// 3. 创建 kafka 生产者对象
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(properties);
// 初始化事务
kafkaProducer.initTransactions();
// 开启事务
kafkaProducer.beginTransaction();
try {
// 4. 调用 send 方法,发送消息
for (int i = 0; i < 5; i++) {
// 发送消息
kafkaProducer.send(new ProducerRecord<>("first", "atguigu " + i));
}
// int i = 1 / 0;
// 提交事务
kafkaProducer.commitTransaction();
} catch (Exception e) {
// 终止事务
kafkaProducer.abortTransaction();
} finally {
// 5. 关闭资源
kafkaProducer.close();
}
数据有序
-
kafka在1.x版本之前保证数据单分区有序,条件如下:
max.in.flight.requests.per.connection=1(不需要考虑是否开启幂等性)。
-
kafka在1.x及以后版本保证数据单分区有序,条件如下:
-
开启幂等性
-
max.in.flight.requests.per.connection(队列中请求个数)需要设置小于等于5。
因为在kafka1.x以后,启用幂等后,kafka服务端会缓存producer发来的最近5个request的元数据,
故无论如何,都可以保证最近5个request的数据都是有序的。
-