【kafka】Producer笔记

记录下kafka生产者遇到的一些问题,主要基于0.8/0.9版本的producer api。

一、kafka简介

Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统)。Kafka主要被用于两大类应用:1.在应用间构建实时的数据流通道;2.构建传输或处理数据流的实时流式应用。

链接:

【logo图】
在这里插入图片描述

二、生产者基本实现

1.示意图

在这里插入图片描述

2.具体实现:

2.1 Fire-and-forget模式

发送消息后不需要逻辑程序关心是否发送成功。这个是默认的写法,依赖producer api本身的高可用(配置相关参数后失败了也会重试),且默认就是高吞吐地异步发送。绝大部分情况下数据是会成功的,但是也会有失败的情况。
[官方demo]
(https://github.com/apache/kafka/blob/0.8.2/examples/src/main/java/kafka/examples/Producer.java)

注意: 这个是0.8版本的例子

  public Producer(String topic)
  {
    props.put("serializer.class", "kafka.serializer.StringEncoder");
    props.put("metadata.broker.list", "localhost:9092");
    // Use random partitioner. Don't need the key type. Just set it to Integer.
    // The message is of type String.
    producer = new kafka.javaapi.producer.Producer<Integer, String>(new ProducerConfig(props));
    this.topic = topic;
  }
  
  public void run() {
    int messageNo = 1;
    while(true)
    {
      String messageStr = new String("Message_" + messageNo);
      producer.send(new KeyedMessage<Integer, String>(topic, messageStr));
      messageNo++;
    }
  }

优点:

  • 写法简单,且producer api本身即提供一定的高可用
  • 吞吐高,默认即异步发送

缺点:

  • 当producer api本身的高可用不可靠时即会出现一些异常的情况,且程序本身很难捕获具体那条数据异常。

2.2 同步模式

参考代码:

producer.send(record).get();

即sender()方法后再调用get()方法会同步地等待结果返回,根据结果可以判断是否发送成功。

优点:

  • 可以捕获每批发送记录的情况,并可以在业务层面做一些二次处理

缺点:

  • 吞吐下降严重

2.3 callback模式

0.9版本引入callback模式

class DemoProducerCallback implements Callback {
	@Override
	public void onCompletion(RecordMetadata recordMetadata, Exception e) {
		if (e != null) {
			e.printStackTrace();
		}
	}
}
 
producer.send(record, new DemoProducerCallback());

通过callback机制,异步地触发式检查broker返回的结果,从而检查每次发送的结果。
要使用callback函数,先要实现org.apache.kafka.clients.producer.Callback接口,该接口只有一个onCompletion方法。如果发送异常,onCompletion的参数Exception e会为非空。

callback性能损失不容小视,但其吞吐仍然远远大于同步的模式。

【性能对比测试】

总之,我们需要根据我们具体的业务场景实现我们的生产方式。

三、producer参数调优

1. acks

  • acks=-1 强一致,不会丢数据。吞吐量会下降
  • acks=0 发过去就完事了,不关心broker是否处理成功,可能丢数据。
  • acks= 1 当写Leader成功后就返回,其他的replica都是通过fetcher去同步的,所以kafka是异步写,主备切换可能丢数据。

我们现网综合权衡成本效率下,默认使用的是acks= 1。

2. retries

顾名思义,当设置为大于零的值,客户端会重新发送任何发送失败的消息。主要问题:

  • retries 不生效问题(大坑),主要是一些不可重试地异常,如“message size too large”(消息太大)
  • 写入顺序的问题:重试会导致数据写入的无序

3. serializer.class

序列化用到的类。因为一些很复杂的业务问题,我们现网中以string为主。在某些特性开发中,会使用avro。

4. compression.codec

现网一般不压缩(生产机器cpu性能不太好),特性开发场景使用Snappy偏多。

5. batch.num.messages & queue.buffering.max.ms

影响吞吐\实时性的两个指标。

  • batch.num.messages:顾名思义,一批发送的消息数量
  • queue.buffering.max.ms:队列中buff的最大时间数目(数据即使没到batch的量也会发送)

注意: 0.9版本以后batch.num.messages替换成batch.size

现网中需要详细地压测着两个指标,以达到吞吐和实时性之间的平衡。

四、分区问题

0.8版本的producer会存在要死broker分区的情况,导致kafka多分区之间数据不均匀的情况。
解决方法有两种:

  • api端指定key: key对应分区不存在会出现异常
  • 0.9版本api已经内置相关的算法,直接升级即可

五、其他问题

1. 生产幂等性

2. kafka生产高吞吐原理

六、kafka高可用生产的一种尝试

TBD

参考

《震惊了!原来这才是kafka!》
https://www.jianshu.com/p/d3e963ff8b70
《Kafka基础-生产者发送消息》
https://blog.csdn.net/gangchengzhong/article/details/80745974

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kafka 中,Producer 是用来发送消息到 Kafka 集群的组件。在本篇文章中,我们将介绍如何使用 KafkaJava 客户端 API 来编写一个简单的 Producer。 1. 引入 Kafka 依赖 首先,需要在 Maven 或 Gradle 构建中引入 Kafka 客户端依赖: ```xml <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.8.0</version> </dependency> ``` 2. 创建 Producer 实例 接下来,在 Java 代码中创建一个 KafkaProducer 实例: ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ``` 其中,bootstrap.servers 是必须设置的属性,用于指定 Kafka 集群中至少一个 Broker 的地址。key.serializer 和 value.serializer 用于指定消息的键和值的序列化器。这里我们使用的是 StringSerializer,也可以使用其他序列化器实现自定义序列化逻辑。 3. 发送消息 一旦创建了 KafkaProducer 实例,就可以使用它来发送消息到指定的 Kafka 主题: ```java ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); ``` 这里的 ProducerRecord 构造函数中,第一个参数是要发送消息的主题名称,第二个参数是消息的键,第三个参数是消息的值。send() 方法用于将 ProducerRecord 发送到 Kafka 集群。 4. 关闭 Producer 在使用完 Producer 后,需要关闭它以释放资源: ```java producer.close(); ``` 完整代码示例: ```java import org.apache.kafka.clients.producer.*; import java.util.Properties; public class KafkaProducerExample { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); producer.close(); } } ``` 这就是一个简单的 Kafka Producer 的使用示例。在实际应用中,还可以根据需要设置其他属性,例如消息的分区策略、消息的压缩方式等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值