1.前言:
本文只是簡單介紹如何搭建kafka,關於kafka的詳細內容,此文暫時不講。
2.Kafka簡介
Kafka是分佈式發佈-訂閱消息系統,它最初由 LinkedIn 公司開發,使用 Scala語言編寫,之後成爲 Apache 項目的一部分。在Kafka集羣中,沒有“中心主節點”的概念,集羣中所有的服務器都是對等的,因此,可以在不做任何配置的更改的情況下實現服務器的的添加與刪除,同樣的消息的生產者和消費者也能夠做到隨意重啓和機器的上下線。
2.1.Kafka術語介紹
1.消息生產者:即:Producer,是消息的產生的源頭,負責生成消息併發送到Kafka服務器上。
2.消息消費者:即:Consumer,是消息的使用方,負責消費Kafka服務器上的消息。
3.主題:即:Topic,由用戶定義並配置在Kafka服務器,用於建立生產者和消息者之間的訂閱關係:生產者發送消息到指定的Topic下,消息者從這個Topic下消費消息。
4.消息分區:即:Partition,一個Topic下面會分爲很多分區,例如:“kafka-test”這個Topic下可以分爲6個分區,分別由兩臺服務器提供,那麼通常可以配置爲讓每臺服務器提供3個分區,假如服務器ID分別爲0、1,則所有的分區爲0-0、0-1、0-2和1-0、1-1、1-2。Topic物理上的分組,一個 topic可以分爲多個 partition,每個 partition 是一個有序的隊列。partition中的每條消息都會被分配一個有序的 id(offset)。
5.Broker:即Kafka的服務器,用戶存儲消息,Kafa集羣中的一臺或多臺服務器統稱爲 broker。
6.消費者分組:Group,用於歸組同類消費者,在Kafka中,多個消費者可以共同消息一個Topic下的消息,每個消費者消費其中的部分消息,這些消費者就組成了一個分組,擁有同一個分組名稱,通常也被稱爲消費者集羣。
7.Offset:消息存儲在Kafka的Broker上,消費者拉取消息數據的過程中需要知道消息在文件中的偏移量,這個偏移量就是所謂的Offset。
3.搭建Kafka
3.1. 安裝JDK
3.1.1 安裝文件:http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html下載Server JRE.
3.1.2 安裝完成後需要添加以下的環境變量(右鍵點擊“我的電腦” -> "高級系統設置" -> "環境變量" ):
<1>.JAVA_HOME: C:\Program Files (x86)\Java\jre1.8.0_60(這個是默認安裝路徑,如果安裝過程中更改了安裝目錄,把更改後的路徑填上就行了)
<2>.PATH: 在現有的值後面添加"; %JAVA_HOME%\bin"
3.1.3 打開cmd運行 "java -version" 查看當前系統Java的版本:
3.2. 安裝Zookeeper
Kafka的運行依賴於Zookeeper,所以在運行Kafka之前我們需要安裝並運行Zookeeper
3.2.1 下載安裝文件: http://zookeeper.apache.org/releases.html
3.2.2 解壓文件(本文解壓到 D:\Software\Devolopment\zookeeper-3.4.14)
3.2.3 打開D:\Software\Devolopment\zookeeper-3.4.14\conf,把zoo_sample.cfg重命名成zoo.cfg
3.2.4 從文本編輯器裏打開zoo.cfg
3.2.5 把dataDir的值改成“D:\Software\Devolopment\zookeeper-3.4.14\data”
3.2.6 添加如下系統變量:
<1>.ZOOKEEPER_HOME: D:\Software\Devolopment\zookeeper-3.4.14
<2>.Path: 在現有的值後面添加";%ZOOKEEPER_HOME%\bin;"
3.2.7 運行Zookeeper: 打開cmd然後執行zkserver
3.3. 安裝並運行Kafka
3.3.1 下載安裝文件: http://kafka.apache.org/downloads.html
3.3.2 解壓文件(本文解壓到 D:\Software\Devolopment\kafka_2.12-0.10.2.2)
3.3.3 打開D:\Software\Devolopment\kafka_2.12-0.10.2.2\config
3.3.4 從文本編輯器裏打開 server.properties
3.3.5 把log.dirs的值改成 “D:\Software\Devolopment\kafka_2.12-0.10.2.2\kafka-logs”
3.3.6 打開cmd
3.3.7 進入kafka文件目錄: cd /d D:\Software\Devolopment\kafka_2.12-0.10.2.2
3.3.8 輸入並執行以打開kafka:
.\bin\windows\kafka-server-start.bat .\config\server.properties
3.4. 創建topics
3.4.1 打開cmd 並進入D:\Software\Devolopment\kafka_2.12-0.10.2.2\bin\windows
3.4.2 創建一個topic:
kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
3.5.打開一個Producer:
cd D:\Software\Devolopment\kafka_2.12-0.10.2.2\bin\windows
kafka-console-producer.bat --broker-list localhost:9092 --topic test
3.6. 打開一個Consumer:
cd D:\Software\Devolopment\kafka_2.12-0.10.2.2\bin\windows
kafka-console-consumer.bat --zookeeper localhost:2181 --topic test
然後就可以在Producer控制檯窗口輸入消息了。在消息輸入過後,很快Consumer窗口就會顯示出Producer發送的消息。
Kafka運行環境的搭建就完成了。
4.代碼實現
需要建一個springboot項目,並導入相關依賴。
4.1 添加依賴
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
4.2 配置
package com.example.kafka.kafka2;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.core.*;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableKafka
public class KafkaConfig {
@Value("${spring.kafka.server}")
private String kafkaServer;
@Value("${spring.kafka.group}")
private String kafkaGroup;
public Map<String, Object> consumerConfig(String consumerGroupId){
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer);
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroupId);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
return props;
}
public ConsumerFactory<String, String> consumerFactory(String consumerGroupId) {
return new DefaultKafkaConsumerFactory<>(consumerConfig(consumerGroupId));
}
public Map<String, Object> producerConfig(){
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer);
props.put(ProducerConfig.RETRIES_CONFIG, 0);
props.put(ProducerConfig.BATCH_SIZE_CONFIG, 1000);
props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 40960);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return props;
}
public ProducerFactory<String, String> producerFactory(){
return new DefaultKafkaProducerFactory<>(producerConfig());
}
@Bean(name="kafkaListenerContainerFactory")
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory(kafkaGroup));
factory.setConcurrency(3);
factory.getContainerProperties().setPollTimeout(3000);
return factory;
}
@Bean
public KafkaTemplate<String, String> kafkaTemplate() {
return new KafkaTemplate<String, String>(producerFactory());
}
}
4.3 生產者
package com.example.kafka.kafka2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class KafkaSender {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
@Value("${spring.kafka.topic}")
private String topic;
private int index;
public void sendTest(){
String msg = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
kafkaTemplate.send(topic,"hello,kafka"+index + ":" + msg);
System.out.println("hello,kafka"+index + ":" + msg);
index ++;
}
}
4.4 消費者
package com.example.kafka.kafka2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.DependsOn;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@Component
public class KafkaConsumer {
/**
* 監聽test主題,有消息就讀取
* @param message
*/
@KafkaListener(topics="${spring.kafka.topic}",containerFactory="kafkaListenerContainerFactory")
public void consumer(String message){
System.out.println("receiveMaching1:"+ message);
}
}