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("localhost:9092")
private String kafkaServer;
@Value("defaultGroup")
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("test")
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="test",containerFactory="kafkaListenerContainerFactory")
public void consumer(String message){
System.out.println("receiveMaching1:"+ message);
}
}
4.5 调用生产者Controller
package com.kafka.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class KafkaController {
@Autowired
private KafkaSender kafkaSender;
@RequestMapping(value = "send",method = RequestMethod.GET)
public String send(String type){
kafkaSender.sendTest();
return "OK";
}
}