Kafka集群搭建(超详细,附Java测试代码)

                                         **

Centos7 Kafka三节点搭建

在这里插入图片描述
**
kafka官网下载地址:
http://kafka.apache.org/downloads.html
Kafka集群搭建规划
在这里插入图片描述

全程hadoop账号安装,符合生产环境的规范

mkdir -p ~/bigdata/kafka
tar -zxvf kafka_2.11-2.1.0.tgz -C ~/bigdata/kafka/
cd /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/config
最小配置项
vi server.properties
broker.id=1
num.partitions=2
default.replication.factor=2
listeners=PLAINTEXT://centosnode01:9092
log.dirs=/home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/kafka-logs
zookeeper.connect=centosnode01:2181centosnode02:2181,centosnode03:2181在这里插入图片描述

创建日志目录
mkdir -p /home/hadoop/kafka/kafka_2.11-2.1.0/kafka-logs

发送安装文件到其他节点
cd /home/hadoop/bigdata/kafka
scp -r kafka_2.11-2.1.0/ hadoop@centosnode02:/home/hadoop/bigdata/kafka
scp -r kafka_2.11-2.1.0/ hadoop@centosnode03:/home/hadoop/bigdata/kafka
修改节点centosnode02的配置文件
ssh centosnode02
cd /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/config/
vi server.properties
broker.id=2
listeners=PLAINTEXT://centosnode02:9092
修改节点centosnode03的配置文件
ssh centosnode03
cd /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/config/
vi server.properties
broker.id=3
listeners=PLAINTEXT://centosnode03:9092

firewall-cmd --zone=public --add-port=9092/tcp --permanent – root账号才能执行
firewall-cmd --reload

通过配置文件启动
/home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/bin/kafka-server-start.sh -daemon /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/config/server.properties

jps
18136 Jps
18057 Kafka
表示启动成功

制作开机启动脚本(非yum方式安装,yum在线安装会自动生成脚本)
vi /usr/lib/systemd/system/kafka.service
[Unit]
Description=kafka -Server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
Environment=JAVA_HOME=/home/hadoop/java/jdk1.8.0_192
ExecStart=/home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/bin/kafka-server-start.sh -daemon /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/config/server.properties
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/home/hadoop/bigdata/kafka/kafka_2.11-2.1.0/bin/kafka-server-stop.sh
PrivateTmp=true
[Install]
WantedBy=multi-user.target

scp -r /usr/lib/systemd/system/kafka.service root@centosnode02:/usr/lib/systemd/system/
scp -r /usr/lib/systemd/system/kafka.service root@centosnode03:/usr/lib/systemd/system/
三台机器上都需要操作如下命令:
systemctl daemon-reload
systemctl enable kafka.service
systemctl start | stop | status kafka

查看系统kafka是否开机启动
systemctl list-unit-files | grep kafka

查看系统那些服务开机启动
使用 systemctl list-unit-files 可以查看启动项
左边是服务名称,右边是状态,enabled是开机启动,disabled是开机不启动

kafka.service failed to run ‘start’ task: No space left on device 启动kafka时发现这个报错
磁盘空间不够用

kafka常用命令操作实战

生产者接收用户的标准输入发送到Kafka,消费者则一直尝试从Kafka中拉取生产的数据,并打印到标准输出中,下面使用kafka命令行客户端创建主题,生产者与消费者,以及测试kafka集群是否能正常工作.
firewall-cmd --zone=public --add-port=9092/tcp --permanent
firewall-cmd --reload
cd /home/hadoop/bigdata/kafka/kafka_2.11-2.1.0
(1)创建主题
bin/kafka-topics.sh
–create
–zookeeper centosnode01:2181,centosnode02:2181,centosnode03:2181
–replication-factor 2
–partitions 2
–topic topictest

命令执行完成后日志信息如下:
Created topic “topictest”.

此时登录zookeeper(任意一个节点)中可以查看到如下信息:
[zk: localhost:2181(CONNECTED) 0] ls /
[cluster, controller_epoch, controller, brokers, zookeeper, dubbo, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]

***(2)查询主题
创建主题成功后,可以执行以下命令,查看当前kafka集群中的所有主题
bin/kafka-topics.sh
–list
–zookeeper centosnode01:2181
输出如下:
topictest
详细查看某一个主题的信息
****[hadoop@centosnode01 kafka_2.11-2.1.0]$ bin/kafka-topics.sh \

