Kafka API

 

Kafka API

 

 

一、消息发送流程

 

 

Kafka消息发送采用异步发送机制。

  • main线程负责将消息经过拦截,序列化,分区,然后提交到RecordAccumulator
  • RecordAccumulator是共享数据的数据结构
  • sender线程则负责从共享数据中拉取数据

 

二、自定义生产者和消费者

 

 

使用就是配置+send/get

比较重要的是理解消息发送流程,如何考虑生产者和消费者同步问题,结合消息发送流程理解。

生产者

使用

    1 acks=all

    2 retries=1

    3 batch.size=16384

    4 linger.ms=1

    5 buffer.memory=33554432

    6 key.serializer=org.apache.kafka.common.serialization.StringSerializer

    7 value.serializer=org.apache.kafka.common.serialization.StringSerializer

    8 bootstrap.servers=hadoop102:9092

代码

    1     public static void main(String[] args) throws ExecutionException, InterruptedException, IOException {

    2         Properties props = new Properties();

    3         props.load(CustomProducer.class.getResourceAsStream("producer.properties"));

    4         Producer<String, String> producer = new KafkaProducer<String, String>(props);

    5         for (int i = 0; i < 10; i++) {

    6             Future<RecordMetadata> future = producer.send(new ProducerRecord<String, String>("first", "" + i, "" + i),

    7                     // 回调时机是ack成功,即发送成功

    8                     new Callback() {

    9                         @Override

   10                         public void onCompletion(RecordMetadata recordMetadata, Exception e) {

   11                             if (e == null) {

   12                                 System.out.println("success -> " + recordMetadata);

   13                             } else {

   14                                 e.printStackTrace();

   15                             }

   16                         }

   17                     });

   18             // 发送后阻塞,等到回复

   19             RecordMetadata recordMetadata = future.get();

   20             System.out.println("send " + i);

   21         }

   22         producer.close();

   23     }

同步讨论:

生成者的同步场景是,如果future不调get,那么事实上发送和接收是异步的。而如果调get,只有main收到kafka返回的ack和metaData才会 继续发送。生产者发送的去重是由kafka的幂等性+事务保证的,因此不用代码考虑。

消费者

    1 bootstrap.servers=hadoop102:9092

    2 group.id=test

    3 enabel.auto.commit=false

    4 auto.commit.interval.ms=5000

    5 key.deserializer=org.apache.kafka.common.serialization.StringDeserializer

    6 value.deserializer=org.apache.kafka.common.serialization.StringDeserializer

代码

    1     public static void main(String[] args) throws IOException {

    2         Properties props = new Properties();

    3         props.load(CustomConsumer.class.getResourceAsStream("consumer.properties"));

    4         KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);

    5         consumer.subscribe(Arrays.asList("first"));

    6         while (true) {

    7             ConsumerRecords<String, String> records = consumer.poll(100);

    8             for (ConsumerRecord<String, String> record : records) {

    9                 System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());

   10             }

   11             consumer.commitSync();

   12         }

   13     }

同步讨论:

消费者的同步,主要考虑的是消费和offset提交,offset默认定时(5ms)提交一次,这样的话,一旦提交之前挂了,就会导致重复消费的问题,像上述代码可以改成手动提交,但是问题在于,上述提交之前也可以被打断。所以消费者实现同步,防止重复很困难,你需要保持消费和提交是同步的。但kafka挂不挂其实不是main线程说的算的,main挂不挂也不是kafka能控制的,于是消费和提交的原子性就比较难考虑。

可能的实现方式如下:

  • 将record取出后暂时不消费,等待提交完成之后消费之
  • offset记录在其他地方,但是这件事必须由下游框架保证消费和记录的原子性,这样的话,即使提交失败也可以重试
  • 去重,在消费者使用map之类去重
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值