Kafka集群搭建编程实践(Java)

Kafka编程实战(JAVA)

一、概述

kafka编程实战主要由两个方面:

  • 消息的发送----生产者生产数据发送到Kafa队列中
  • 消息的消费----消费者从队列中拉取数据消费

主要内容:

  • Kafka消息发送流程
  • Kafka消息消费流程
  • 消息发送失败重试机制
  • 组件扩展

二、Kafka消息发送流程

在这里插入图片描述

如图为Kafka客户端架构主要有以下几个部分:

  • main线程----负责消息的封装、初始化、分区计算

    • Interceptors:拦截器,可组成连接器链,如web中的Filter等
    • Serializer:初始化器
    • Partitioner:负责分区计算,计算消息要发往哪个分区
  • Sender线程

    可理解成一个while…true循环,不断将监听RecordAccumulator,将其中的数据发往对应的分区

  • 共享变量RecordAccumulator

    如图RecordAccumulator中由多个队列,这些队列和主题中的分区是一一对应的

    主线程封装好数据,保存在RecordAccumulator中,sender负责具体将共享变量中的数据发送网络传输

    • 为了减少网络传输次数,不断的网络连接建立是比较耗费资源的,所以sender从共享变量中获取数据是一批一批的

    • main线程,向共享变量中发送数据是一条一条一条的

    • 共享变量中对立中每批数据量的大小是可以配置的

      **batch.size:**只有数据积累到batch.size之后,sender才会发送数据

      **linger.ms:**如果数据迟迟未达到batch.size,sender等待linger.time之后就会发送数据

三、Kafka消息发送

首先Kafka发送消息的方式在老版本中有两种:

  • 异步发送
  • 同步发送

在新版本中只有异步发送

3.1、集群环境搭建

三台服务器

在linux环境中,首先安装zookeeper(kafaka是依赖于kafka工作的),zookeeper集群配置参考zookeeper集群搭建(docker)

安装kafka,下载其压缩包,解压即可

3.1.1、对kafka进行配置:

#broker的全局唯一编号,不能重复
broker.id=0
#删除topic功能使能
delete.topic.enable=true
#处理网络请求的线程数量
num.network.threads=3
#用来处理磁盘IO的现成数量
num.io.threads=8
#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400
#接收套接字的缓冲区大小
socket.receive.buffer.bytes=102400
#请求套接字的缓冲区大小
socket.request.max.bytes=104857600
#kafka运行日志存放的路径	
log.dirs=/opt/module/kafka/logs
#topic在当前broker上的分区个数
num.partitions=1
#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#配置连接Zookeeper集群地址
zookeeper.connect=192.168.23.100:2181,192.168.23.101:2181,192.168.23.102:2181

3.1.2、环境变量

#KAFKA_HOME
export KAFKA_HOME=/opt/module/kafka
export PATH=$PATH:$KAFKA_HOME/bin

3.1.3、修改broker.id

broker.id=1、broker.id=2

每台机器上的broker.id必须唯一

3.1.4、基本命令

#启动
bin/kafka-server-start.sh  stop
#关闭
bin/kafka-server-stop.sh  stop

3.1.5、群起脚本

for i in `cat /opt/module/hadoop-2.7.2/etc/hadoop/slaves`
do
echo "========== $i ==========" 
ssh $i 'source /etc/profile&&/opt/module/kafka_2.11-0.11.0.2/bin/kafka-server-start.sh -daemon /opt/module/kafka_2.11-0.11.0.2/config/server.properties'
echo $?
done

其中路径需要根据自己路径修改

启动kafka集群前保证zookeeper已经启动,否则启动失败

3.2、创建发送客户端

通过maven构建kafka客户端

3.2.1、导入依赖

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.11.0.0</version>
</dependency>

3.2.2、异步发送

需要用到的类:

  • KafkaProducer:需要创建一个生产者对象,用来发送数据
  • ProducerConfig:获取所需的一系列配置参数
  • ProducerRecord:每条数据都要封装成一个ProducerRecord对象

客户端API有两种:

  • 不带回调函数的api
public class CustomProducer {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Properties props = new Properties();
        props.put("bootstrap.servers", "192.168.23.100:9092");//kafka集群,broker-list
        props.put("acks", "all");
        props.put("retries", 1);//重试次数
        props.put("batch.size", 16384);//批次大小
        props.put("linger.ms", 1);//等待时间
        props.put("buffer.memory", 33554432);//RecordAccumulator缓冲区大小
        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>("first", Integer.toString(i), Integer.toString(i)));
        }
        producer.close();
    }
}
  • 带回调函数的API:发送失败后,会自动重试(异步调用)
public class CustomProducer2 {
   public static void main(String[] args) throws ExecutionException, InterruptedException {
      Properties props = new Properties();
      props.put("bootstrap.servers", "192.168.23.100:9092");//kafka集群,broker-list
      props.put("acks", "all");
      props.put("retries", 1);//重试次数
      props.put("batch.size", 16384);//批次大小
      props.put("linger.ms", 1);//等待时间
      props.put("buffer.memory", 33554432);//RecordAccumulator缓冲区大小
      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>("first", Integer.toString(i), Integer.toString(i),new Callback() {

            //回调函数,该方法会在Producer收到ack时调用,为异步调用
            @Override
            public void onCompletion(RecordMetadata metadata, Exception exception) {
               if (exception == null) {
                  System.out.println("success->" + metadata.offset());
               } else {
                  exception.printStackTrace();
               }
            }
         });
      }
      producer.close();
   }
}

