batch.size:只有数据累计到batch.size后,sender才会发送数据。默认16klinger.ms:如果迟迟没有达到batch.size,sender等待linger.ms设置时间之后,发送数据。单位:ms,默认0(没有延迟)acks设置:
0:不需要等待数据落盘应答;1:leader落盘后应答;-1(all):leader和follower落盘后应答;
一、ApI调用
(1)、异步API:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KafkaProducerTest {
public static void main(String[] args){
//配置
Properties properties = new Properties();
//连接,如果是集群,不需要全部都配置,只需要配置几个
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.88:9092");
//设置序列化方式
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
//创建连接对象
KafkaProducer kafkaProducer = new KafkaProducer<>(properties);
//发送数据--向first发送10条数据
for (int i = 1; i <= 10; i++){
kafkaProducer.send(new ProducerRecord("first","test1", "hello-kafka" + i));
}
//关闭资源
kafkaProducer.close();
}
}
(2)、带回调的异步API:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KafkaProducerTest {
public static void main(String[] args){
//配置
Properties properties = new Properties();
//连接,如果是集群,不需要全部都配置,只需要配置几个
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.88:9092");
//设置序列化方式
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
//创建连接对象
KafkaProducer kafkaProducer = new KafkaProducer<>(properties);
//发送数据--向first发送10条数据
for (int i = 1; i <= 10; i++){
kafkaProducer.send(new ProducerRecord("first", "test1", "hello-kafka" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if(e == null){
System.out.println("topic:"+recordMetadata.topic()+";partition:"+ recordMetadata.partition());
}
}
});
}
//关闭资源
kafkaProducer.close();
}
}
控制台输出:
(3)、同步API:
同步API只是比异步API多加了一个
.get()
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
public class KafkaProducerTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//配置
Properties properties = new Properties();
//连接,如果是集群,不需要全部都配置,只需要配置几个
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.88:9092");
//设置序列化方式
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
//创建连接对象
KafkaProducer kafkaProducer = new KafkaProducer<>(properties);
//发送数据--向first发送10条数据
for (int i = 1; i <= 10; i++){
kafkaProducer.send(new ProducerRecord("first", "test1", "同步API-发送数据" + i)).get();
}
//关闭资源
kafkaProducer.close();
}
}
二、生产者分区
(1)、好处:
- 1.
便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。 - 2.
提高并行度,生产者可以以分区为单位发送数据,消费者可以以分区为单位消费数据
(2)、默认分区策略
- 1.如果指定分区,发往指定分区
- 2.未指定分区,有key,用key的hash值对topic的partition数量取余,得到partition
- 3.没有指定分区,也没有key,使用粘性分区(一批数据,一次一个分区)。尽可能一直用一个分区,该分区的batch.size/linger.ms已到,再随机选择一个分区,且和上一次的分区不同
//指定分区,发往指定分区
ProducerRecord(String topic, Integer partition, K key, V value);
//未指定分区,有key
ProducerRecord(String topic, K key, V value);
//未指定分区,也没有key
ProducerRecord(String topic, V value);
(3)、自定义分区策略
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import org.apache.kafka.common.PartitionInfo;
import java.util.List;
import java.util.Map;
public class MyPartitioner implements Partitioner {
/**
* @param topic
* @param key 发送的key
* @param keyBytes
* @param value 发送的value
* @param valueBytes
* @param cluster
* @return
*/
@Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
List<PartitionInfo> partitionInfos = cluster.availablePartitionsForTopic(topic);
//分区数量
int num = partitionInfos.size();
//根据value与分区数求余的方式得到分区ID
return value.hashCode() % num;
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> map) {
}
}
//在properties中设置自定义的分区策略properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, MyPartitioner.class);