1、首先创建一个topic,三个分区,三个副本
[root@haha-01 kafka_2.11-1.1.0]# bin/kafka-topics.sh --create --zookeeper 192.168.6.133:2181 --replication-factor 3 --partitions 3 --topic haha
2、添加maven依赖
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>1.1.0</version>
</dependency>
3、消息发送
构建一个消费发送的程序一般有下面几步:
- 创建一个简单的首先配置Properties 生产端属性。
- 根据属性实例化一个KafkaProducer对象
- 实例化一个ProducerRecord对象指定topic 、key、value
- 调用KafkaProducer对象的send方法
- 关闭连接,释放资源
3.1配置Kafka连接信息
/**
* 配置Kafka连接信息.
* bootstrap.servers、key.serializer、value.serializer是
* 必须要配置的,其他可以按需添加配置。
* 配置对应的类:org.apache.kafka.clients.producer.ProducerConfig
* 可以查看ProducerConfig的属性,进行其他的一些配置
* @return
*/
public Properties configure() {
Properties props = new Properties();
//用于初始化时建立链接到kafka集群,以host:port形式,多个以逗号分隔host1:port1,host2:port2。
props.put("bootstrap.servers", "192.168.6.133:9092,192.168.6.133:9093,192.168.6.133:9094");
props.put("acks", "1"); // 设置应答模式, 1表示有一个Kafka代理节点返回结果
//发送失败时,指定生产者可以重发消息的次数。
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");// 序列化值
return props;
}
相关配置介绍
注意:bootstrap.servers、key.serializer、value.serializer是必须要配置的,其他可以按需添加配置。
生产者有很多属性可以设置,大部分都有合理的默认值,无需调整。有些参数可能对内存使用,性能和可靠性方面有较大影响。生产者所有的配置都在org.apache.kafka.clients.producer.ProducerConfig这个类里。比如acks,
ACKS_CONFIG 配置的属性,ACKS_DOC 为属性的文档说明。下面介绍一下主要的几个配置。
acks:
指定了必须要有多少个分区副本收到消息,生产者才会认为写入消息是成功的,这个参数对消息丢失的可能性有重大影响。
acks=0:生产者在写入消息之前不会等待任何来自服务器的响应,容易丢消息,但是吞吐量高。
acks=1:只要集群的首领节点收到消息,生产者会收到来自服务器的成功响应。如果消息无法到达首领节点(比如首领节点崩溃,新首领没有选举出来),生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果一个没有收到消息的节点成为新首领,消息还是会丢失。默认使用这个配置。
acks=all:只有当所有参与复制的节点都收到消息,生产者才会收到一个来自服务器的成功响应。延迟高。
buffer.memory:
设置生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息。如果数据产生速度大于向broker发送的速度,导致生产者空间不足,producer会阻塞或者抛出异常。缺省33554432 (32M)
retries:
发送失败时,指定生产者可以重发消息的次数。默认情况下,生产者在每次重试之间等待100ms,可以通过参数retry.backoff.ms参数来改变这个时间间隔。缺省0
batch.size:
当多个消息被发送同一个分区时,生产者会把它们放在同一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算。当批次内存被填满后,批次里的所有消息会被发送出去。但是生产者不一定都会等到批次被填满才发送,半满甚至只包含一个消息的批次也有可能被发送。缺省16384(16k)
linger.ms:
指定了生产者在发送批次前等待更多消息加入批次的时间。它和batch.size以先到者为先。也就是说,一旦我们获得消息的数量够batch.size的数量了,他将会立即发送而不顾这项设置,然而如果我们获得消息字节数比batch.size设置要小的多,我们需要“linger”特定的时间以获取更多的消息。这个设置默认为0,即没有延迟。设定linger.ms=5,例如,将会减少请求数目,但是同时会增加5ms的延迟,但也会提升消息的吞吐量。
3.2发送消息
发送消息有同步发送和异步回调发送,同步会阻塞,降低吞吐量,一般都会采用异步回调的方式。
同步:
@Test
public void testSys(){
//Kafka连接信息对象
Properties configure = configure();
//构建一个生产者
KafkaProducer<String, String> producer = new KafkaProducer<String, String>(configure);
try {
ProducerRecord<String, String> record;
try {
record = new ProducerRecord<String, String>("haha",
"12134", "sys hello world");
Future<RecordMetadata> future = producer.send(record);
RecordMetadata recordMetadata = future.get();//会阻塞直到kafka返回信息
log.debug("RecordMetadata----partition:{},offset:{}",recordMetadata.partition(),recordMetadata.offset());
} catch (Exception e) {
e.printStackTrace();
}
} finally {
producer.close();
}
}
异步回调:
/**
* 异步回调发送
*/
@Test
public void testAsy() throws InterruptedException {
Properties configure = configure();
KafkaProducer<String, String> producer = new KafkaProducer<String, String>(configure);
try {
ProducerRecord<String, String> record;
try {
record = new ProducerRecord<String, String>("haha",
"12134", "asy hello world");
producer.send(record,new Callback() {
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e != null) {
log.error("Send error, msg is " + e.getMessage());
} else {
log.debug("RecordMetadata----partition:{},offset:{}",recordMetadata.partition(),recordMetadata.offset());
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
} finally {
producer.close();
}
TimeUnit.SECONDS.sleep(5);
}
4、消费消息
- 首先初始化连接的配置信息
- 构建KafkaConsumer对象
- 调用subscribe方法订阅话题
- 调用poll方法从kafka服务里拉取消息
- 循环处理
关于消费者的属性配置在org.apache.kafka.clients.consumer.ConsumerConfig这个类里面,包括所有消费端的配置,每条属性配置下面都有介绍说明。
@Slf4j
public class HelloKafkaConsumer {
/** 初始化Kafka集群信息. */
private Properties configure() {
Properties props = new Properties();
//用于初始化时建立链接到kafka集群,以host:port形式,多个以逗号分隔host1:port1,host2:port2。
props.put("bootstrap.servers", "192.168.6.133:9092,192.168.6.133:9093,192.168.6.133:9094");
props.put("group.id", "haha01");// 指定消费者组
props.put("enable.auto.commit", "true");// 开启自动提交
props.put("auto.commit.interval.ms", "1000");// 自动提交的时间间隔
// 反序列化消息主键
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// 反序列化消费记录
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return props;
}
@Test
public void test(){
Properties properties = configure();
KafkaConsumer<String,String> consumer
= new KafkaConsumer<String, String>(properties);
try {
consumer.subscribe(Collections.singletonList("haha"));
while(true){
ConsumerRecords<String, String> records
= consumer.poll(500);
for(ConsumerRecord<String, String> record:records){
log.info("topic:{},分区:{},偏移量:{},key:{},value:{}",record.topic(),
record.partition(),record.offset(),record.key(),record.value());
//do bussiness
}
}
} finally {
consumer.close();
}
}
}
消费者相关配置
消费者有很多属性可以设置,大部分都有合理的默认值,无需调整。有些参数可能对内存使用,性能和可靠性方面有较大影响。可以参考org.apache.kafka.clients.consumer包下ConsumerConfig类。
fetch.min.bytes
每次fetch请求时,server应该返回的最小字节数。如果没有足够的数据返回,请求会等待,直到足够的数据才会返回。缺省为1个字节。多消费者下,可以设大这个值,以降低broker的工作负载
fetch.wait.max.ms
如果没有足够的数据能够满足fetch.min.bytes,则此项配置是指在应答fetch请求之前,server会阻塞的最大时间。缺省为500个毫秒。和上面的fetch.min.bytes结合起来,要么满足数据的大小,要么满足时间,就看哪个条件先满足。
max.partition.fetch.bytes
指定了服务器从每个分区里返回给消费者的最大字节数,默认1MB。假设一个主题有20个分区和5个消费者,那么每个消费者至少要有4MB的可用内存来接收记录,而且一旦有消费者崩溃,这个内存还需更大。注意,这个参数要比服务器的message.max.bytes更大,否则消费者可能无法读取消息。
session.timeout.ms
如果consumer在这段时间内没有发送心跳信息,则它会被认为挂掉了。默认3秒。
auto.offset.reset
消费者在读取一个没有偏移量的分区或者偏移量无效的情况下,如何处理。默认值是latest,从最新的记录开始读取,另一个值是earliest,表示消费者从起始位置读取分区的记录。
注意:默认值是latest,意思是说,在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录),可以先启动生产者,再启动消费者,观察到这种情况。观察代码,在模块kafka-no-spring下包hellokafka中。
enable .auto.commit
默认值true,表明消费者是否自动提交偏移。为了尽量避免重复数据和数据丢失,可以改为false,自行控制何时提交。
partition.assignment.strategy
分区分配给消费者的策略。系统提供两种策略。默认为Range。允许自定义策略。
Range
把主题的连续分区分配给消费者。例如,有主题T1和T2,各有3个分区,消费者C1和C2,则可能的分配形式为:
C1: T1(0,1),T2(0,,1)
C2: T1(2),T2(2)
RoundRobin
把主题的分区循环分配给消费者。例如,有主题T1和T2,各有3个分区,消费者C1和C2,则可能的分配形式为:
C1: T1(0,2),T2(1)
C2: T1(1),T2(0,2)
自定义策略
extends 类AbstractPartitionAssignor,然后在消费者端增加参数:
properties.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG, 类.class.getName());即可。
client.id
当向server发出请求时,这个字符串会发送给server。目的是能够追踪请求源头,以此来允许ip/port许可列表之外的一些应用可以发送信息。这项应用可以设置任意字符串,因为没有任何功能性的目的,除了记录和跟踪。
max.poll.records
控制每次poll方法返回的的记录数量。
receive.buffer.bytes和send.buffer.bytes
指定TCP socket接受和发送数据包的缓存区大小。如果它们被设置为-1,则使用操作系统的默认值。如果生产者或消费者处在不同的数据中心,那么可以适当增大这些值,因为跨数据中心的网络一般都有比较高的延迟和比较低的带宽。