kafka

kafka

1.概述

Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。

架构组成:生产者,broker,消费者,zk

概念理解:
producer:生产者,向kafka broker发消息的客户端
consumer:消费者,从kafka broker取消息的客户端
consumergroup:多个消费者组成一个消费者组,是逻辑上的一个订阅者,每个消费者消费一个分区的数据
broker:一台kafka服务器就是一个broker
topic:一个队列,消费者和生产者面向的都是一个topic
partition:一个topic可以分成多个partition,每个partition是一个有序队列
replica:副本,为了防止某节点故障导致partition数据丢失,一个topic的每个分区都有若干副本
leader:副本的主,生产者和消费者生产和消费的对象
follower:副本,保持同步,leader发生故障时,某个follower会成为新的leader
segment:partition相当于一个巨型文件,里面有多个segment file小文件,多个segment的消息数量不一定想等,方便旧的segment快速删除

2、kafka集群搭建

1、上传压缩包至/opt/software:rz kafka_2.11-2.4.1.tgz

2、解压:tar -zxvf kafka_2.11-2.4.1.tgz -C /opt/module/

3、改名:mv kafka_2.11-2.4.1.tgz kafka

4、更改配置文件:vim /opt/module/kafka/config/server.properties
输入以下内容:
#broker的全局唯一编号,不能重复
broker.id=0
#删除topic功能使能
delete.topic.enable=true
#处理网络请求的线程数量
num.network.threads=3
#用来处理磁盘IO的现成数量
num.io.threads=8
#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400
#接收套接字的缓冲区大小
socket.receive.buffer.bytes=102400
#请求套接字的缓冲区大小
socket.request.max.bytes=104857600
#kafka运行日志存放的路径
log.dirs=/opt/module/kafka/logs
#topic在当前broker上的分区个数
num.partitions=1
#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#配置连接Zookeeper集群地址
zookeeper.connect=hadoop102:2181,hadoop103:2181,hadoop104:2181/kafka

5、更改环境变量:vim /etc/profile.d/my_env.sh
#KAFKA_HOME
export KAFKA_HOME=/opt/module/kafka
export PATH=$PATH:$KAFKA_HOME/bin

6、环境变量生效:source /etc/profile

7、分发kafka和环境变量配置至hadoop103和hadoop104

8、改hadoop103和hadoop104配置文件:vim /opt/module/kafka/config/server.properties
分别改id为:broker.id=1、broker.id=2

9、分发配置文件/etc/profile.d/my_env.sh并执行source /etc/profile

10、三台机器分别验证:echo $KAFKA_HOME

3、集群启动

1、三个机器上:kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties

2、查看集群:jps

3、关闭集群:kafka-server-stop.sh

4、启停脚本

#!/bin/bash
if [ $# -lt 1 ]
then
echo "参数不能为空"
exit;
fi
for i in hadoop102 hadoop103 hadoop104
do
case $1 in
"start")
echo "开始启动 $i 的kafka"
ssh $i /opt/module/kafka/bin/kafka-server-start.sh -daemon /opt/module/kafka/config/server.properties
;;
"stop")
echo "开始关闭 $i 的kafka"
ssh $i /opt/module/kafka/bin/kafka-server-stop.sh
;;
*)
echo "参数错误"
;;
esac
done

5、命令操作

1、显示所有topic:	kafka-topics.sh --list --bootstrap-server hadoop102:9092

2、创建topic:		 kafka-topics.sh --create --bootstrap-server hadoop102:9092 --topic GMALL_START --partitions 4 --replication-factor 1
说明:partitions用来指定分区,replication-factor用来指定副本数

3、显示topic详细信息:kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first

4、删除topic:kafka-topics.sh --delete --bootstrap-server hadoop102:9092 --topic first


6、生产消息:kafka-console-producer.sh --broker-list hadoop102:9092 --topic first

7、消费消息:kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --from-beginning --topic first

