基本概念
一个典型的 Kafka 体系架构包括若干 Producer、若干 Broker、若干 Consumer,以及一个 Zoo Keeper 集群
- Producer: 生产者,也就是发送消息的一方。生产者负责创建消息, 然后将其投递到 Kafka 中。
- Consumer:消费者,也就是接收消息的一方。消费者连接到 Kafka上并接收消息,进 而进行相应的业务逻辑处理。
- Broker:服务代理节点。对于 Kafka 而言, Broker 可以简单地看作一个独立的 Kafka 服务节点或Kafka服务实例。大多数情况下也可以将Broker看作一台 Kafka服务器,前提是这 台服务器上只部署了一个Kafka实例。一个或多个Broker组成了一个Kafka集群。一般而言, 我们更习惯使用首字母小写的broker来表示服务代理节点。
- Topic:主题,消费者发送消息往往就是发送到特定的主题
- Partition:分区,主体的下一级,一个分区只属于单个主题,同一主题下的不同分区包含的消息是不同的,分区在存储层面可以看作一个可追加的日志(Log)文件
- offset:偏移量,消息在被追加到分区日志、文件的时 候都会分配一个特定的偏移量(offset)。 offset是消息在分区中的唯一标识,Kafka通过它来保证消息在分区内的顺序性,不过offset并不跨越分区,也就是说,Kafka保证的是分区有序而不是主题有序。
- Replica:多副本,Kafka 为分区引入了多副本 (Replica) 机制, 通过增加副本数量可以提升容灾能力。同一 分区的不同副本中保存的是相同的消息(在同一时刻,副本之间并非完全一样),自1J本之间是 “一主多从”的关系,其中 leader 副本负责处理读写请求, follower 副本只负责与 leader副本的消息同步。副本处于不同的broker 中,当 leader 副本出现故障时,从 follower 副本中重新选举 新的leader 副本对外提供服务。 Kafka通过多副本机制实现了故障的自动转移,当 Kafka集群中 某个broker 失效时仍然能保证服务可用。 如图 1-3 所示, Kafka集群中有4个 broker,某个主题中有3个分区,且副本因子(即副本个数)也为3,如此每个分区便有l个leader副本和2个follower副本。生产者和消费者只与leader副本进行交互,而followr副本只负责消息的同步,很多时候 follower副本中的消息相对leader副本而言会有一定的滞后。
java代码连接kafka
简单连接测试,我们主要就是进行消息的生产和消费,先跑起来简单的
先运行消费者,然后启动生产者发送消息,如果发送成功会在消费者控制台看到发送的消息
生产者
public class FirstKafkaProducer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "101.201.52.230:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 关键配置:给够等待时间
props.put("max.block.ms", "30000"); // 最多等30秒(默认60秒,可以更大)
props.put("request.timeout.ms", "30000"); // 请求超时30秒
System.out.println("开始发送消息...");
try (KafkaProducer<String, String> producer = new KafkaProducer<>(props)) {
for(int i=0;i<10;i++){
ProducerRecord<String, String> record =
new ProducerRecord<>("test-topic", "key", "Hello Kafka!---"+i);
// 同步发送,会等待结果
producer.send(record).get();
System.out.println("消息发送成功!");
}
} catch (Exception e) {
System.err.println("发送失败: " + e.getMessage());
e.printStackTrace();
}
}
}
消费者
public class FirstKafkaConsumer {
public static final String brokerList = "101.201.52.230:9092";
public static final String topic = "test-topic";
public static final String groupId = "group.demo";
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers",brokerList);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.put("group.id",groupId);
KafkaConsumer<String,String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList(topic));
while (true){
ConsumerRecords<String,String> records = consumer.poll(Duration.ofMillis(1000));
for(ConsumerRecord<String,String> record:records){
System.out.println("consumer:"+record.value());
}
}
}
}