Kafka消息隊列學習筆記(2020.3.20)

Kafka消息隊列學習筆記(2020.3.20)

前言:

kafka官網(點擊打開) Kafka 中文文檔

1. 什麼是 Kafka

Kafka 用於構建實時數據管道和流應用。它具有水平可伸縮性,容錯性,快速快速性。

1.1 Kafka 核心功能

  • 發佈 / 訂閱 - 發佈 / 訂閱類似於一個消息系統,讀寫流式的數據
  • 流處理 - 編寫可擴展的流處理應用,用於實時事件響應
  • 存儲 - 將流式數據存儲在一個分佈式、有副本的集羣中

1.2 Kafka的特性

Kafka 有什麼優點, 爲什麼使用Kafka而不使用其他消息隊列中間件呢? Kafka 具有如下特性:

  • 伸縮性 - 隨着數據量增長,可以通過對 Broker 集羣水平擴展來提高系統性能。
  • 高性能 - 通過橫向擴展生產者、消費者(通過消費者羣組實現)和 Broker(通過擴展實現系統伸縮性)可以輕鬆處理巨大的消息流。
  • 消息持久化 - Kafka 將所有的消息存儲到磁盤,並在結構中對它們進行排序,以便利用順序磁盤讀取,所以消息不會丟失。

1.3 Kafka具有四個核心API

  • Producer API (生產者) - 允許一個應用程序發佈的流式數據至一個或多個 Kafka的主題(topics)。
  • Consumer API (消費者) - 允許一個應用程序訂閱一個或多個 Kafka Topic(主題),並且對發佈給他們的流式數據進行處理。
  • Streams API (流處理器) -允許一個應用程序作爲一個流處理器,從一個或多個主題消耗的輸入流,併產生一個輸出流到一個或多個 Kafka Topic(主題),在輸入輸出流中進行有效的轉換。
  • Connector API (連接器) - 允許構建並運行可重用的生產者或者消費者連接Kafka Topic(主題),將 Kafka Topic 連接到已存在的應用程序或數據庫。例如,連接到一個關係型數據庫,捕捉表的所有變更內容。

其他詳細介紹在官網介紹有!

2. 快速入門開始 (kafka版本是2.4.1)

2.1 下載Kafka代碼 (在Windows下安裝使用Kafka)

Kafka控制腳本在Unix和Windows平臺有所不同,在Windows平臺,請使用 bin\windows\ 而不是bin/, 並將腳本擴展名改爲.bat.

2.2 啓動服務器(windows版)

Kafka 使用 ZooKeeper 如果你還沒有ZooKeeper服務器,你需要先啓動一個ZooKeeper服務器。 您可以通過與kafka打包在一起的便捷腳本來快速簡單地創建一個單節點ZooKeeper實例。

2.3 windows系統上啓動kafka打包一起的 ZooKeeper,

進到kafka_2.11-2.4.1\bin\windows目錄下,運行cmd窗口。

備註: ..\..\config\zookeeper.properties: 代表zookeeper配置文件在此目錄下

D:\Mykafka\kafka_2.11-2.4.1\bin\windows>zookeeper-server-start.bat ..\..\config\zookeeper.properties
[2020-03-20 15:01:37,495] INFO Reading configuration from: config/zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
.................

2.4 啓動kafka

依舊在目錄下打開cmd,執行命令kafka-server-start.bat ..\..\config\server.properties

D:\Mykafka\kafka_2.11-2.4.1\bin\windows>kafka-server-start.bat ..\..\config\server.properties
[2020-03-20 15:01:47,028] INFO Verifying properties (kafka.utils.VerifiableProperties)
[2020-03-20 15:01:47,051] INFO Property socket.send.buffer.bytes is overridden to 1048576 (kafka.utils.VerifiableProperties)
.....

如果遇到命令語法不正確,需要修改config文件夾下的zookeeper.properties中dataDir=server.properties中的log.dirs=。 注意盤符命令使用 \\

例如: dataDir=D:\\Mykafka\\kafka_2.11-2.4.1\\tmp\\zookeeper

log.dirs=D:\\Mykafka\\kafka_2.11-2.4.1\\tmp\\kafka-logs

到此就啓動成功了!

2.5 創建kafka的topic(主題)

創建一個名爲“mykafkaDemo”的topic,它有一個分區和一個副本:

依舊在\bin\windows目錄下打開cmd

windows>kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic mykafkaDemo
Created topic mykafkaDemo. #創建成功後輸出

zookeeper localhost:2181 是指定zookeeper地址和端口

這條命令會創建一個名爲mykafkaDemo的topic,有1個分區,每個分區需分配1個副本。

或者,您也可將代理配置爲:在發佈的topic不存在時,自動創建topic,而不是手動創建。

現在我們可以運行list(列表)命令來查看這個topic:

windows>kafka-topics.bat --list --zookeeper localhost:2181
mykafkaDemo #成功後輸出

2.6 發送一些消息

Kafka自帶一個命令行客戶端,它從文件或標準輸入中獲取輸入,並將其作爲message(消息)發送到Kafka集羣。默認情況下,每行將作爲單獨的message發送。

運行 producer.bat,然後在控制檯輸入一些消息以發送到服務器。

windows>kafka-console-producer.bat --broker-list localhost:9092 --topic mykafkaDemo
This is a message
This is another message

如果生產者進程報錯:

[2020-03-20 16:33:47,934] WARN Bootstrap broker 127.0.0.1:9092 disconnected (org.apache.kafka.clients.NetworkClient)

