kafka(十):Kafka Java Producer的实现

38 篇文章 2 订阅
32 篇文章 0 订阅

一、KAFKA-0.8实现

1.参考官网:

    http://kafka.apache.org/082/documentation.html#producerapi
    http://kafka.apache.org/081/documentation.html#producerconfigs
    http://kafka.apache.org/081/documentation.html#apidesign
    http://kafka.apache.org/081/documentation.html#producerapi

2.producer参数说明

参数名称

默认参数值

备注

metadata.broker.list

 

指定kafka服务器监听的主机名和端口号列表,不同服务器之间使用“,”进行分割

request.required.acks

0

指定producer需要等待broker返回数据成功接收标识;0表示不等待,1表示等待一个broker返回结果,-1表示等待所有broker返回结果

request.timeout.ms

10000

acks参数配置的时候,指定producer等待连接过期的时间毫米数

producer.type

sync

指定producer发送数据的方式是异步(async)还是同步(sync)

serializer.class

kafka.serializer.DefaultEncoder

指定producer发送数据的时候数据/消息编码器,即将消息转换为byte数组的编码器

key.serializer.class

 

指定producer发送数据的时候key类型的数据编码器,默认使用${serializer.class}给定的值

partitioner.class

kafka.producer.DefaultPartitioner

指定producer发送数据的数据分区器,默认采用hash进行数据分区操作;该参数的主要功能是:决定数据到底发送到那一个分区中

参数名称

默认参数值

备注

compression.codec

none

给定发送数据是否进行压缩设置,默认不进行压缩;参数可选:nonegzipsnappy

message.send.max.retries

3

指定数据发送失败,重试次数,默认3

retry.backoff.ms

100

在数据重新发送过程中,producer会刷新topic的元数据信息(leader信息),由于topic元数据的变化需要一点点时间,故该参数指定的值主要用于在producer刷新元数据之前的等待时间

topic.metadata.refresh.interval.ms

600000

给定producertopic元数据周期性刷新的间隔时间,默认10分钟;当该参数给定的值为负数的时候,topic元数据的刷新只有在发送数据失败后进行刷新;当该参数给定为0的时候,每次发送数据后都进行元数据刷新(不推荐);注意:元数据的刷新是在发送数据后触发的,如果永远不发送数据,那么元数据不会被刷新

queue.buffering.max.ms

5000

当数据传输方式是async(异步)的时候,指定数据在producer端停留的最长时间,该参数对于数据吞吐量有一定的影响,当时会增加数据的延迟性

queue.buffering.max.messages

10000

当数据传输方式为async(异步)的时候,指定producer端最多允许临时保存的最大数据量,当数据量超过该值的时候,发送一次数据

queue.enqueue.timeout.ms

-1

当数据发送方式为async(异步),而且等待队列数据填充满的时候{queue.buffering.max.messages},一条新的数据过来,最大阻塞时间;设置为0表示,不阻塞,当队列满的时候,直接将新数据删除(不发送); 当设置为正数的时候,表示等待给定毫秒数后,进行重试操作,失败则数据删除(不发送);设置为-1表示一直等待,直到队列允许添加数据

batch.num.messages

200

当数据发送方式为async(异步)的时候,producer一个批次发送的数据条数;当producer中的数据量达到该参数${batch.num.messages}的设置值或者数据停留时间超过参数${queue.buffering.max.ms}的时候,触发producer发送数据的动作(实际发送数据量可能不超过该参数值)

send.buffer.bytes

102400

指定producer端数据缓存区大小,默认值为:10KB

 

 

3.Producer的java代码【kafka环境:kafka_2.10-0.8.2.1】

【参考官网:http://kafka.apache.org/082/documentation.html#producerapi

(1)PartitionerDemo 

package _0807ProducerSelf;

import kafka.producer.Partitioner;
import kafka.utils.VerifiableProperties;

/**
 * 
 */
public class PartitionerDemo implements Partitioner {
    public PartitionerDemo(VerifiableProperties props) {
        // 该构造函数必须添加
        // props其实就是Producer连接Kafka服务的配置参数
    }

//    @Override
    public int partition(Object key, int numPartitions) {
        // 假设key的偶数到分区0,奇数到分区1,
        // 如果分区数量等于1,那么全部数据到分区0
        if (numPartitions == 1) {
            return 0;
        } else {
            String str = (String) key;
            int num = Integer.valueOf(str.replace("key_", ""));
            return num % 2;
        }
    }
}