8、修改分区数:kafka-topics.sh --bootstrap-server --alter --topic first --partitions 6

9、消费数据时指明消费者组:kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first --consumer-property group.id=group_mytest


说明:指明同一个消费者组时,可以开两个及多个进程充当这个消费者组的多个消费者实例,共同消费一个topic下的数据

6、topic 和 partition

1、kafka中消息均以topic分类:消费者和生产者都是面向topic的

2、topic是逻辑概念,partition是物理概念,每个partition对应一个文件,文件中包含生产的数据,每条数据都有自己的offset,消费者根据这个记录自己消费到了哪个offset

3、一个partition包含多个segment,每个段中有.index文件记录索引信息,.log记录真实数据

4、partition文件命名规则:topic名字 + 分区号 例如:first-0,first-1,first-2

7、分区的好处

1、集群方便扩展:
每个Partition可以通过调整segment以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可以适应任意大小的数据了;

2、提高并发性:
以partition为单位,多个节点并发读写

8、分区原则

首先将发送的数据封装成ProducerRecord对象
1、指明 partition 的情况下,直接将指明的值直接作为 partiton 值

2、没有指明 partition 值但有 key 的情况下,将 key 的 hash 值与 topic 的 partition 数进行取余得到 partition 值

3、既没有 partition 值又没有 key 值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与 topic 可用的 partition 总数取余得到 partition 值,也就是常说的 round-robin 算法。

9、数据同步策略

方案优点缺点
半数以上完成同步,就发送ack延迟低选举新的leader时,容忍n台节点的故障,需要2n+1个副本
全部完成同步,才发送ack选举新的leader时,容忍n台节点的故障,需要n+1个副本延迟高(kafka选用此策略)

10、kafka的数据同步策略

全部同步
原因:
(1)同样为了容忍n台节点的故障,第一种方案需要2n+1个副本,而第二种方案只需要n+1个副本,而Kafka的每个分区都有大量的数据,第一种方案会造成大量数据的冗余。
(2)虽然第二种方案的网络延迟会比较高,但网络延迟对Kafka的影响较小。万一有个节点迟迟同步不上,怎么办?使用ISR机制

11、ISR机制

1、Leader维护了一个动态的in-sync replica set (ISR),意为和leader保持同步的follower集合。
2、当ISR中的follower完成数据的同步之后,leader就会给producer发送ack。如果follower长时间未向leader同步数据,则该follower将被踢出ISR,该时间阈值由replica.lag.time.max.ms参数设定。
3、Leader发生故障之后,就会从ISR中选举新的leader。

12、ack三种应答机制

1、acks=0
producer不等待broker的ack,这一操作提供了一个最低的延迟,broker一接收到还没有写入磁盘就已经返回,当broker故障时有可能丢失数据
2、ack=1
producer等待broker的ack,partition的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将会丢失数据

数据不会重复,但可能丢失
3、ack=-1
producer等待broker的ack,partition的leader和follower全部落盘成功后才返回ack。但是如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复

数据会重复,但不会丢失

13、幂等性解决数据重复

启用:设置参数enable.idompotence=true

1、Kafka的幂等性实现其实就是将原来下游需要做的去重放在了数据上游。开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带Sequence Number。而Broker端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。

2、但是PID重启就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区跨会话的Exactly Once。

3、at least once  + 幂等性 = exactly once

14、消费方式

push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。

pull(拉)模式则可以根据consumer的消费能力以适当的速率消费消息

consumer采用pull(拉)模式从broker中读取数据。

15、consumer group消费策略

roundrobin
两个topic:
topic1:	a1,a2,a3,a4,a5,a6,a7
topic2:	b1,b2,b3,b4,b5

一个消费者组包含三个消费者c1,c2,c3:
c1:	a1,a4,a7,b3
c2:	a2,a5,b1,b4
c3:	a3,a6,b2,b5

