应用场景:
代码示例:
public class KafkaDemo {
public static void main(String[] args) {
//1.创建生产者
KafkaProducer<String, String> producer = new KafkaProducer<>(getProperties());
//2.创建消息
ProducerRecord<String, String> record = new ProducerRecord<>("myTopic", "key", "value");
try {
//3.发送消息
producer.send(record).get();
System.out.println("Sent message successfully");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
//4.关闭连接
producer.close();
}
}
/**
* 获取Kafka配置信息
*
* @return 配置信息
*/
private static Properties getProperties() {
Properties props = new Properties();
//设置Kafka地址
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
//设置消息Key和Value的序列化方式
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
return props;
}
}
Kafka生产者将数据以消息的形式发送到Kafka集群。生产者可以将消息发送到一个指定的主题(topic),也可以选择在发送时指定分区(partition)。当生产者需要发送消息时,它先与Kafka集群上的一个Broker建立TCP连接,然后将消息发送到该Broker。
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KafkaProducerExample {
public static void main(String[] args) throws InterruptedException {
// 配置Kafka生产者属性
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 创建Kafka生产者实例
Producer<String, String> producer = new KafkaProducer<>(props);
// 发送消息到指定主题
for (int i = 0; i < 10; i++) {
producer.send(new ProducerRecord<>("my-topic", Integer.toString(i), "Hello World-" + i));
Thread.sleep(1000); // 每秒发送一条消息
}
producer.close(); // 关闭Kafka生产者实例
}
}
Kafka消费者从Kafka集群中的一个或多个分区中消费消息。消费者可以随时订阅一个或多个主题,并在每个主题中定位到特定分区。
import org.apache.kafka.clients.consumer.*;
import java.util.Collections;
import java.util.Properties;
public class KafkaConsumerExample {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "my-group"); // 与生产者所在的组相同
props.put("enable.auto.commit", "true"); // 自动提交偏移量
props.put("auto.commit.interval.ms", "1000"); // 自动提交偏移量的时间间隔
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// 创建Kafka消费者实例
Consumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("my-topic")); // 订阅指定主题
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
// 处理消息
System.out.printf("offset=%d, key=%s, value=%s%n", record.offset(), record.key(), record.value());
}
}
// consumer.close();
}
}
Kafka的主题(topic)是Kafka用于区分消息类型和类别的单位。每个主题都由一个或多个分区(partition)组成,分区是存储在Kafka集群中不同节点上的数据容器。每个主题的消息可以分布在不同的分区中。
Kafka的副本机制是为了保证消息的高可用性和数据的持久性。当一个分区的消息被发送到Kafka集群后,它会被复制到多个副本(replica)中。每个分区都有一个或多个副本,其中有且仅有一个被标记为“首领副本”(leader replica),负责读写该分区的数据。其他副本被称为“追随者副本”(follower replica),它们只能复制首领副本的数据,并借此提高系统的可靠性和容错性。
消息发送者将消息发送到Kafka主题(topic),然后由Kafka Producer将消息分区并写入到Broker中的指定分区中。在发送消息之前,Producer需要从Zookeeper中获取集群元数据信息,包括Broker列表和主题分区的信息。具体流程如下:
消息发送者通过Producer API将消息发送到指定topic中。
String topic = "test_topic";
String message = "Hello, Kafka!";
ProducerRecord<String, String> record = new ProducerRecord<>(topic, message);
producer.send(record);
Producer根据消息的key值使用Partitioner算法将同一个key的消息发送到同一个分区里,保证消息的有序性。
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes,
Cluster cluster) {
int numPartitions = cluster.partitionCountForTopic(topic);
if (keyBytes == null) {
Random random = new Random();
return random.nextInt(numPartitions);
}
int hash = Utils.murmur2(keyBytes);
return hash % numPartitions;
}
Producer将记录存储在缓冲区中,如果缓冲区已满,则会调用send方法将缓冲区中的内容批量发送到Broker中。
消息被存储在Broker的一个或多个分区中,分区中的每条消息都有一个唯一的偏移量(offset),并按照其他参数(如消息的时间戳)进行排序存储。当Consumer消费分区中的消息时,可以根据偏移量来读取消息,保证消息的顺序性。
在Broker上保存的消息是以一种高效而紧凑的格式进行编码的,称为RecordBatch,它可以将多个Producer的相关记录分组在一起,以便有效地压缩提交到Broker的数据传输量。
Consumer订阅并读取特定主题(topic)的消息。消费者(Consumer)从Broker中拉取特定分区的消息,并对其进行处理。具体流程如下:
消费者向Kafka集群发送Fetch请求,获取数据。
Broker收到Fetch请求后,从指定的分区和偏移量(offset)开始读取消息,然后将数据返回给Consumer。
Consumer获取到数据后,进行处理和消费,同时记录每个Partition的下一个可拉取的偏移量,并定期将其提交到Zookeeper中,用于在Consumer发生故障或重启后重新读取未被处理的消息。
String topicName = "test_topic";
String groupId = "test_group";
Properties props = new Properties();
props.setProperty("bootstrap.servers", "localhost:9092");
props.setProperty("group.id", groupId);
props.setProperty("auto.commit.enable", "false");
props.setProperty("auto.offset.reset", "earliest");
props.setProperty("key.deserializer", StringDeserializer.class.getName());
props.setProperty("value.deserializer", StringDeserializer.class.getName());
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList(topicName));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s%n",
record.offset(), record.key(), record.value());
}
consumer.commitSync();
}
以下是Kafka Producer端实现批量写入消息的Java代码示例:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KafkaProducerSample {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("batch.size", 16384);
Producer<String, String> producer = new KafkaProducer<>(props);
String topic = "myTopic";
for (int i = 0; i < 10000; i++) {
String msg = "My message No." + i;
ProducerRecord<String, String> record = new ProducerRecord<String, String>(topic, msg);
producer.send(record);
}
producer.close();
}
}
Kafka是一个开源的分布式消息系统,在大数据领域有着广泛的应用。下面介绍Kafka的三个应用案例。
网络爬虫的核心功能是从互联网上抓取数据并进行分析或保存。Kafka可以作为网络爬虫的消息队列,负责将被爬取数据传输给爬虫程序。当网络爬虫处理完数据后,将数据发送到Kafka中,供后续处理程序使用。
具体实现时,需要先创建一个名为spider
的Kafka主题,然后在爬虫程序中编写生产者代码,将爬取到的数据发送至该主题。以下是Java示例代码:
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class SpiderProducer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer =
new KafkaProducer<String, String>(props);
for(int i = 0; i < 100; i++)
producer.send(new ProducerRecord<String, String>(
"spider", Integer.toString(i), "data-" + Integer.toString(i)));
producer.close();
}
}
Kafka除了可以作为消息队列,还可以作为数据缓存,可以处理大量的数据流。在数据统计过程中,Kafka既可以作为生产者将收集到的数据发送到主题中,也可以作为消费者从主题中获取数据并进行分析、统计等操作。具体实现时,需要先创建一个名为data
的Kafka主题,然后在收集数据的程序中编写生产者代码,将数据发送至该主题。再在处理数据的程序中编写消费者代码,从该主题中获取数据以完成数据统计。
以下是Java示例代码:
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
import java.util.Properties;
public class DataConsumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer =
new KafkaConsumer<String, String>(props);
consumer.subscribe(Arrays.asList("data"));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records)
System.out.printf("offset = %d, key = %s, value = %s\n",
record.offset(), record.key(), record.value());
}
}
}
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class DataProducer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer =
new KafkaProducer<String, String>(props);
for(int i = 0; i < 100; i++)
producer.send(new ProducerRecord<String, String>(
"data", Integer.toString(i), "data-" + Integer.toString(i)));
producer.close();
}
}
Kafka可以在实时监控中作为传输媒介,将源数据流发送到消费者,以满足分布式的需求。具体实现时,需要先创建一个名为metrics
的Kafka主题,然后在生产者程序中将监控数据发送至该主题。再在监控中心中编写消费者代码,从该主题中获取数据并进行分析、监控等操作。
以下是Java示例代码:
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
import java.util.Properties;
public class MetricsConsumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer =
new KafkaConsumer<String, String>(props);
consumer.subscribe(Arrays.asList("metrics"));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records)
System.out.printf("offset = %d, key = %s, value = %s\n",
record.offset(), record.key(), record.value());
}
}
}
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class MetricsProducer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer =
new KafkaProducer<String, String>(props);
for(int i = 0; i < 100; i++)
producer.send(new ProducerRecord<String, String>(
"metrics", Integer.toString(i), "metrics-" + Integer.toString(i)));
producer.close();
}
}