一、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 | 给定发送数据是否进行压缩设置,默认不进行压缩;参数可选:none、gzip、snappy |
message.send.max.retries | 3 | 指定数据发送失败,重试次数,默认3次 |
retry.backoff.ms | 100 | 在数据重新发送过程中,producer会刷新topic的元数据信息(leader信息),由于topic元数据的变化需要一点点时间,故该参数指定的值主要用于在producer刷新元数据之前的等待时间 |
topic.metadata.refresh.interval.ms | 600000 | 给定producer中topic元数据周期性刷新的间隔时间,默认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();
}
}