kafka保证数据发送消息有且仅发送一次

286 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

kafka生产模式下生产者经验

提高吞吐量

可以通过修改以下这四个参数来提高消费者的吞吐量。

• batch.size:批次大小,默认16k

• linger.ms:等待时间

• compression.type:压缩snappy

• RecordAccumulator:缓冲区大小,修改为64m

相关设置解释

1、适当增加 缓冲区一批数据最大值 (batch.size)可以提高吞吐量,但是太大之后可能会造成数据传输的延时增加。

2、数据达不到batch.size的值时候,在达到等待时候之后也会发送消息。

数据可靠性

生产者发送消息到broker之后的应答策列,Ack的设置

• 0:生产者发送过来的数据,不需要等数据落盘应答。效率快,但是可靠性不高。

• 1:生产者发送过来的数据,Leader收到数据后应答。 效率和可靠性适中

• -1(all):生产者发送过来的数据,Leader+和isr队列 里面的所有节点收齐数据后应答。-1和all等价。 效率慢,可靠性高(kafka默认的应答策列)

1666419201000.png

当红色的follow挂了之后,一直不能和Leader进行同步,这种情况会认为机器故障,但是避免这种情况在Leader中维护了一个ISR队列,它包含Follow和Leader的集合,如果一个Follow长时间没有和Leader进行通信(发送数据交互或者同步数据)就会从ISR集合中移除这个Follow。 该时间阈值由replica.lag.time.max.ms参 数设定,默认30s。例如2超时,(leader:0, isr:0,1)。 所以数据的可靠性:(分区副本包含Leader和Follow,kafka副本默认一个,生成环境设置2个

完成可靠性分析:ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2

数据重复问题

数据保证不重复:第一:生产者至少发送一次数据到kafka集群(数据不丢),第二:生产者最多也只发送一个次数到kafka集群。(数据不重复

幂等性

生产者无论向kafka集群发送多少次数据,broker中都只会持久化一次。

重复数据判断条件:通过以下这三个条件判断该数据是否重复。

  • 生产者Id:PID kafka每次重启都会生成一个新的Id(所以只能在单次会话中保证不重复
  • 分区号 Partition :分区号
  • 序列号SeqNumber:单调递增

生产者事务

幂等性只能保证在单次会话中保证数据不重复,当kafka集群重启后仍然可能会有重复数据产生。

开启事务,必须要先开启幂等性。

事务协调器选择

事务协调器 ( Transaction Coordinator )每一个broke节点都有事务协调器,那么是如何选择的呢?

  • 根据存储事务信息的特殊主题(该主题默认有50个分区)
  • 用事务id(需要配置)除以50取摸,得到事务属于哪一个分区。
  • 该分区的Leader副本所在的broker就是这个事务id对应的Transaction Coordinator 节点。

1666420655548.png

生产者使用事务示例

        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
​
        kafkaProducer.initTransactions();
​
        kafkaProducer.beginTransaction();
​
        try {
            // 2 发送数据
            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 {
            // 3 关闭资源
            kafkaProducer.close();
        }
​

数据有序

由于分区的原因导致发送的消息可能在不同的分区。所以我们需要数据在多分区下有序。生产者发送的数据有先后关系,在消费者消费数据同时,我们需要消费的数据也是原来发送的顺序的。

多分区的情况下可采用一个消费者拉去所有分区的数据再进行排序,然后再进行消费。效率还不如单分区,保证单分区内数据有序。

数据乱序

产生的原因:数据1发送过去,发送成功,数据2发送失败导致重试,但是数据3可能已经发送过去了,最后又发送数据2,导致数据为1,3,2乱序了。

解决办法:

1)kafka在1.x版本之前保证数据单分区有序,条件如下: max.in.flight.requests.per.connection=1(不需要考虑是否开启幂等性)。

2)kafka在1.x及以后版本保证数据单分区有序,条件如下:

(1)未开启幂等性 max.in.flight.requests.per.connection需要设置为1。

(2)开启幂等性 max.in.flight.requests.per.connection需要设置小于等于5。

原因说明:因为在kafka1.x以后,启用幂等后,kafka服务端会缓存producer发来的最近5个request的元数据, 故无论如何,都可以保证最近5个request的数据都是有序的。