(2)ProducerDemo

package _0807ProducerSelf;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

import java.util.Properties;
import java.util.Random;

/**
 * Created by ibf on 08/26.
 */
public class ProducerDemo {
    public static void main(String[] args) {
//        final char[] chars = "qazwsxedcrfvtgbyhnujmikolp".toCharArray();
        final char[] chars = "abcwsxs".toCharArray();
        final int charLength = chars.length;
        final String topic = "hadoop1";

        // 1. 创建一个Producer对象
        // 1.1 构建一个Properties以及给定连接kafka的相关producer的参数
        Properties props = new Properties();
        // a. 给定kafka的服务路径信息
//        props.put("metadata.broker.list", "hadoop-senior01.hadoop:9092,hadoop-senior01.hadoop.com:9093,hadoop-senior01.hadoop.com:9094,hadoop-senior01.hadoop.com:9095");
        props.put("metadata.broker.list", "bigdata.hadoop.com:9092,bigdata.hadoop.com:9093");

        // b. 给定数据发送是否等待broker返回结果, 默认为0表示不等待
        props.put("request.required.acks", "0");
        // c. 给定数据发送方式,默认是sync==>同步发送数据,可以修改为异步发送数据(async)
        props.put("producer.type", "sync");
        // d. 给定消息序列化为byte数组的方式,默认为: kafka.serializer.DefaultEncoder, 默认情况下,要求Producer发送的数据类型是byte数组;如果发送string类型的数据,需要给定另外的Encoder编码器
        props.put("serializer.class", "kafka.serializer.StringEncoder");
        // e. 数据发送默认采用hash的机制决定消息发送到那一个分区中,默认值为: kafka.producer.DefaultPartitioner, 参数为: partitioner.class
        // TODO: 有时候需要根据业务的需要自定义一个数据分区器
//        props.put("partitioner.class", "com.hadoop.kafka.producer.PartitionerDemo");PartitionerDemo
        props.put("partitioner.class", "_0807ProducerSelf.PartitionerDemo");
        // 1.2 构建ProducerConfig
        ProducerConfig config = new ProducerConfig(props);
        // 1.3 构建Producer
        final Producer<String, String> producer = new Producer<String, String>(config);

        // 2. 多线程的形式发送数据
        final Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 初始化一个发送数据的值, [100, 1099]
                    int events = random.nextInt(1000) + 100;
                    String threadName = Thread.currentThread().getName();
                    for (int j = 0; j < events; j++) {
                        if (j != 0 && j % 100 == 0) {
                            System.out.println("线程[" + threadName + "]已经发送" + j + "条数据!");
                        }

                        // 1. 初始化key和message
                        String key = "key_" + random.nextInt(100);
                        // 假设message由单词构成,单词数量范围为:[1, 10]
                        StringBuilder sb = new StringBuilder();
                        int wordNums = random.nextInt(10) + 1;
                        for (int k = 0; k < wordNums; k++) {
                            // 单词由单个字符构成,数量范围为: [1, 10]
                            StringBuilder sb2 = new StringBuilder();
                            int charNums = random.nextInt(10) + 1;
                            for (int l = 0; l < charNums; l++) {
                                sb2.append(chars[random.nextInt(charLength)]);
                            }
                            sb.append(sb2.toString().trim()).append(" ");
                        }
                        String value = sb.toString().trim();

                        // 2. 初始化要发送的数据
                        KeyedMessage<String,String> keyedMessage = new KeyedMessage<String, String>(topic, key, value);

                        // 3. 发送数据
                        producer.send(keyedMessage);

                        // 4. 发送完数据后,休息一下
                        try {
                            Thread.sleep(random.nextInt(50) + 10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("线程[" + threadName + "]总共发送" + events + "条数据!!!!");
                }
            }, "Thread-" + i).start();
        }

        // 3.  数据发送完成后,需要关闭连接
        // 一般情况下,是添加一个jvm的钩子,当jvm退出的时候进行数据关闭操作
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("关闭Producer.....");
                producer.close();
            }
        }));

    }


}

3.Producer的java代码【kafka环境:kafka_2.11-0.10.0.1】