一个消费者组包含四个消费者d1,d2,d3,d4:
d1:	a1,a5,b2
d2:	a2,a6,b3
d3:	a3,a7,b4
d4:	a4,b1,b5

优点:数据均衡,缺点增加节点时分区调整动作过大
range
两个topic:
topic1:	a1,a2,a3,a4,a5,a6,a7
topic2:	b1,b2,b3,b4,b5

一个消费者包含三个消费者c1,c2,c3:
c1:	a1,a2,a3,b1,b2
c2:	a4,a5,b3,b4
c3:	a6,a7,b5

优点:增加节点,数据调整动作小,缺点是数据倾斜
sticky
两个topic:
topic1:	a1,a2,a3,a4,a5,a6,a7
topic2:	b1,b2,b3,b4,b5

一个消费者组包含三个消费者c1,c2,c3:
c1:	a1,a4,a7,b3
c2:	a2,a5,b1,b4
c3:	a3,a6,b2,b5

增加一个节点c4:
c1:	a1,a4,a7
c2:	a2,a5,b1
c3:	a3,a6,b2
c4:	b3,b4,b5

16、offset的维护

作用:记录consumer在消费到什么地方了,方便在断电宕机后继续原先的位置消费

原理:kafka0.9之前维护在zookeeper中,之后维护在kafka内置的topic中,名字叫_concumer_offsets

17、kafka高效读写的秘密

1、顺序读写,省去了磁头寻址时间

2、使用pagecache
Kafka数据持久化是直接持久化到Pagecache中,这样会产生以下几个好处: 
1、I/O Scheduler 会将连续的小块写组装成大块的物理写从而提高性能
2、I/O Scheduler 会尝试将一些写操作重新按顺序排好,从而减少磁盘头的移动时间
3、充分利用所有空闲内存(非 JVM 内存)。如果使用应用层 Cache(即 JVM 堆内存),会增加 GC 负担
4、读操作可直接在 Page Cache 内进行。如果消费和生产速度相当,甚至不需要通过物理磁盘(直接通过 Page Cache)交换数据
5、如果进程重启,JVM 内的 Cache 会失效,但 Page Cache 仍然可用
尽管持久化到Pagecache上可能会造成宕机丢失数据的情况,但这可以被Kafka的Replication机制解决。如果为了保证这种情况下数据不丢失而强制将 Page Cache 中的数据 Flush 到磁盘,反而会降低性能。

3、零拷贝技术

如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存。

传统方式消费者读取数据:
磁盘拷贝到内核缓冲区(1)=》内核缓冲区拷贝到用户缓冲区(2)=》用户缓冲区拷贝到socket缓冲区(3)=》socket缓冲区拷贝到网卡接口(4)

零拷贝:磁盘拷贝到内核缓冲区(1),其他消费者也可以用=》网卡接口

18、zookeeper在kafka中的作用

1、在kafka集群中选举出controller
2、controller管理broker上下线(通过监听集群isr)
3、controller管理topic的分区副本分配
4、controller管理leader的选举
以上都依赖于zookeeper

19、事务

Producer事务
作用:实现跨分区跨会话的事务,引入全局id:Transaction ID

原理:Transaction ID和PID绑定,当Producer重启后,可以通过唯一的Transaction ID找到PID。

Consumer事务
作用:实现精准一次性消费

原理:将消费过程和offset提交过程进行原子绑定

20、kafka api

producer api
导入依赖:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.4.1</version>
</dependency>



package com.zhangyubo.producer;

import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

import java.util.Properties;

/**
 * @author zhangyubo
* @create 2020-05-08 10:51
 */
public class Myproducer {

