kafka+ubuntu20.04+docker配置

记录一次配置过程

安装docker

参加下面链接的第一部分

Ubuntu20.04使用docker安装kafka服务-CSDN博客

安装zookeeper

docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper

安装kafka服务

docker run  -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=[你的IP地址]:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://[你的IP地址]:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -t wurstmeister/kafka

改成我自己的本机的就是:

docker run  -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=192.168.147.131:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.147.131:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -t wurstmeister/kafka

进入docker

执行docker ps -a命令,查看结果如下:

 注意上述结果显示kafka和zookeeper都是已关闭状态,需要开启,使用下面的命令:docker start 容器id,即

docker start a01c
docker start c0c7

注意要先启动父容器(或者说是依赖项zookeeper),再启动子容器kafka,容器id输入前几位有区分即可,不必全部输入,也不必补全(tab不会给你补全)

执行docker ps -a命令,再次查看结果如下:

ok这就启动成功了

然后执行命令进入docker

docker exec -it [container-id] /bin/sh    #container-id就是上图中c0c7这一串数字,执行命令时只需要输入前几个数字/字母即可
cd /opt/kafka/bin    #跳转到kafka目录下的bin目录,这下面有一些可执行脚本

换成我的本机就是执行下面的命令:

docker exec -it c0c7 /bin/sh    #container-id就是上图中41b8e4db352f这一串数字,执行命令时只需要输入前几个数字/字母即可
cd /opt/kafka/bin    #跳转到kafka目录下的bin目录,这下面有一些可执行脚本

得到下面的结果:

生产者消费者模式初体验

启动生产者

注意下面的ip:192.168.147.131要和你本机ip一致,使用ifconfig命令查看

./kafka-console-producer.sh --broker-list 192.168.147.131:9092 --topic wxj

打开另一个终端,启动消费者

 注意ip要一致,topic要一致

docker exec -it c0c7 /bin/sh
cd /opt/kafka/bin
./kafka-console-consumer.sh --bootstrap-server 192.168.147.131:9092 --topic wxj

运行效果如下:

其他一点别的,就是常识啦,比如如何退出生产者消费者的环境,ctrl+c,ctrl+d都试试,如何退出容器,可以试试输入exit命令

ok 完事了,还是去探索腾讯云的kafka服务吧

常用命令行命令

首先进入kafka容器的环境中

docker exec -it c0c7 /bin/sh
cd /opt/kafka/bin

kafka-topics.sh

对主题topic进行增删改查的工具

常用选项如下:

--bootstrap-server:kafka服务器ip:port,需要查询指定的topic或者topic列表,必须指定这个量
--create:创建主题
--delete:删除主题
--describe:描述主题
--list:查看主题列表
--alter:修改主题的 partitions等
--topic <String: topic>:主题名
--topic-id <String: topic-id>:主题id
--partitions <Integer: # of partitions>:主题的partition


新增

命令

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --create --topic wxj2

效果

查看topic列表

命令

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --list

效果

查看topic详情(描述)

命令

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --describe --topic wxj2

效果

修改

命令
以修改主题partiion数量为例

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --alter --topic wxj2 --partitions 3

再次查看topic的描述发现分区完成 

删除

命令

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --delete --topic wxj2

kafka-console-producer.sh

标准输入读数据,发送到Kafka的工具

常用选项如下:

--bootstrap-server:kafka服务器ip:port,必须的
--topic <String: topic> :Kafka主题,必须的
--sync:同步发送
--compression-codec [String: compression-codec] :压缩方式,‘none’,‘gzip’, ‘snappy’, ‘lz4’, , ‘zstd’,默认gzip.
 

使用示例

kafka-topics.sh --bootstrap-server=127.0.0.1:9092 --create --topic demo
kafka-console-producer.sh  --bootstrap-server=127.0.0.1:9092 --topic demo

kafka-console-consumer.sh

常用选项如下:

--bootstrap-server:kafka服务器ip:port,必须的
--topic <String: topic> :Kafka主题,必须的
--group <String: consumer group id>:消费者组id
--key-deserializer <String: deserializer for key>:key反序列化,默认是org.apache.kafka.common.serialization.StringDeserializer
--value-deserializer <String: deserializer for values>:value反序列化,默认是org.apache.kafka.common.serialization.StringDeserializer
--offset <String: consume offset>:消费的offset
--partition <Integer: partition>:消费的分区
 

使用示例

kafka-console-consumer.sh  --bootstrap-server=127.0.0.1:9092 --topic demo
kafka-console-consumer.sh  --bootstrap-server=127.0.0.1:9092 --topic demo --partition 0 --offset 2

上述命令的使用方法是进入到了docker容器kafka中了,要是不想进入环境直接运行命令的示例是

docker exec -it c0c7 /opt/kafka/bin/kafka-topics.sh  --bootstrap-server=127.0.0.1:9092 --create --topic demo

效果:

Kafka+IDEA+Maven