–describe
–zookeeper centos01:2181
topic topictest**
输出结果如下:
opic:topictest PartitionCount:2 ReplicationFactor:2 Configs:
Topic: topictest Partition: 0 Leader: 3 Replicas: 3,1 Isr: 3,1
Topic: topictest Partition: 1 Leader: 1 Replicas: 1,2 Isr: 1
(3)创建生产者
模拟生产者客户端
[hadoop@centosnode01 kafka_2.11-2.1.0]$ bin/kafka-console-producer.sh
–broker-list centosnode01:9092,centosnode02:9092,centosnode03:9092
–topic topictest
hello
hse
hello world
shHH
**
另外打开一个模拟consumer消费者客户端
[hadoop@centosnode01 kafka_2.11-2.1.0]$bin/kafka-console-consumer.sh
–bootstrap-server centosnode01:9092,centosnode02:9092,centosnode03:9092
–topic topictest
hse
hello world
sh**
模拟界面如下:***
在这里插入图片描述

至此,kafka集群搭建完毕!完美收官…

maven依赖

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

测试代码:
package org.jy.data.yh.bigdata.platform.kafka;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.serialization.IntegerDeserializer;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
// kafka消费者实例
public class MyKafkaConsumer {
public static void main(String[] args){
// 1.使用Properties定义配置属性
Properties properties = new Properties();
// 设置消费者Broker服务器的连接地址
properties
.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,“centosnode01:9092,centosnode02:9092,centosnode03:9092”);
// 设置key反序列化的程序,与生成者对应
properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
// 设置value反序列化的程序,与生产者对应
properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class.getName());
// 设置消费者组ID,即组名称,值可自定义,组名称相同的消费者进程属于同一个消费者组
properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG,“groupid-node”);
// 2, 定义消费者对象
Consumer<String,Integer> consumer = new KafkaConsumer<String, Integer>(properties);
// 3 设置消费者读取的主题名称,可以设置多个
consumer.subscribe(Arrays.asList(“topicTest-node”));
while(true){
// 拉取消息,并设置超时时间为10秒
ConsumerRecords<String, Integer> records = consumer.poll(Duration.ofSeconds(10));
for(ConsumerRecord<String,Integer> record : records){
// 打印消息关键消息
System.out.println("key: “+record.key()+”, value: “+record.value()+”, partition: “+record.partition()+”,offset: "+record.offset());
}
}
}
}

package org.jy.data.yh.bigdata.platform.kafka;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.IntegerSerializer;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
// kafka生产者实例
public class MyKafkaProducer {
    public static void main(String[] args){
        // 使用配置文件属性
        Properties properties = new Properties();
        // 设置生产者服务器的连接地址
        properties
        .setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"centosnode01:9092,centosnode02:9092,centosnode03:9092");
        // 设置系列化key程序类
        properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        // 设置序列化value程序类,此处不一定非得是Integer,也可以是String
        properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName());
        // 定义消息生产者对象,依靠此对象可以进行消息的传递
        Producer<String,Integer> producer = new KafkaProducer<String,Integer>(properties);
        // 循环发送10条消息
        for(int i = 0; i<100000;i++){
            producer.send(new ProducerRecord<String, Integer>("topicTest-node","这是MyKafkaProducer发送的消息"+i,i));
        }
        // 关闭生成者,释放资源
       producer.close();
    }
}

基于生产者拦截器:

package org.jy.data.yh.bigdata.platform.kafka.filter;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
// 时间戳拦截器
// 发送消息之前,在消息内容前面加入时间戳
// 定制化消息: 各种可行方案
public class KafkaTimeInterceptor implements ProducerInterceptor<String,String> {
    private static final Logger logger = LoggerFactory.getLogger(KafkaTimeInterceptor.class);
    /**
     * 该方法在消息发送前被调用
     * 将原消息记录进行修改,在消息内容最前面添加时间戳
     * @param producerRecord  生产者发送的消息记录,将自动传入
     * @return 修改后的消息记录
     */
    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
        System.out.println("KafkaTimeInterceptor-----onSend 方法被调用,消息的内容为:"+producerRecord.value());
        // 创建一条新的消息记录,将时间戳加入消息内容的最前面
        ProducerRecord<String,String> prorecord
                = new ProducerRecord<String, String>(
                        producerRecord.topic(),
                producerRecord.key(), System.currentTimeMillis()+","+ producerRecord.value().toString());
        return prorecord;
    }

    /**
     * 该方法在消息发送完毕后被调用
     * 当发送到服务器的记录已被确认,或者记录发送失败时,将调用此方法
     * @param recordMetadata
     * @param e
     */
    @Override
    public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
        logger.info("KafkaTimeInterceptor-----onAcknowledgement方法被调用:"+recordMetadata.topic());
    }
    /**
     * 当拦截器被关闭时,调用该方法
     */
    @Override
    public void close() {
        logger.info("KafkaTimeInterceptor ----- close方法被调用");
    }

    /**
     * 获取生产者的配置信息
     * @param configs
     */
    @Override
    public void configure(Map<String, ?> configs) {
        logger.info("生成者的配置信息:"+configs.get(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG));
    }
}
package org.jy.data.yh.bigdata.platform.kafka.filter;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;