    public static void main(String[] args) {
        Properties properties = new Properties();//kafka生产者参数

        properties.setProperty("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
        properties.setProperty("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
        properties.setProperty("acks","all");//ack原则
        properties.setProperty("bootstrap.servers","hadoop102:9092");//集群地址
        properties.setProperty("batch.size","5");//批次大小
        properties.setProperty("linger.ms","500");//等待时间
        properties.setProperty("retries","1");//重试次数
        properties.setProperty("buffer.memory","33554432");//缓冲区大小


        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);//构建生产者

        for (int i = 0; i < 20; i++) {

            ProducerRecord<String, String> first = new ProducerRecord<String, String>("first", "这是第" + i + "条数据");
            Callback callback = new Callback() {
                public void onCompletion(RecordMetadata recordMetadata, Exception e) {

                    if(recordMetadata != null){
                        System.out.println(recordMetadata.topic() + "话题" + recordMetadata.partition() + "分区" + recordMetadata.offset()
                        + "发送成功");
                    }
                }
            };
            producer.send(first,callback);
        }

        producer.close();
    }
}

consumer api
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.4.1</version>
</dependency>




package com.zhangyubo.consumer;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

/**
 * @author zhangyubo
 * @create 2020-05-08 10:51
 */
public class Myconsumer {
    public static void main(String[] args) {

        Properties properties = new Properties();

        properties.setProperty("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
        properties.setProperty("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
        properties.setProperty("bootstrap.servers","hadoop102:9092");
        properties.setProperty("group.id","Idea01");//消费者组id
        properties.setProperty("auto.offset.reset","earliest");

        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(properties);

        consumer.subscribe(Collections.singleton("first"));//订阅主题

        Duration millis = Duration.ofMillis(500);

        ConsumerRecords<String, String> poll = consumer.poll(millis);//0.5秒拉取一次

        for (ConsumerRecord<String, String> record : poll) {
            System.out.println(record);
        }

        consumer.close();

    }
}

说明:
auto.offset.reset
这个配置项,是告诉Kafka Broker在发现kafka在没有初始offset,或者当前的offset是一个不存在的值(如果一个record被删除,就肯定不存在了)时,该如何处理。它有4种处理方式:

1) earliest:自动重置到最早的offset。

2) latest:看上去重置到最晚的offset。

3) none:如果边更早的offset也没有的话,就抛出异常给consumer,告诉consumer在整个consumer group中都没有发现有这样的offset。

4) 如果不是上述3种,只抛出异常给consumer。

默认值是latest。

21、kafka监控


Version 1.4.5 -- Copyright 2016-2020
*******************************************************************
* Kafka Eagle Service has started success.
* Welcome, Now you can visit 'http://192.168.75.102:8048/ke'
* Account:admin ,Password:123456
*******************************************************************
* <Usage> ke.sh [start|status|stop|restart|stats] </Usage>
* <Usage> https://www.kafka-eagle.org/ </Usage>
*******************************************************************

22、故障

follower故障:
leader会将故障的follower提出ISR,当故障的follower重启后,先截取掉hw之后的内容,然后和leader同步,当自身的leo大于等于leader时,就可以重新加入ISR

leader故障:
会从其余的follower中选举出新的leader,其他follower会截取掉hw之后的内容,重新和新的leader同步

23、面试题

1、ISR和AR是什么
ISR:与leader保持同步的follower集合
AR:分区所有副本

2、HW和LEO分别代表什么
HW:一个分区所有副本最小的offset
LEO:每个副本最后一条消息的offset

leader:0,1,2,3,4,5,6,7,8,9	LEO是9,HW是7
f1:1,2,3,4,5,6,7			LEO是7,HW是7
f2:1,2,3,4,5,6,7,8			LEO是8,HW是7

说明:只有HW之前的数据对consumer可见

3、Kafka中是怎么体现消息顺序性的
分区内,每条消息有一个offset,可实现分区内有序,分区间无序

4、Kafka中的分区器、序列化器、拦截器是否了解?它们之间的处理顺序是什么
分区器:分区字段有值时,分区器不起作用,直接将消息分往指定分区,如果没有值,分区器起作用,如果指定了key,按照key进行hash操作,取模指定分区,如果没有key,先产生随机数,之后在这个数基础上自增1产生新的数,优先对可用分区取模后选择一个可用分区进入,如果没有可用分区,就对不可用分区取模后选择一个分区进入

