Kafka核心原理

一.消息中间件

1.优点

  • 异步调用:同步变异步
  • 应用解耦/可扩展性:提供基于数据的接口层
  • 流量削峰:缓解瞬时高流量压力
  • 可恢复性
  • 顺序保障

2.消息中间件工作模式

  • 点对点模式:一对一,消费者主动拉取数据
  • 发布订阅模式:一对多,数据生产后,推送给所有订阅者
    在这里插入图片描述

3.消息中间件中的术语

  • Broker:消息服务器,提供核心服务
  • Producer:消息生产者
  • Consumer:消息消费者
  • Topic:主题,发布订阅模式下的消息统一汇集地
  • Queue:队列,点对点模式下的消息队列

二.Apache Kafka

kafka中文文档

Kafka是一种高吞吐量的分布式发布-订阅 消息系统,专为超高吞吐量的实时日志采集、实时数据同步、实时数据计算等场景来设计

  • 快速,单Broker每秒几百MB读取
  • 不停机扩展集群
  • 消息副本冗余
  • 实时数据管道

使用Scala编写
在这里插入图片描述

1.Kafka安装

  • 下载解压
  • 配置文件
//config/server.properties
broker.id=0
listeners=PLAINTEXT://master:9092
zookeeper.connect=master:2181,slave1:2181,slave2:2181
log.dirs、log.retention.hours
  • 启动
    bin/kafka-server-start.sh config/server.properties
  • 验证
    bin/kafka-topics.sh、kafka-console-producer.sh、kafka-console-consumer.sh
  • 具体过程如下
    在这里插入图片描述
    点我获取脚本,提取码: 39fk

2.Kafka架构

  • Broker:Kafka集群中的服务器
  • Topic:维护一个主题中的消息,可视为消息分类
  • Producer:向Kafka主题发布(生产)消息
  • Consumer:订阅(消费)主题并处理消息
    在这里插入图片描述

3.Kafka Topic

Topic

  • 主题是已发布消息的类别名称
  • 发布和订阅数据必须指定主题
  • 主题副本数量不大于Brokers个数
    在这里插入图片描述

Partition(提高并发)

  • 一个主题包含多个分区,默认按Key Hash分区
  • 每个Partition对应一个文件夹<topic_name>-<partition_id>
  • 每个Partition被视为一个有序的日志文件(LogSegment)
  • Replication策略是基于Partition,而不是Topic
  • 每个Partition都有一个Leader,0或多个Followers

4.Kafka Message

header:消息头,固定长度

  • offset:唯一确定每条消息在分区内的位置
  • CRC32:用crc32校验消息
  • “magic”:表示本次发布Kafka服务程序协议版本号
  • “attributes”:表示为独立版本、或标识压缩类型、或编码类型

body:消息体

  • key:表示消息键,可选
  • value bytes payload:表示实际消息数据

物理结构
在这里插入图片描述

5.Kafka Producer

生产者将消息写入到Broker

  • Producer直接发送消息到Broker上的Leader Partition(follower只会拷贝)
  • Producer客户端自己控制着消息被推送到哪些Partition:指定key通过hash,未指定使用轮询,自定义分区算法等
  • Batch推送提高效率

6.Kafka Broker

Kafka集群中每个Broker都可以响应Producer的请求

  • 哪些Broker是存活的? 需要确保broker是存活的
  • Topic的Leader Partition在哪?分布在多个broker

每个Broker充当Leader和Followers保持负载平衡

  • Leader处理所有读写请求
  • Followers被动复制Leader

7.Kafka Consumer

消费者通过订阅消费消息

  • offset的管理是基于消费组(group.id)的级别
  • 每个Partition只能由同一消费组内的一个Consumer来消费
  • 每个Consumer可以消费多个分区
  • 消费过的数据仍会保留在Kafka中
  • 消费者数量一般不超过分区数量

消费模式

  • 队列:所有消费者在一个消费组内
  • 发布/订阅:所有消费者被分配到不同的消费组

8.Kafka数据流

副本同步:ISR(In-Sync Replica)
容灾:Leader Partition
高并发

  • 读写性能
  • Consumer Group

负载均衡
数据不丢失(ack机制)
在这里插入图片描述

9.ZooKeeper在Kafka中的作用

Broker注册并监控状态

  • /brokers/ids

Topic注册

  • /brokers/topics