具体详细情况参见我自己写的kafka进阶博客

http://t.csdnimg.cn/0s80b

此处连接的是上述虚拟机中安装的kafka,故使用前需要开启服务

生产者

普通消费者

package com.tjut.kafka.producer;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;

public class CustomProducer {
    public static void main(String[] args) {
        //创建kafka生产者对象
        //""  "hello"
        //属性配置
        Properties properties = new Properties();
        //连接集群
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.147.131:9092");

        //指定对应的key和value的序列化类型
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());


        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);

        //发送数据
        for (int i=0;i<5;i++) {
            kafkaProducer.send(new ProducerRecord<>("first", "wxj"+i));
        }
        //关闭资源
        kafkaProducer.close();
    }
}

带有返回值的生产者(CallBack)

package com.tjut.kafka.producer;

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;

public class CustomProducerCallBack {
    public static void main(String[] args) {
        //创建kafka生产者对象
        //""  "hello"
        //属性配置
        Properties properties = new Properties();
        //连接集群
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.147.131:9092");

        //指定对应的key和value的序列化类型
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());


        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);

        //发送数据
        for (int i=10;i<15;i++) {
            kafkaProducer.send(new ProducerRecord<>("first", "wxj" + i), new Callback() {
                @Override
                public void onCompletion(RecordMetadata recordMetadata, Exception e) {
                    if(e==null){
                        System.out.println("主题:"+recordMetadata.topic());
                        System.out.println("分区:"+recordMetadata.partition());
                    }
                }
            });
        }
        //关闭资源
        kafkaProducer.close();
    }
}

同步方式(多了get)

package com.tjut.kafka.producer;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;
import java.util.concurrent.ExecutionException;

public class CustomProducerSync {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建kafka生产者对象
        //""  "hello"
        //属性配置
        Properties properties = new Properties();
        //连接集群
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.147.131:9092");

        //指定对应的key和value的序列化类型
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());


        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);

        //发送数据
        for (int i=0;i<5;i++) {
            //多了get
            kafkaProducer.send(new ProducerRecord<>("first", "wxj"+i)).get();
        }
        //关闭资源
        kafkaProducer.close();
    }
}

使用事务的方式

package com.tjut.kafka.producer;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;

public class CustomProducerTransaction {
    public static void main(String[] args) {
        //创建kafka生产者对象
        //""  "hello"
        //属性配置
        Properties properties = new Properties();
        //连接集群
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.147.131:9092");

        //指定对应的key和value的序列化类型
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());

        //设置事务id
        properties.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG,"transaction_id_0");


        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);

        // 初始化事务
        kafkaProducer.initTransactions();
        // 开启事务
        kafkaProducer.beginTransaction();

        try {
            //发送数据
            for (int i=0;i<5;i++) {
                kafkaProducer.send(new ProducerRecord<>("first", "wxj"+i));
            }
//            int i = 1 / 0;
            //提交事务
            kafkaProducer.commitTransaction();
        }catch (Exception e){
            System.out.println("事务终止!!!");
            //终止事务
            kafkaProducer.abortTransaction();
        }finally {
            //关闭资源
            kafkaProducer.close();
        }
    }
}

消费者

package com.tjut.kafka.consumer;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Properties;

public class CustomerConsumer {
    public static void main(String[] args) {
        //创建kafka生产者对象
        //""  "hello"
        //属性配置
        Properties properties = new Properties();
        //连接集群,必须
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.147.131:9092");

        //指定对应的key和value的序列化类型,必须
        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

        // 配置消费者组(组名任意起名) 必须
        properties.put(ConsumerConfig.GROUP_ID_CONFIG, "test");

        KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);
        // 消费某个主题的某个分区数据,assign方式
        ArrayList<TopicPartition> topicPartitions = new  ArrayList<TopicPartition>();
        topicPartitions.add(new TopicPartition("first", 0));
        kafkaConsumer.assign(topicPartitions);

        // 注册要消费的主题(可以消费多个主题),subscribe方式
//        ArrayList<String> topics = new ArrayList<String>();
//        topics.add("first");
//        // 消息订阅
//        kafkaConsumer.subscribe(topics);

        // 拉取数据打印
        while (true) {
            // 设置 1s 中消费一批数据
            ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(Duration.ofSeconds(1));
            // 打印消费到的数据
            for (ConsumerRecord<String, String> consumerRecord :consumerRecords) {
                System.out.println(consumerRecord);
            }
        }
//        //关闭资源
//        kafkaConsumer.close();
    }
}

注意,集合订阅的方式subscribe和指定分区的订阅方式assign分表代表了两种不同的订阅状态。然而这两种状态是互斥的, 在一个消费者中只能使用其中的一种,否则会报出IllegalStateException 异常:

java.lang.IllegalStateException : Subscription to topics , partitions and patter are mutually exclusive.

参考解读:Kafka-消费者订阅主题和取消订阅_consumer is not subscribed to any topics or assign-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值