kafka第二天 事务 producerOnly

1 篇文章 0 订阅

Kafka的幂等性,只能保证一条记录的在分区发送的原子性,但是如果要保证多条记录(多分区)之间的完整性,这个时候就需要开启kafk的事务操作。

在Kafka0.11.0.0除了引入的幂等性的概念,同时也引入了事务的概念。通常Kafka的事务分为 生产者事务Only、消费者&生产者事务。一般来说默认消费者消费的消息的级别是read_uncommited数据,这有可能读取到事务失败的数据,所有在开启生产者事务之后,需要用户设置消费者的事务隔离级别。

isolation.level = read_uncommitted 默认

该选项有两个值read_committed|read_uncommitted,如果开始事务控制,消费端必须将事务的隔离级别设置为read_committed

开启的生产者事务的时候,只需要指定transactional.id属性即可,一旦开启了事务,默认生产者就已经开启了幂等性。但是要求"transactional.id"的取值必须是唯一的,同一时刻只能有一个"transactional.id"存储在,其他的将会被关闭。

producer

package com.kafka.transaction;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;
import java.util.UUID;

public class ProducerTransaction {
    public static void main(String[] args) {
        KafkaProducer<String, String> producer = getProducer();
        //1.事务初始化
        producer.initTransactions();
        //2.开始事务
        producer.beginTransaction();
        try{
            for (int i = 0; i < 10; i++) {
                if(i==8){
                   int j = 10/0;
                }
                ProducerRecord<String, String> record = new ProducerRecord<>("topic01", "transaction" + i, "error test" + i);
                producer.send(record);
                //把缓冲区的数据刷出去
                producer.flush();
            }
            //3.提交事务
            producer.commitTransaction();
        }catch (Exception e){
            System.err.println("error message:"+e.getMessage());
            //4.终止事务
            producer.abortTransaction();
        }finally {
            producer.close();
        }


    }

    public static KafkaProducer<String,String> getProducer(){
        Properties properties = new Properties();
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"node05kafka:9092,node06kafka:9092,node07kafka:9092");
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class);
        // 单个链接上未确认请求的最大数量,若>1并且开启重试,可能导致数据重排序。
        properties.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION,1);
        // 开启事务的唯一标识事务id
        properties.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG,"transaction_id"+ UUID.randomUUID().toString());

        // 设置批处理缓冲区的大小
        properties.put(ProducerConfig.BATCH_SIZE_CONFIG,1024);
        // 若数据不够缓冲区大小,等待时间,刷出数据
        properties.put(ProducerConfig.LINGER_MS_CONFIG,5);

        //开启幂等和重试机制
        properties.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG,true);
        // 设置ack的应答级别
        properties.put(ProducerConfig.ACKS_CONFIG,"all");
        //重试多少次 有默认值2147483647,可以不设置
        properties.put(ProducerConfig.RETRIES_CONFIG,3);
        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);

        return producer;
    }
}

注意consumer也要开启 隔离级别才行,才能保证读取到 正确的数据,ConsumerConfig.ISOLATION_LEVEL_CONFIG,“read_uncommitted”;
主要有两种级别:read_uncommitted和read_committed;默认read_uncommitted
consumer

package com.kafka.transaction;

import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;

import java.time.Duration;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;

public class ConsumerTransaction {

    public static void main(String[] args) {

        Properties properties = new Properties();
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"node05kafka:9092,node06kafka:9092,node07kafka:9092");
        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        properties.put(ConsumerConfig.GROUP_ID_CONFIG,"g2");
        //消费者开启事务,要设置隔离级别,两种read_committed和read_uncommitted
        /**
         * read_committed:读取已经提交的
         * read_uncommitted:读取包含未提交的
         */
        properties.put(ConsumerConfig.ISOLATION_LEVEL_CONFIG,"read_uncommitted");

        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(properties);
        consumer.subscribe(Arrays.asList("topic01"));
        while(true){
            ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofSeconds(1));
            if(!consumerRecords.isEmpty()){
                Iterator<ConsumerRecord<String, String>> iterator = consumerRecords.iterator();
                if(iterator.hasNext()){
                    ConsumerRecord<String, String> record = iterator.next();
                    String topic = record.topic();
                    long timestamp = record.timestamp();
                    int partition = record.partition();
                    long offset = record.offset();
                    String key = record.key();
                    String value = record.value();
                    System.out.println(key+"\t"+value+"\t"+offset+"\t"+partition+"\t"+topic+"\t"+timestamp);

                }
            }

        }
    }
}

producer控制台

INFO 2020-10-21 16:41:46 org.apache.kafka.clients.producer.internals.TransactionManager - [Producer clientId=producer-1, transactionalId=transaction_id7af06238-55ec-4b49-8446-23362ecbb083] ProducerId set to -1 with epoch -1
INFO 2020-10-21 16:41:46 org.apache.kafka.clients.Metadata - Cluster ID: IPQxx1YvSm2lsAXHgX5mVg
INFO 2020-10-21 16:41:47 org.apache.kafka.clients.producer.internals.TransactionManager - [Producer clientId=producer-1, transactionalId=transaction_id7af06238-55ec-4b49-8446-23362ecbb083] ProducerId set to 4000 with epoch 0
error message:/ by zero
INFO 2020-10-21 16:41:48 org.apache.kafka.clients.producer.KafkaProducer - [Producer clientId=producer-1, transactionalId=transaction_id7af06238-55ec-4b49-8446-23362ecbb083] Closing the Kafka producer with timeoutMillis = 9223372036854775807 ms.

consumer控制台两种级别的输出
read_committed:没有输出,因为 producer是错误的测试
read_uncommitted:

transaction0	error test0	70	2	topic01	1603269707202
transaction1	error test1	84	1	topic01	1603269707335
transaction2	error test2	85	1	topic01	1603269707371
transaction3	error test3	86	1	topic01	1603269707390
transaction4	error test4	71	2	topic01	1603269707403
transaction5	error test5	72	2	topic01	1603269707429
transaction6	error test6	73	2	topic01	1603269707446
transaction7	error test7	40	0	topic01	1603269707459
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值