生产者负载均衡

  • 每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更

offset维护

  • Kafka早期版本使用ZooKeeper为每个消费者存储offset,由于ZooKeeper写入性能较差,从0.10版本后,Kafka使用自己的内部主题维护offset
    在这里插入图片描述

三.Kafka API

  • Producer API
  • Consumer API
  • Streams API
  • Connector API
    在这里插入图片描述

1.Kafka Producer API

关键类

  • KafkaProducer
  • ProducerRecord
<dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>0.11.0.2</version>
 </dependency>

Properties props = new Properties();
props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");
props.put("acks", "all");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++)
    producer.send(new ProducerRecord<String, String>("topic1", Integer.toString(i), "dd:"+i));

配置项

参数名称 说明 默认值
bootstrap.servers kafka集群的broker-list
acks 确保生产者可靠性设置 -1
acks=0:不等待成功返回
acks=1:等Leader写成功返回
acks=all:等Leader和所有ISR中的Follower写成功返回,all也可以用-1代替
key.serializer key的序列化器
value.serializer value的序列化器
retries 发送失败尝试重发次数 0
batch.size 每个partition的未发送消息大小 16384
partitioner.class 分区类,可以自定义分区类,实现partitioner接口 默认是哈希值%partitions
max.block.ms 最大阻塞时长 60000

2.Kafka Consumer API

关键类

  • KafkaConsumer
  • ConsumerRecords
Properties props = new Properties();
props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");
props.put("group.id", "testGroup1");
props.put("enable.auto.commit", "true");//默认值true
props.put("auto.commit.interval.ms", "1000");//默认值5000
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(props);
consumer.subscribe(Arrays.asList("20190626"));
while (true) {
    
    
     ConsumerRecords<String, String> records = consumer.poll(1000);
     for (ConsumerRecord<String, String> record : records)
           System.out.printf("partition=%d, offset = %d, key = %s, value = %s%n",
                                                                                  record.partition(),record.offset(), record.key(), record.value());
}
参数名称 说明 默认值
bootstrap.servers kafka集群的broker-list
group.id 用于表示该consumer想要加入到哪个group中 “”
key.deserializer key的反序列化器
value.deserializer value的反序列化器
enable.auto.commit 是否自动提交 TRUE
auto.commit.interval.ms 设置自动提交的频率 5000(5s)
auto.offset.reset 1) earliest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费 latest
2) latest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
3) none:topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常

手动提交Offset

Properties props = new Properties();
props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");
props.put("group.id", "testGroup1");
props.put("enable.auto.commit", "false");
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(props);
consumer.subscribe(Arrays.asList("20190626"));
List<ConsumerRecord<String, String>> buffer = new ArrayList();
while (true) {
    
    
    ConsumerRecords<String, String> records = consumer.poll(1000);
    for (ConsumerRecord<String, String> record : records) {
    
             
        buffer.add(record);
   }
   if(buffer.size()>5){
    
    //此处可进行业务逻辑处理,如保存数据库
                consumer.commitAsync(); //异步调用,非阻塞方式
                buffer.clear();
   }}

四.Kafka优化

1.消息有序

Kafka保证在同一主题同一分区内有序
如何确保基于主题全局有序

  • 一个主题一个分区
  • 生产者将消息按Key分组如(Table+PK),一个分组写入一个分区

2.消息副本保证

request.required.acks

  • 0 -生产者从不等待ack
  • 1 -生产者等Leader写成功后返回
  • -1 /all -生产者Leader和所有ISR中的Follower写成功后返回

min.insync.replicas

  • 该属性规定了最小的ISR数。当producer设置request.required.acks为all或-1时,指定副本(replicas)的最小数目,如果这个数目没有达到,producer会产生异常

3.Producer数据丢失分析

Kafka Producer API

  • 消息积累在Batch的缓冲区
  • 消息按分区批处理,正处于批处理级别重试中
  • 重试后,过期的批次被丢弃
  • Producer close/flush失败
  • 数据生产比交付快,导致BufferExhausedException

最佳实践

  • 结合Spark Streaming的实时流处理
  • 通用消息总线
  • 收集用户活动数据
  • 从应用程序、服务器或设备收集操作指标
  • 日志聚合(结合ELK)
  • 分布式系统提交日志

猜你喜欢

转载自blog.csdn.net/sun_0128/article/details/108062549