/**
 * 该拦截器类与时间拦截器类似:KafkaTimeInterceptor 只是实现的业务逻辑不一样吧了
 * 可以实现多个这样的拦截器,并配置拦截器的顺序,组成拦截器链
 * 消息发送状态统计拦截器
 * 统计发送成功和失败的消息数,并在生产者关闭时打印者两个消息数
 */
public class KafkaCounterInterceptor implements ProducerInterceptor<String,String> {
    private static final Logger loggger = LoggerFactory.getLogger(KafkaCounterInterceptor.class);
    private int successCounter = 0; // 发送成功的消息数量
    private int errorCounter = 0; // 发送失败的消息数量
    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
        loggger.info("KafkaCounterInterceptor----onSend 方法被调用....");
        return producerRecord;
    }
    /**
     * 该方法在消息发送完毕后调用
     * 当发送到服务器的记录已被确认,或者记录发送失败时,将调用该方法
     * @param recordMetadata
     * @param e
     */
    @Override
    public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
        loggger.info("KafkaCounterInterceptor----onAcknowledgement方法被调用");
        // 统计成功和失败的消息
        if(e == null){
            successCounter ++;
        } else{
            errorCounter ++;
        }
    }
    /**
     * 当生产者关闭时调用该方法,可以在此方法将结果进行持久化保存
     */
    @Override
    public void close() {
        loggger.info("KakfaCounterInterceptor----拦截器被关闭时调用-----close 方法");
        // 打印统计的结果数
        System.out.println("发送成功的消息数量: " + successCounter + " 条!");
        System.out.println("发送失败的消息数量: " + errorCounter + " 条!");
    }
    /**
     * 获取生产者配置信息
     * @param configs
     */
    @Override
    public void configure(Map<String, ?> configs) {
        loggger.info("KakfaCounterInterceptor集群的配置信息:"+ configs.get(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG));
    }
}
package org.jy.data.yh.bigdata.platform.kafka.filter;
import com.google.common.collect.Lists;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.List;
import java.util.Properties;

 //生产者拦截器:
 // 向名为topicTest-node主题循环发送10条消息
public class MyKafkaFilterProducer {
    public static void main(String[] args){
         // 1.设置配置属性
        Properties properties = new Properties();
        // 设置生产者Broker服务器连接地址
       properties
        .setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"centosnode01:9092,centosnode02:9092,centosnode03:9092");
        // 设置序列化Keyd 程序
        properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        // 设置序列化Value程序
        properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());

        // 2 设置拦截器
        List<String> interceptors = Lists.newArrayList();
        // 添加拦截器KafkaTimeInterceptor (需要指拦截器的全路径名)
        interceptors.add("org.jy.data.yh.bigdata.platform.kafka.filter.KafkaTimeInterceptor");
        // 添加拦截器KafkaCounterInterceptor
        interceptors.add("org.jy.data.yh.bigdata.platform.kafka.filter.KafkaCounterInterceptor");
        // 将拦截器添加到配置属性中
        properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,interceptors);
        // 3 发送消息
        Producer<String,String> producer = new KafkaProducer<String, String>(properties);
        // 循环发送10条消息
        for (int i=0;i<10000;i++){
            // 发送消息,此方法只负责发送消息,不关心是否发送成功
            // 第一个参数: 主题的名称
            // 第二个参数: 消息的value值(消息内容)
            ProducerRecord<String, String> msg = new ProducerRecord<String, String>("topicTestFilter-node","这是kafka消息拦截器生产者产生的消息!"+i);
            producer.send(msg);
        }
        // 4 关闭生产者,释放资源
        // 调用该方法后,将触发拦截器的close()方法
        producer.close();

    }
}

package org.jy.data.yh.bigdata.platform.kafka.filter;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;

 // kafka消费者实例
public class MyKafkaFilterConsumer {
    public static void main(String[] args){
        // 1.使用Properties定义配置属性
        Properties properties = new Properties();
        // 设置消费者Broker服务器的连接地址
        properties
        .setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"centosnode01:9092,centosnode02:9092,centosnode03:9092");
        // 设置key反序列化的程序,与生成者对应
        properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        // 设置value反序列化的程序,与生产者对应
        properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        // 设置消费者组ID,即组名称,值可自定义,组名称相同的消费者进程属于同一个消费者组
        properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG,"groupFilter-node");
        // 2, 定义消费者对象
        Consumer<String,String> consumer = new KafkaConsumer<String, String>(properties);
        // 3 设置消费者读取的主题名称,可以设置多个
        consumer.subscribe(Arrays.asList("topicTestFilter-node"));
        while(true){
            // 拉取消息,并设置超时时间为10秒
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(10));
            for(ConsumerRecord<String,String> record : records){
                // 打印消息关键消息
                System.out.println("kafka-filter-key: "+record.key()+", kafka-filter-value: "+record.value()+", kafka-filter-partition: "+record.partition()+",kafka-filter-offset: "+record.offset());
            }
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值