3.2.2、同步发送

每次发送消息后,等到接收到ack后再发送消息

Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++) {
    producer.send(new ProducerRecord<String, String>("first", Integer.toString(i), Integer.toString(i))).get();
}
producer.close();

send方法返回的是Future对象,其个get方法可以阻塞线程,当拿到返回值后再继续发送

异步、同步的api是相同的,只是利用了Future的特性,开发中大部分场景下不使用

四、Kafka消息消费

Consumer消费数据时的可靠性是很容易保证的,因为数据在Kafka中是持久化的,故不用担心数据丢失问题。

由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置的继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便故障恢复后继续消费。

所以offset的维护是Consumer消费数据是必须考虑的问题。

4.1、offset提交

offset提交有两种:

手动提交

  • 异步提交
  • 同步提交

相同点: 都会将本次 poll 的一批数据最高的偏移量提交

不同点: commitSync会失败重试,一直到提交成功(如果由于不可恢复原因导致,也会提交失败);而commitAsync则没有失败重试机制,故有可能提交失败。

可能都会有重复消费

手动提交时,要关闭自动提交配置

props.put("enable.auto.commit", "false")
public class CustomConsumer {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "192.168.23.100:9092");
        props.put("group.id", "test");//消费者组,只要group.id相同,就属于同一个消费者组
        props.put("enable.auto.commit", "false");//自动提交offset
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
        consumer.subscribe(Arrays.asList("first"));
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            for (ConsumerRecord<String, String> record : records) {
                System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
            }
            //同步
            consumer.commitSync();
            //异步
            //consumer.commitASync();
        }
    }
}

自动提交

默认是自动提交(异步提交)

props.put("enable.auto.commit", "true")
props.put("auto.commit.interval.ms", "1000");

五、自定义Interceptor

自定义Intercetpor要实现接口org.apache.kafka.clients.producer.ProducerInterceptor

原理与web中servlet、filter、Intercetpor是一样的

消息发送前以及producer回调逻辑前有机会对消息做一些定制化需求

该接口有以下几个方法:

  1. configure(configs) 获取配置信息和初始化数据时调

  2. onSend(ProducerRecord)

    Producer确保在消息被序列化以及计算分区前调用该方法。用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的topic和分区,否则会影响目标分区的计算。

  3. onAcknowledgement(RecordMetadata, Exception)

    该方法会在消息从RecordAccumulator成功发送到Kafka Broker之后,或者在发送过程中失败时调用。并且通常都是在producer回调逻辑触发之前。onAcknowledgement运行在producer的IO线程中,因此不要在该方法中放入很重的逻辑,否则会拖慢producer的消息发送效率。

  4. close

    关闭interceptor,主要用于执行一些资源清理工作

    如前所述,interceptor可能被运行在多个线程中,因此在具体实现时用户需要自行确保线程安全。另外倘若指定了多个interceptor,则producer将按照指定顺序调用它们,并仅仅是捕获每个interceptor可能抛出的异常记录到错误日志中而非在向上传递。这在使用过程中要特别

    留意。

六、Kafka监控

kafka监控使用一个web接口的访问插件

6.1 Kafka Monitor

一个web项目

1.上传jar包KafkaOffsetMonitor-assembly-0.4.6.jar到集群

2.在/opt/module/下创建kafka-offset-console文件夹

3.将上传的jar包放入刚创建的目录下

4.在/opt/module/kafka-offset-console目录下创建启动脚本start.sh,内容如下

#!/bin/bash
java -cp KafkaOffsetMonitor-assembly-0.4.6-SNAPSHOT.jar \
com.quantifind.kafka.offsetapp.OffsetGetterWeb \
--offsetStorage kafka \
--kafkaBrokers 192.168.23.100:9092,192.168.23.101:9092,192.168.23.101:9092 \
--kafkaSecurityProtocol PLAINTEXT \
--zk 192.168.23.100:2181,192.168.23.101:2181,192.168.23.102:2181 \
--port 8086 \
--refresh 10.seconds \
--retain 2.days \
--dbName offsetapp_kafka &

5.在/opt/module/kafka-offset-console目录下创建mobile-logs文件夹

mkdir /opt/module/kafka-offset-console/mobile-logs

6.启动KafkaMonitor

./start.sh

7.登录页面hadoop102:8086端口查看详情

6.2 Kafka Manager

1.上传压缩包kafka-manager-1.3.3.15.zip到集群

2.解压到/opt/module

3.修改配置文件conf/application.conf

kafka-manager.zkhosts="kafka-manager-zookeeper:2181"

修改为:

kafka-manager.zkhosts="192.168.23.100:2181,192.168.23.101:2181,192.168.23.102:2181"

4.启动kafka-manager

bin/kafka-manager

5.登录hadoop102:9000页面查看详细信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值