(1)Kafka消费者

[root@hadoop kafka_2.11-0.10.2.1]# bin/kafka-console-consumer.sh --bootstrap-server hadoo9092 --topic dayu

(2)kafka生产者代码

package _0807ProducerSelf;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

import java.util.Properties;
import java.util.Random;

/**
 */
public class ws_hadoop01_ProducerDemo {
    public static void main(String[] args) {
//        final char[] chars = "qazwsxedcrfvtgbyhnujmikolp".toCharArray();
        final char[] chars = "abcwsxs".toCharArray();
        final int charLength = chars.length;
        final String topic = "dayu";

        // 1. 创建一个Producer对象
        // 1.1 构建一个Properties以及给定连接kafka的相关producer的参数
        Properties props = new Properties();
        // a. 给定kafka的服务路径信息
//        props.put("metadata.broker.list", "hadoop-senior01.hadoop.com:9092,hadoop-senior01.hadoop.com:9093,hadoop-senior01.hadoop.com:9094,hadoop-senior01.hadoop.com:9095");
        props.put("metadata.broker.list", "hadoop:9092");

        // b. 给定数据发送是否等待broker返回结果, 默认为0表示不等待
        props.put("request.required.acks", "1");
        // c. 给定数据发送方式,默认是sync==>同步发送数据,可以修改为异步发送数据(async)
        props.put("producer.type", "sync");
        // d. 给定消息序列化为byte数组的方式,默认为: kafka.serializer.DefaultEncoder, 默认情况下,要求Producer发送的数据类型是byte数组;如果发送string类型的数据,需要给定另外的Encoder编码器
        props.put("serializer.class", "kafka.serializer.StringEncoder");
        // e. 数据发送默认采用hash的机制决定消息发送到那一个分区中,默认值为: kafka.producer.DefaultPartitioner, 参数为: partitioner.class
        // TODO: 有时候需要根据业务的需要自定义一个数据分区器
//        props.put("partitioner.class", "com.hadoop.kafka.producer.PartitionerDemo");PartitionerDemo
//        props.put("partitioner.class", "_0807ProducerSelf.PartitionerDemo");
        // 1.2 构建ProducerConfig
        ProducerConfig config = new ProducerConfig(props);
        // 1.3 构建Producer
        final Producer<String, String> producer = new Producer<String, String>(config);

        // 2. 多线程的形式发送数据
        final Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 初始化一个发送数据的值, [100, 1099]
                    int events = random.nextInt(1000) + 100;
                    String threadName = Thread.currentThread().getName();
                    for (int j = 0; j < events; j++) {
                        if (j != 0 && j % 100 == 0) {
                            System.out.println("线程[" + threadName + "]已经发送" + j + "条数据!");
                        }

                        // 1. 初始化key和message
                        String key = "key_" + random.nextInt(100);
                        // 假设message由单词构成,单词数量范围为:[1, 10]
                        StringBuilder sb = new StringBuilder();
                        int wordNums = random.nextInt(10) + 1;
                        for (int k = 0; k < wordNums; k++) {
                            // 单词由单个字符构成,数量范围为: [1, 10]
                            StringBuilder sb2 = new StringBuilder();
                            int charNums = random.nextInt(10) + 1;
                            for (int l = 0; l < charNums; l++) {
                                sb2.append(chars[random.nextInt(charLength)]);
                            }
                            sb.append(sb2.toString().trim()).append(" ");
                        }
                        String value = sb.toString().trim();

                        // 2. 初始化要发送的数据
                        KeyedMessage<String,String> keyedMessage = new KeyedMessage<String, String>(topic, key, value);

                        // 3. 发送数据
                        producer.send(keyedMessage);

                        // 4. 发送完数据后,休息一下
                        try {
                            Thread.sleep(random.nextInt(50) + 10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("线程[" + threadName + "]总共发送" + events + "条数据!!!!");
                }
            }, "Thread-" + i).start();
        }

        // 3.  数据发送完成后,需要关闭连接
        // 一般情况下,是添加一个jvm的钩子,当jvm退出的时候进行数据关闭操作
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("关闭Producer.....");
                producer.close();
            }
        }));

    }


}

(3)运行生产者后,消费者消费

