在Kafka中,保证数据安全可靠的条件是:
数据完全可靠条件 = ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2;
Ack应答级别
可靠性总结: acks=0,生产者发送过来数据就不管了,可靠性差,效率高;
acks=1,生产者发送过来数据Leader应答,可靠性中等,效率中等;
acks=-1,生产者发送过来数据Leader和ISR队列里面所有Follwer应答,可靠性高,效率低; 在生产环境中,acks=0很少使用;acks=1,一般用于传输普通日志,允许丢个别数据;acks=-1,一般用于传输和钱相关的数据, 对可靠性要求比较高的场景。
数据重复分析
acks: -1(all):生产者发送过来的数据,Leader和ISR队列里面的所有节点收齐数据后应答。
即使数据可靠,也有可能产生数据重复的文图,见下图:
当Leader和所有的Follower都接收数据落盘成功,正准备应答时,Leader挂了,此时由一个Follower充当Leader的角色,再重新接收数据,由于上一次已经接受了,这次又发来一样的,导致数据重复。
数据去重
幂等性
幂等性就是指Producer不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复。
精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2) ,这是我们想要的。
重复数据的判断标准:具有相同主键的消息提交时,Broker只会持久化一条。其 中PID是Kafka每次重启都会分配一个新的;Partition 表示分区号;Sequence Number是单调自增的。 所以幂等性只能保证的是在单分区单会话内不重复。
开启参数 enable.idempotence 默认为 true,false 关闭,即可开启幂等性。
事务
幂等性只能保证单分区单会话数据不重复,一旦kafka挂掉再重启,还是有可能会产生重复,这时候只能用事务。
开启事务,必须开启幂等性。
Producer 在使用事务功能前,必须先 自定义一个唯一的 transactional.id。
Kafka 的事务一共有如下 5 个 API
// 1 初始化事务
void initTransactions();
// 2 开启事务
void beginTransaction() throws ProducerFencedException;
// 3 在事务内提交已经消费的偏移量(主要用于消费者)
void sendOffsetsToTransaction(Map<TopicPartition, OffsetAndMetadata> offsets,
String consumerGroupId) throws
ProducerFencedException;
// 4 提交事务
void commitTransaction() throws ProducerFencedException;
// 5 放弃事务(类似于回滚事务的操作)
void abortTransaction() throws ProducerFencedException;