有关 kafka 的各个问题

1.kafka 中的数据是有序的吗?  kafka 中分区消息的有序性 

kafka 中的数据是有序的。

单分区内有序,多分区,分区与分区间无序;

1、一个分区,消费者将消息全部写入一个分区中,一个消费者进行消费。

2、自定义分区器 Partitioner ,重写 partition 方法,将消息顺序追加到 K 个分区,然后在消费者写 K 个内存队列,相同分区号的数据都存到一个内存 Queue 中,N 个线程分别消费一个内存队列即可

2.kafka 的分区分配策略

在 Kafka 内部存在两种默认的分区分配策略:Range 和 RoundRobin。

Range 是默认策略。Range 是对每个 Topic 而言的(即一个 Topic 一个 Topic 分),首先对同一个 Topic 里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。然后用 Partitions 分区的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。

例如:我们有 10 个分区,两个消费者(C1,C2),3 个消费者线程,10 / 3 = 3 而且除不尽。

C1-0 将消费 0, 1, 2, 3 分区

C2-0 将消费 4, 5, 6 分区

C2-1 将消费 7, 8, 9 分区

RoundRobin:前提:同一个 Consumer Group 里面的所有消费者的 num.streams(消费者消费线程数)必须相等;每个消费者订阅的主题必须相同。

第一步:将所有主题分区组成 TopicAndPartition 列表,

然后对 TopicAndPartition 列表按照 hashCode 进行排序,最后按照轮询的方式发给每一个消费线程。

3 如果 kafka 挂掉了,

    flume 有记录

    日志有记录

    短期也是不影响的

4.kafka 的数据积压问题

      如果是 Kafka 消费能力不足,则可以考虑增加 Topic 的分区数,并且同时提升消费组的消费者数量,消费者数 = 分区数。(两者缺一不可)

      如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据 / 处理时间 < 生产速度),使处理的数据小于生产的数据,也会造成数据积压。

8)多少个 Topic

     通常情况:多少个日志类型就多少个 Topic。也有对日志类型进行合并的。

9)Kafka 丢不丢数据

Ack=0,producer 不等待 kafka broker 的 ack,一直生产数据。

Ack=1,leader 数据落盘就发送 ack,producer 收到 ack 才继续生产数据。

Ack=-1,ISR 中的所有副本数据罗盘才发送 ack,producer 收到 ack 才继续生产数据。

12)Kafka 中数据量计算

每天总数据量 100g,每天产生 1 亿条日志, 10000 万 /24/60/60=1150 条 / 每秒钟

平均每秒钟:1150 条

低谷每秒钟:400 条

高峰每秒钟:1150 条 *(2-20 倍)=2300 条 -23000 条

每条日志大小:0.5k-2k

每秒多少数据量:2.3M-20MB

### Spring Boot 整合 Kafka 配置教程 #### 1. 添加依赖 为了使 Spring Boot 应用程序能够与 Kafka 进行交互,需要在 `pom.xml` 文件中添加相应的 Maven 依赖项。这一步骤确保应用程序可以访问 Kafka 客户端库和其他必要的组件[^1]。 ```xml <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> ``` #### 2. 配置 Kafka 设置 接下来,在 Spring Boot 项目的配置文件 (`application.properties` 或 `application.yml`) 中定义 Kafka 的连接参数以及其他重要的属性设置。这些配置指定了如何连接到 Kafka 集群以及消费者的行为模式[^2]。 对于 `application.properties`: ```properties spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=my-group spring.kafka.consumer.auto-offset-reset=earliest ``` 而对于 `application.yml` 则如下所示: ```yaml spring: kafka: bootstrap-servers: localhost:9092 consumer: group-id: my-group auto-offset-reset: earliest ``` 以上配置允许应用通过指定地址连接至本地运行的单节点 Kafka 实例,并为消费组设定了唯一标识符;同时设置了当没有初始偏移量或当前偏移量不再存在时从最早的消息开始读取。 #### 3. 创建生产者和消费者逻辑 ##### 生产者部分 - **引入库** 已经完成于第一步中的 pom.xml 修改。 - **配置类 PublicConfig.java** 此 Java 类用于提供 KafkaTemplate Bean 来发送消息给主题(topic),并可自定义序列化器等选项[^4]。 ```java import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; import java.util.HashMap; import java.util.Map; @Configuration public class PublicConfig { @Bean public ProducerFactory<String, String> producerFactory() { Map<String, Object> configProps = new HashMap<>(); configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); return new DefaultKafkaProducerFactory<>(configProps); } @Bean public KafkaTemplate<String, String> kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); } } ``` - **业务处理类 MessageProducer.java** 该类负责实际向特定的主题发布消息。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Service; @Service public class MessageProducer { private final KafkaTemplate<String, String> kafkaTemplate; @Autowired public MessageProducer(KafkaTemplate<String, String> kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } public void sendMessage(String topicName, String message){ System.out.println("Publishing to Topic:" +topicName+" Message:"+message); kafkaTemplate.send(topicName,message); } } ``` ##### 消费者部分 同样地,也需要编写对应的接收方代码来监听来自某个主题的信息流。 - **引入库** 同上。 - **配置类 PublicConfig.java (扩展)** 除了上述提到的内容外,还需要增加 ConsumerFactory 和 ConcurrentKafkaListenerContainerFactory Beans 的声明以便支持消息监听功能。 ```java import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; import org.springframework.context.annotation.Bean; import org.springframework.kafka.annotation.EnableKafka; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.listener.ContainerProperties.AckMode; @EnableKafka @Configuration public class PublicConfig extends BasePublicConfig { // 假设有BasePublicConfig继承 @Bean public ConsumerFactory<String, String> consumerFactory() { Map<String, Object> props = new HashMap<>(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group"); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); return new DefaultKafkaConsumerFactory<>(props); } @Bean public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory()); factory.getContainerProperties().setAckMode(AckMode.MANUAL_IMMEDIATE); // 手动确认机制 return factory; } } ``` - **业务类 MessageConsumer.java** 最终实现具体的消费行为,即每当有新消息到达时触发的方法体。 ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.support.Acknowledgment; import org.springframework.stereotype.Component; @Component public class MessageConsumer { private static final Logger logger = LoggerFactory.getLogger(MessageConsumer.class); @KafkaListener(topics = "${kafka.topic.name}", groupId = "${spring.kafka.consumer.group-id}") public void listen(String message, Acknowledgment acknowledgment) throws Exception { try{ logger.info("Received Message: {}", message); Thread.sleep(1000L); // Simulate processing time. acknowledgment.acknowledge(); // Manually acknowledge the receipt of messages after successful processing. } catch(Exception e){ throw new RuntimeException(e.getMessage(),e.getCause()); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值