參考: Leader Not Available Kafka in Console Producer

config/server.properties 添加以下行:

listeners=PLAINTEXT://localhost:9092
  • 無需更改advertised.listeners,因爲它從std偵聽器屬性中獲取了值。

2.7 啓動一個consumer

Kafka 還有一個命令行consumer(消費者),將消息轉儲到標準輸出。

windows>kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic mykafkaDemo --from-beginning

3. java原態方式操作kafka

並沒使用到spring封裝操作的kafka

3.1 依賴:

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

3.2 發送消息

生產者的配置

		// 指定生產者的配置
        Properties properties = new Properties();
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        properties.put(ProducerConfig.ACKS_CONFIG, "all");
        properties.put(ProducerConfig.RETRIES_CONFIG, 0);
        properties.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
        properties.put(ProducerConfig.LINGER_MS_CONFIG, 1);
        properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
                "org.apache.kafka.common.serialization.StringSerializer");
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
                "org.apache.kafka.common.serialization.StringSerializer");
		//使用配置初始化 Kafka 生產者
        Producer<String,String> producer = new KafkaProducer<>(properties);

發送並忽略返回

ProducerRecord<String,String> record = null;
        try {
            for (int i = 0; i < 100; i++) {
            record = new ProducerRecord<>("mykafkaDemo","message"+i,message+i);
            producer.send(record);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            producer.close();
        }

同步發送和上面例子區別在於多了一個 get 方法,會一直阻塞等待 Broker 返回結果。

ProducerRecord<String,String> record = null;
        try {
            for (int i = 0; i < 100; i++) {
                record = new ProducerRecord<>("mykafkaDemo","message"+i,message+i);
                producer.send(record).get();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            producer.close();
        }

異步發送,相對於其他方式,異步發送在異步返回時可以執行一些操作,如記錄錯誤或者成功日誌

ProducerRecord<String,String> record = null;
        try {
            for (int i = 0; i < 100; i++) {
                record = new ProducerRecord<>("mykafkaDemo","message"+i,message+i);
                //使用 send 方法發送異步消息
                producer.send(record, new Callback() {
                    @Override
                    public void onCompletion(RecordMetadata metadata, Exception exception) {
                        System.out.println(metadata.toString());
                        System.out.println(exception.getMessage());
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            producer.close();
        }

到此發送消息結束。

3.3 消費消息

消費流程:

  1. 創建消費者。
  2. 訂閱主題。除了訂閱主題方式外還有使用指定分組的模式,但是常用方式都是訂閱主題方式。
  3. 輪詢(監聽)消息。通過 poll 方法輪詢。
  4. 關閉消費者。在不用消費者之後,會執行 close 操作。close 操作會關閉 socket,並觸發當前消費者羣組的再均衡。
 /** 
     * 創建並獲取消費者
     *
     * @return KafkaConsumer
     * @author: zhihao
     * @date: 2020/3/20 
     */
    public KafkaConsumer<String, String> getConsumer(){
        Properties properties = new Properties();
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"localhost:9092");
        properties.put(ConsumerConfig.GROUP_ID_CONFIG,"test");
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"true");
        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG,"1000");
        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
        //創建kafka消費者
        KafkaConsumer<String,String> consumer = new KafkaConsumer<>(properties);
        //訂閱主題方式
        consumer.subscribe(Arrays.asList("mykafkaDemo"));
        return consumer;
    }

    /**
     * 訂閱主題方式 -消費消息
     *
     * @author: zhihao
     * @date: 2020/3/20
     */
    @Test
    public void consumeMessage(){
         //訂閱主題方式
        KafkaConsumer<String, String> consumer= this.getConsumer();
        consumer.subscribe(Arrays.asList("mykafkaDemo"));
        try {
            while (true) {
                // 接受消息
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : records)
                    System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //關閉消息
            consumer.close();
        }
    }

消費消息方式

分爲訂閱主題和指定分組兩種方式:

  • 消費者分組模式。通過訂閱主題方式時,消費者必須加入到消費者羣組中,即消費者必須有一個自己的分組;
  • 獨立消費者模式。這種模式就是消費者是獨立的不屬於任何消費者分組,自己指定消費那些 Partition

1、訂閱主題方式, 上面的例子。

consumer.subscribe(Arrays.asList(topic));

2、獨立消費者模式

通過 consumer 的 assign(Collection partitions) 方法來爲消費者指定分區。

/**
     * 獨立消費消息
     *
     * @author: zhihao
     * @date: 2020/3/20
     */
    @Test
    public void consumeMessageS(){
        // 1.構建KafkaCustomer
        KafkaConsumer<String, String> consumer = this.getConsumer();
        // 2.指定分區
        // 2.1獲取可用分區
        List<PartitionInfo> partitionInfoList = consumer.partitionsFor("mykafkaDemo");
        // 2.2指定分區,這裏是指定了所有分區,也可以指定個別的分區
        if(null != partitionInfoList){
            List<TopicPartition> partitions = new ArrayList();
            for(PartitionInfo partitionInfo : partitionInfoList){
                partitions.add(new TopicPartition(partitionInfo.topic(),partitionInfo.partition()));
            }
            consumer.assign(partitions);
        }

        try {
            while (true) {
                // 接受消息
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : records)
                    System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
                // 異步提交
                consumer.commitAsync();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //關閉消息
            consumer.close();
        }
    }

到此叫學習結束了,一般我們都不會使用原生態的操作方式。

1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章