序列化器:serializer 和deserializer

拦截器:拦截器允许修改key和value,多个拦截器组成拦截器链,依次对k-v进行修改
顺序:拦截器 > 序列化器 > 分区器

5、Kafka生产者客户端的整体结构是什么样子的?使用了几个线程来处理?分别是什么?
两个线程:main线程和sender线程
main线程:生产Producer——》interceptors拦截器封装——》Serializer——》partitioner——多个封装成recordbatch交给recordaccumulate生成队列,
sender线程:从recordbatch队列中读取数据写入topic的某个分区

6、“消费组中的消费者个数如果超过topic的分区,那么就会有消费者消费不到数据”这句话是否正确?
正确

7、消费者提交消费位移时提交的是当前消费到的最新消息的offset还是offset+1?
offset + 1

8、有哪些情形会造成重复消费?
消费端在提交offset时宕机,导致消费最新数据的offset未及时同步给_consumer_offsets,重启后又消费了一次未同步的offset数据

9、那些情景会造成消息漏消费
先提交offset,后消费

10、当你使用kafka-topics.sh创建(删除)了一个topic之后,Kafka背后会执行什么逻辑?
1)会在zookeeper中的/brokers/topics节点下创建一个新的topic节点,如:/brokers/topics/first
2)触发Controller的监听程序
3)kafka Controller 负责topic的创建工作,并更新metadata cache

11、topic的分区数可不可以增加?如果可以怎么增加?如果不可以,那又是为什么
可以,使用kafka-topics.sh --bootstrap-server --alter --topic first --partitions 6

12、topic的分区数可不可以减少?如果可以怎么减少?如果不可以,那又是为什么
不可以,被删除的分区数据难以处理

13、Kafka有内部的topic吗?如果有是什么?有什么所用
有_consumer_offsets,用来保存消费者返回的offset

14、简述Kafka的日志目录结构
每个分区对应一个文件夹,文件夹命名规则是topic名+分区编号,内部是.log文件存储真实数据,.index存储索引

15、如果我指定了一个offset,Kafka Controller怎么查找到对应的消息?
例如offset为3,先找到对应的segement,从.index文件中找到3对应的索引,然后从.log文件中找到对应的消息

16、Kafka Controller的作用
1)broker的上下线管理
2)topic删除新建,分区和副本的分配
3)leader选举

17、Kafka中有那些地方需要选举?这些地方的选举策略又有哪些
1)controller选举(先到先得)
2)partition leader选举(isr列表顺序继承)

18、失效副本是指什么?有那些应对措施
不能及时与leader同步的副本,暂时将失效副本踢出isr列表,等失效副本追上leader后再重新加入

19、Kafka的那些设计让它有如此高的性能
分区,pagecache的使用,顺序读写,零拷贝技术


20、Kafka分区分配的概念
roundrobin、range和sticky策略

24、kafka和flume对比

共同点:
1、都是日志系统的中间件,

区别:
1、kafka是分布式中间件,自带存储,提供push和pull存取数据,
2、flume分为agent采集,collector数据简单处理,存储storage
3、kafka作为日志缓存比较合适,但是flume的数据采集部分做的比较好,因为可以有很多数据源,减少开发量
4、比较流行的是flume+kafka的方式,如果是写入到hdfs中会使用kafka+flume的方式
5、kafka是一个可持久化的分布式的消息对列
6、flume可以使用拦截器对数据进行处理,kafka需要外部的流处理系统才能做到
7、flume和kafka都是可靠的系统,但是flume不支持副本机制,所以节点崩毁会丢数据,除非恢复这些磁盘,如果需要高可用则考虑使用kafka
8、使用flume开发量少,而使用kafka开发量比较大,因为他对社区支持的不是很好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值