......
bxxxsawcs xbwcssccc wc csc xsawass x bwwsascxas bswx c
ssswxsbsa saxssawca sc wbcbb c c saxa
xca
scsw ccwbs wxaaxsxxs ax wcxssswsx axxwwa wscxxwscs xxxxxwa
ssscbsbc wcbsscsas xwaax cs
cswaw caswba xbssxsswxs
bbcaccabsb xxcwaccx ccbcaxwb
ww aswx asbcaxwsab swxbw wb ssxbxxss baccswswa xssx wsxxacaxas xbwxbs
.......

二、KAFKA-0.10.2-KAFKA2.2.0实现

1.环境

基于cdh集群的0.10.2-KAFKA2.2.0

topic名称为:tests,Partition:3,Replication:3

2.pom依赖

    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>kafka_2.11</artifactId>
      <version>0.10.0.1</version>
    </dependency>

3.生产者使用KafkaProducer

包:org.apache.kafka.clients.producer.KafkaProducer

参考源码中配置:

* <pre>
* {@code
* Properties props = new Properties();
* props.put("bootstrap.servers", "localhost:9092");
* props.put("acks", "all");
* props.put("retries", 0);
* props.put("batch.size", 16384);
* props.put("linger.ms", 1);
* props.put("buffer.memory", 33554432);
* 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);
* for(int i = 0; i < 100; i++)
*     producer.send(new ProducerRecord<String, String>("my-topic", Integer.toString(i), Integer.toString(i)));
*
* producer.close();
* }</pre>

4.JAVA程序

package com.test;

import kafka.javaapi.producer.Producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.util.Properties;

public class ProducerTest {

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

        Properties props = new Properties();
        //kafkabroker地址
        props.put("bootstrap.servers", "broker1:9092,broker2:9092,broker3:9092");
        //相应策略
        //0:只是发送;-1:leader节点接受返回;all所有节点接收,才返回
        props.put("acks", "all");
        //等效: 
//        props.put(ProducerConfig.ACKS_CONFIG, "all");
        
        //重试次数
        props.put("retries", 0);
        props.put("batch.size", 16384);
        props.put("linger.ms", 1);
        props.put("buffer.memory", 33554432);
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        KafkaProducer<String, String> producer = new KafkaProducer<String,String>(props);
        for (int i = 0; i < 100; i++){
            producer.send(new ProducerRecord<String, String>("tests", Integer.toString(i), Integer.toString(i)));
            System.out.println(i);
        }
//
        producer.close();

    }
}

5.开启消费者,即可消费

kafka-console-consumer --bootstrap-server broker1:9092,broker2:9092,broker3:9092 --topic tests


结果是无序的
...
43
44
45
47
48
52
54
55
56
59
60
61
63
64
70
71
72
76
79
80
82
...

6.自定义分区器partitioner

实现implements Partitioner(import org.apache.kafka.clients.producer.Partitioner)接口

package com.test.kafka;

import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;

import java.util.Map;

public class SelfPartitioner implements Partitioner {
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        //设置都存储到0分区
        return 0;

    }

    public void close() {

    }

    public void configure(Map<String, ?> configs) {

    }
}

7.生产者程序配置分区器类

//分区
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.test.kafka.SelfPartitioner");
//等效:props.put("partitioner.class","com.test.kafka.SelfPartitioner");

具体生产者代码

package com.test;

import kafka.javaapi.producer.Producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.util.Properties;

public class ProducerTest {

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

        Properties props = new Properties();
        //kafkabroker地址
        props.put("bootstrap.servers", "broker1:9092,broker2:9092,broker3:9092");
        //相应策略
        //0:只是发送;-1:leader节点接受返回;all所有节点接收,才返回
        props.put("acks", "all");
        //等效:
//        props.put(ProducerConfig.ACKS_CONFIG, "all");

        //重试次数
        props.put("retries", 0);
        props.put("batch.size", 16384);
        props.put("linger.ms", 1);
        props.put("buffer.memory", 33554432);
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        //分区
        props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.test.kafka.SelfPartitioner");
        KafkaProducer<String, String> producer = new KafkaProducer<String,String>(props);
        for (int i = 0; i < 100; i++){
            producer.send(new ProducerRecord<String, String>("tests", Integer.toString(i), Integer.toString(i)));
            System.out.println(i);
        }
//
        producer.close();

    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值