Spark学习之路(十二)——Kafka

一、Kafka简介

1、Zookeeper安装(apache-zookeeper-3.5.5-bin.tar.gz)
解压:tar -xzf /home/spark/桌面/apache-zookeeper-3.5.5-bin.tar.gz
移动:sudo mv apache-zookeeper-3.5.5-bin /home/spark/app/zookeeper
配置环境变量
①vi ~/.bash_profile

export  ZOOKEEPER_HOME=/home/spark/app/zookeeper
export  PATH=$ZOOKEEPER_HOME/bin:$PATH

②source ~/.bash_profile
③echo $ZOOKEEPER_HOME
配置zookeeper(路径:zookeeper/conf):
①cp zoo_sample.cfg zoo.cfg
②vi zoo.cfg

dataDir=/home/spark/app/zookeeper/data		#修改数据存放的位置
server.1=Master:2888:3888
server.2=Slave1:2888:3888
server.3=Slave2:2888:3888
#服务器地址遵循:server.X=hostname:peerPort:leaderPort
#X:服务器的ID,必须是正数,可不连续
#hostname:服务器机器名或IP地址
#peerPort:节点间通信的TCP端口
#leaderPort:首领选举的TCP端口

验证(路径:zookeeper/bin):
①./zkServer.sh start(用jps查看,出现QuorumPeerMain进程)
②连接到zookeeper端口:telnet localhost 2181
③发送四字命令:srvr(出现下列信息即为安装成功)

Zookeeper version: 3.5.5-390fe37ea45dee01bf87dc1c042b5e3dcce88653, built on 05/03/2019 12:07 GMT
Latency min/avg/max: 0/0/0
Received: 1
Sent: 0
Connections: 1
Outstanding: 0
Zxid: 0x4
Mode: standalone
Node count: 5
Connection closed by foreign host.

#注:Zookeeper使用的是一致性协议,建议每个群组里应包含奇数个节点,因为只有当群组里的大多数节点(即法定人数)处于可用状态,Zookeeper才能处理外部的请求。(即,若群组包含3个节点,则允许1个节点失效;若群组包含5个节点,则允许2个节点失效)

2、Zookeeper集群一键启动脚本(路径:zookeeper/bin)
①sudo vi zkServer_all.sh

#!/bin/bash

case $1 in
"start"){
    for host in Master Slave1 Slave2
    do
        echo "INFO:starting Zookeeper on $host"
        ssh $host "source ~/.bash_profile; /home/spark/app/zookeeper/bin/zkServer.sh start"
    done
};;

"stop"){
    for host in Master Slave1 Slave2
    do
        echo "INFO:stopping Zookeeper on $host"
        ssh $host "source ~/.bash_profile; /home/spark/app/zookeeper/bin/zkServer.sh stop"
    done
};;

esac

②修改权限:chmod 777 zkServer_all.sh
③启动(结束):zkServer_all.sh start(stop)

3、Kafka安装(kafka_2.11-2.3.0.tgz)
解压:tar -xzf /home/spark/桌面/kafka_2.11-2.3.0.tgz
移动:sudo mv kafka_2.11-2.3.0 /home/spark/app/kafka
配置环境变量
①vi ~/.bash_profile

export  KAFKA_HOME=/home/spark/app/kafka
export  PATH=$KAFKA_HOME/bin:$PATH

②source ~/.bash_profile
③echo $KAFKA_HOME
配置kafka(路径:kafka/config/server.properties):
[常规配置:broker.id、listeners、host.name、log.dirs、zookeeper.connect、port、num.recovery.threads.per.data.dir、auto.create.topics.enable]

  • broker.id:每个brober都需要有一个标识符,使用brober表示。默认为0,也可被设置成其它任意整数,但该值在整个Kafka集群里必须是唯一的,建议设置为与机器名有关的整数,便于维护。
  • listeners:配置kafka的监听地址(listeners=PLAINTEXT://host:9092)。
  • host.name:仅在未设置listensers时使用,broker的主机名。若设置了此选项,broker只绑定到该地址上;否则绑定所有接口。
  • log.dirs:保留日志的目录。
  • zookeeper.connect:以hostname:port格式指定Zookeeper连接字符串,其中host和port是Zookeeper服务器的主机和端口。该服务器还可在其Zookeeper连接字符串中包含一个Zookeeper chroot路径,即hostname:port/path。
  • port: 仅在未设置listensers时使用。
  • num.recovery.threads.per.data.dir:每个数据目录在启动时用于日志恢复和关机时用于刷新的线程数。(默认每个日志只使用一个线程,在以下三种情况,Kafka会使用可配置的线程池来处理日志片段:①服务器正常启动,用于打开每个分区的日志片段;②服务器崩溃后重启,用于检查和截短每个分区的日志片段;③服务器正常关闭,用于关闭日志片段)
  • auto.create.topics.enable:自动创建主题(默认:True)。(以下情况,Kafka会自动创建主题:①当一个生产者开始往主题写入消息时;②当一个消费者开始从主题读取消息时;③当任一客户端项主题发送元数据请求时)

#注:把一个broker配置到集群中,只需修改两个参数,即①所有的broker都必须配置相同的zookeeper.connect,该参数用于保存元数据的Zookeeper群组和路径;②每个broker都必须为broker.id参数设置唯一的值。(仅修改了broker.id,log.dirs,zookeeper.connect)

启动Kafka:①启动集群中的Zookeeper(路径:zookeeper/bin):./zkServer.sh start;②启动集群中的Kafka(路径:kafka):./bin/kafka-server-start.sh config/server.properties[阻塞进程]、./bin/kafka-server-start.sh -daemon config/server.properties [守护进程]

4、Kafka集群一键启动脚本(路径:kafka/bin)
①sudo vi kafka_server_all.sh

#!/bin/bash

case $1 in
"start"){
    for broker in Master Slave1 Slave2
    do
        echo "INFO:starting kafka server on $broker"
ssh $broker "source ~/.bash_profile; /home/spark/app/kafka/bin/kafka-server-start.sh -daemon /home/spark/app/kafka/config/server.properties"
#source ~/.bash_profile使配置的环境变量立即生效
    done
};;

"stop"){
    for broker in Master Slave1 Slave2
    do
        echo "INFO:stopping kafka server on $broker"
        ssh $broker "source ~/.bash_profile; /home/spark/app/kafka/bin/kafka-server-stop.sh"
    done
};;

esac

②修改权限:chmod 777 kafka_server_all.sh
③启动(结束):kafka_server_all.sh start(stop)
#注:关闭Kafka时需要修改kafka-server-stop.sh中的内容

#PIDS=$(ps ax | grep -i 'kafka\.Kafka' | grep java | grep -v grep | awk '{print $1}')
PIDS=$(jps -lm | grep -i 'kafka\.Kafka' | awk '{print $1}')

5、Kafka命令行操作(生产者:broker-list;Kafka集群:zookeeper;消费者: bootstrap-server)
查看当前服务器的topic

./bin/kafka-topics.sh  --zookeeper  Master:2181  --list

创建topic

./bin/kafka-topics.sh  --zookeeper  Master:2181  --create  --replication-factor 3  --partitions 1  --topic test

说明:–topic:定义topic名;–replication-factor:定义副本数(副本数不能超过可用的broker数(机器),默认一个副本50个分区);–partitions:定义分区数。
删除topic

./bin/kafka-topics.sh  --zookeeper  Master:2181  --delete  --topic test

#注:需要server.properties中设置delete.topic.enable=true,否则只是标记删除。
发送消息

./bin/kafka-console-producer.sh  --broker-list  Master:9092  --topic test

消费消息

#(仅在0.9以下版本使用,高版本不可用)
./bin/kafka-console-consumer.sh  --zookeeper  Master:2181  --topic test  --from-beginning
./bin/kafka-console-consumer.sh  --bootstrap-server  Master:9092  --topic test  --from-beginning

说明:–from-beginning表示把主题中的所有数据都读取出来
查看topic详情

./bin/kafka-topics.sh  --zookeeper  Master:2181  --describe  --topic test

修改分区数

./bin/kafka-topics.sh  --zookeeper  Master:2181  --alter  --topic test  --partitions 6

6、Kafka架构
在这里插入图片描述
定义:Kafka是一个分布式的基于发布/订阅模式消息队列(Message Queue)。
使用MQ(消息队列)的优点:①解耦:生产消息和消费消息异步处理;②可恢复性:系统的一部分组件失效时,不会影响整个系统;③缓冲:解决生产消息和消费消息的处理速度不一致(生产>消费)的情况;④灵活性&峰值处理能力:可灵活地增减机器,在访问量剧增的情况下,应用仍然可以发挥作用;⑤异步通信:不需要立即处理消息。
MQ的两种模式:①点对点模式:一对一,消费者主动拉取数据,数据收到后清除数据;②发布/订阅模式:一对多,消费者消费数据之后不会删除数据。
Producer(生产者)Consumer(消费者)Broker(Kafka服务器):broker接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。broker为消费者服务,对读取分区的请求作出响应,返回已经提交到磁盘上的消息。
在这里插入图片描述
#注:同一个消费者组里的不同消费者不能同时消费同一个分区中的数据。
Kafka的消息通过主题进行分类。主题就好比数据库的表,或者文件系统里的文件夹。主题可以被分为若干个分区,一个分区就是一个提交日志。消息以追加的方式写入分区,按照先入先出的顺序读取。

7、Kafka工作流程
在这里插入图片描述
Kafka中消息是以topic进行分类的,生产者生产消息,消费者消费消息,都是面向topic。topic是逻辑上的概念,partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的是producer生产的数据。producer生产的数据会被不断追加到log文件末端,且每条数据都有自己的offset。消费者组中的每个消费者,都会实时记录自己消费位置,以便出错恢复时,从上次的位置继续消费。

8、Kafka文件存储机制
在这里插入图片描述
由于生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,Kafka采取了分片索引的机制,每个partition分为多个segment,每个segment对应两个文件——“.index”文件和“.log”文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名+分区序号。

二、Kafka生产者

1、分区
原因:①方便在集群中扩展,每个partition可通过调整来适应它所在的机器,而一个topic又可分为多个partition,因此整个集群便可适应任意大小的数据;②提高并发,数据可以partition为单位读写。
原则:将producer发送的数据封装成一个ProducerRecord对象。①若在ProducerRecord对象里指定了partition,则分区器直接将指定的分区返回;②若没有指定partition,则分区器会根据ProducerRecord对象的key来选择分区;③既没有指定partition又没有key时,第一次调用时随机生成整数(此后依次递增),即round-robin(轮询)算法。
在这里插入图片描述
2、数据可靠性保证
为保证producer能可靠的将数据发送到指定的topic, topic的每个partition收到数据后,都会向producer发送ack(acknowledgement确认收到),若producer收到ack,则进行下一轮数据发送,否则重新发送数据。

3、副本数据同步策略

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

Kafka选择第二种方案,原因如下:①容忍n台节点故障时,方案一需要2n+1个副本,方案二只需n+1个副本,Kafka的每个分区都有大量的数据,方案一会造成大量数据冗余;②虽然方案二的网络延迟较高,但网络延迟对Kafka的影响较小。

4、ISR
采用方案二时,当leader收到数据,所有follower都开始同步数据,但有一个follower因某种故障,暂时不能与leader进行同步,则leader会一直等待,直到所有follower完成同步,才发送ack。
为了解决上诉问题,方案二对其进行了优化:leader维护了一个动态的In-Sync Replica set(ISR),ISR是所有副本集合中的一个子集。当ISR中的follower完成数据同步之后,Leader就会发送ack。若follower长时间未向leader同步数据,则该follower将被从ISR中剔除,该时间阈值由replica.lag.time.max.ms参数设定。Leader发生故障后,将从ISR中选举新leader。(将follower加入ISR中的条件是follower与leader的同步时间快)

5、故障处理
在这里插入图片描述
#注:HW可保证消费者消费数据的一致性
follower故障
follower发生故障后会被踢出ISR,待该follower恢复后,follower会读取本地磁盘记录上次的HW,并将log文件高于HW的部分截掉,从HW开始向leader进行同步。等该follower的LED大于该partition的HW,即follower追上leader后,可重新加入ISR。
leader故障
leader故障发生故障后,会从ISR中选出一个新的leader,为保证多个副本之间数据存储的一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新leader同步数据。
注意:只能保证副本之间的数据一致性,并不能保证数据不丢失或不重复。

6、生产者必要参数配置

参数说明
acksacks参数指定了必须要有多少分区副本收到消息,生产者才会认为消息写入是成功的。
buffer.memory该参数用来设置生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息。
compression.type默认情况下,消息发送时不会被压缩。该参数可以设置为snappy、gzip或lz4,它指定了消息被发送给broker之前使用哪一种压缩算法进行压缩。
retries生产者从服务器收到的错误有可能是临时性的错误(比如分区找不到首领)。在这种情况下,retries参数的值决定了生产者可以重发消息的次数,如果达到这个次数,生产者会放弃重试并返回错误。默认情况下,生产者会在每次重试之间等待1OOms,不过可以通过retries.backoff.ms参数来改变这个时间间隔。
batch.size当有多个消息需要被发送到同一个分区时,生产者会把它们放在放一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算(而不是消息个数)。
linger.ms该参数指定了生产者在发送批次之前等待更多消息加入批次的时间。KafkaProducer会在批次填满或linger.ms达到上限时把批次发送出去。默认情况下,只要有可用的线程, 生产者就会把消息发送出去,就算批次里只有一个消息。
client.id该参数可以是任意的字符串,服务器会用它来识别消息的来源,还可以用在日志和配额指标里。
max.in.flight.requests.per.connection该参数指定了生产者在收到服务器晌应之前可以发送多少个消息。
timeout.ms、request.timeout.ms和metadata.fetch.timeout.msrequest.timeout.ms指定了生产者在发送数据时等待服务器返回响应的时间,metadata.fetch.timeout.ms指定了生产者在获取元数据(比如目标分区的首领是谁)时等待服务器返回响应的时间。如果等待响应超时,那么生产者要么重试发送数据,要么返回 一个错误 (抛出异常或执行回调)。timeout.ms指定了broker等待同步副本返回消息确认的时间,与asks的配置相匹配一一如果在指定时间内没有收到同步副本的确认,那么broker就会返回一个错误。
max.block.ms该参数指定了在调用send()方法或使用 parttitionFor()方法获取元数据时生产者的阻塞时间。
max.request.size该参数用于控制生产者发送的请求大小。它可以指能发送的单个消息的最大值,也可以指单个请求里所有消息总的大小。
receive.buffer.bytes和send.buffer.bytes这两个参数分别指定了TCP socket接收和发送数据包的缓冲区大小。如果它们被设为-1, 就使用操作系统的默认值。

acks参数
acks=0:producer在成功写入消息之前不会等待任何来自broker的响应。若broker故障,则可能丢失数据
acks=1:只要集群的leader收到消息,生产者就会收到一个来自broker的成功响应(ack)。若在follower同步完成前,leader故障,则将丢失数据
在这里插入图片描述
acks=-1(all):只用当所有参与参与复制的节点(leader和ISR中的所有follower)全部收到消息时,生产者才会收到一个来自broker的成功响应。若在follower同步完成后,broker发送ack前,leader故障,将会造成数据重复
在这里插入图片描述

7、Exactly Once
将服务器的ack级别设置为-1,可保证producer到broker之间不会丢失数据,即At Least Once语义;将服务器的ack级别设置为0,可保证producer的每条消息被发送一次,即At Most Once语义
At Least Once可保证数据不丢失,但不能保证数据不重复;At Most Once可保证数据不重复,但不能保证数据不丢失。但是对于一些重要的数据,下游消费者要求数据既不丢失也不重复,即Exactly Once语义
Kafka 0.11版本之后,引入了幂等性(幂等性:producer不论向Sever发送多少条重复数据,Sever端都只会持久化一条)。At Most Once + 幂等性 = Exactly Once
启用幂等性:将producer的参数enable.idempotence设置为true即可。开启幂等性的producer在初始化时会被分配一个PID,发往同一个partition的消息会附带Sequence Number,而Broker端会对<PID,partition,Sequence Number>缓存,当具有相同主键的消息提交时,Broker只会持久化一次。但PID重启、不同的partition主键不同,因此幂等性无法保证跨分区、跨会话的Exactly Once。

8、创建Kafka生产者
Kafka生产者有3个必选属性
bootstrap.servers
该属性指定broker的地址清单,地址的格式为host:port。清单里不需要包含所有的broker地址,生产者会从给定的broker里查找到其他broker的信息。不过建议至少要提供两个broker的信息, 一旦其中一个宕机,生产者仍然能够连接到集群上。
key.serializer
key.serializer必须被设置为一个实现了org.apache.kafka.common.serialization.Serializer接口的类,生产者会使用这个类把键对象序列化成字节数组。注意:key.serializer必须设置,即使只发送值内容。
value.serializer
与 key.serializer一样, value.serializer指定的类会将值序列化。

发送消息的3种方式
发送并忘记(fire-and-forget)
将消息发送给服务器(broker),但并不关心它是否正常到达。大多数情况下,消息会正常到达,因为Kafka是高可用的,而且生产者会自动尝试重发。
同步发送
调用Producer.send()方法发送消息,先返回一个Future对象,调用Future对象的get()方法等待Kafka响应。若服务器返回错误,则get()方法会抛出异常。若没有发生错误,将得到一个RecordMetadata对象,可用它获取消息的偏移量。
异步发送
调用send()方法,并指定一个回调函数,服务器在返回响应时调用该函数。

三、Kafka消费者

1、消费方式
Kafka的consumer采用pull(拉取)模式从broker中读取数据。
push(推)模式很难适应消费速率不同的消费者,因为消息发送速率由broker决定,目的是尽可能以最快速度传递消息,但这样很容易造成consumer来不及处理消息,而pull模式则可根据consumer的消费能力以适当的速率消费消息。pull模式的缺点是,若kafka没有数据,消费者可能会陷入循环中,一直返回空数据。为此,kafka的消费者在消费数据时会传入一个时长参数timeout。若当前没有数据可供消费,则consumer会等待时长timeout后再返回。

2、分区分配策略(消费者组内的消费者数量改变触发策略执行)
Consumer分区分配策略:RoundRobin(轮询)Range
RoundRobin
消费者组有多个消费者,该策略会将消费者组里的所有消费者订阅的全部主题的所有分区逐个分配给该组的所有消费者进行消费,即消费者不能指定消费主题
优点:同一消费者组的不同消费者分配的分区数量最大相差1个分区,适合同一消费者组的消费者订阅主题相同的情况。
缺点:若消费者组内的消费者订阅的主题有差别,则会导致消费者消费到未订阅的主题。
Range
该策略把主题的若干连续的分区分配给所有订阅该主题的消费者,未订阅该主题的消费者消费不到该主题的分区。
优点:同一消费者组的不同消费者可以按需单独指定自己的消费主题。
缺点:同一消费者组的多个消费者订阅的主题相似,且相同的主题较多,这样将导致消费者分配的分区数量不平衡。

3、创建Kafka消费者
Kafka消费者有3个必选属性
bootstrap.servers:指定Kafka集群的连接字符串。
key.deserializer:将字节数组转化成Java对象。
value.deserializer:类似key.deserializer作用。
group.id:非必需,指定了kafkaConsumer的消费者群组。

4、消费者重要参数配置

参数说明
fetch.min.bytes该属性指定了消费者从服务器获取记录的最小字节数。broker在收到消费者的数据请求时,如果可用的数据量小于fetch.min.bytes指定的大小,那么它会等到有足够的可用数据时才把它返回给消费者。
fetch.max.wait.msfetch.max.wait.ms则用于指定broker的等待时间,默认为500ms。如果没有足够的数据流入Kafka,消费者获取最小数据量的要求就得不到满足,最终导致500ms的延迟。
max.partition.fetch.bytes该属性指定了服务器从每个分区里返回给消费者的最大字节数,默认为1MB。max.parition.fetch.bytes的值必须比broker能够接收的最大消息的字节数(通过 max.message.size属性配置)大,否则消费者可能无法读取这些消息,导致消费者一直挂起重试。
session.timeout.ms该属性指定了消费者在被认为死亡之前可以与服务器断开连接的时间,默认是3s。若消费者没有在 session.timeout.ms指定的时间内发送心跳给群组协调器,则被认为已经死亡,协调器就会触发再均衡,把它的分区分配给群组里的其他消费者。该属性与heartbeat.interval.ms紧密相关。heartbeat.interval.ms指定了poll()方法向协调器 发送心跳的频率,session.timeout.ms则指定了消费者可以多久不发送心跳。一般需要同时修改这两个属性,heartbeat.interval.ms必须比session.timeout.ms小,一般是session.timeout.ms的三分之一。
auto.offset.reset该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下(因消费者长时间失效,包含偏移量的记录已经过时井被删除)该作何处理。默认值为latest,即在偏移量无效时,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)。另一值是 earliest,即在偏移量无效的情况下,消费者将从起始位置读取分区的记录。
enable.auto.commit该属性指定了消费者是否自动提交偏移量,默认值为true。为了尽量避免出现重复数据和数据丢失,可设为false,由自己控制何时提交偏移量。如果设为true,可通过配置 auto.commit.interval.mls属性来控制提交的频率。
partition.assignment.strategy通过设置partition.assignment.strategy来选择分区策略。默认为 org. apache.kafka.clients.consumer.RangeAssignor,即Range策略。可将其改成 org.apache.kafka.clients.consumer.RoundRobinAssignor,即RoundRobin策略。还可使用自定义策略,partition.assignment.strategy属性的值就是自定义类的名字。
client.id该属性可以是任意字符串,broker用它来标识从客户端发送过来的消息,通常被用在日志、度量指标和配额里。
max.poll.records该属性用于控制单次调用call()方法能够返回的记录数量,可控制在轮询里需要处理的数据量。
receive.buffer.bytes和send.buffer.bytessocket在读写数据时用到的TCP缓冲区可设置大小。若设置为-1,则使用操作系统的默认值。若生产者或消费者与broker处于不同的数据中心内,可适当增大该值,因为跨数据中心的网络一般都有较高的延迟和较低的带宽。

5、offset维护
从0.9及之后版本,consumer默认将offset保存在Kafka内置的topic中,该topic为__consumer_offsets(系统主题)。
读取offset
①修改配置文件(路径:kafka/config/consumer.properties)

exclude.internal.topics=false

②读取offset(0.11及之后版本)

./bin/kafka-console-consumer.sh --topic __consumer_offsets --bootstrap-server Master:9092 --formatter “kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter” --consumer.config config/consumer.properties --from-beginning

自动提交offset
自动提交offset相关参数
enable.auto.commit:是否开启自动提交offset功能
auto.commit.interval.ms:自动提交offset的时间间隔
消费者会自动把从poll()方法接收到的最大偏移量提交上去。提交时间间隔由auto.commit.interval.ms控制,默认为5s。消费者在最近一次提交之后发生了再均衡,再均衡之后,消费者将从最后一次提交的偏移量位置开始读取消息。则最后一次提交偏移量到再均衡之间的消息将会被重复处理。
手动提交offset
手动提交offset有两种:commitSync(同步提交)和commitAsync(异步提交)。两者的相同点是:都会将本次poll的一批数据最高的偏移量提交。不同点是:commitSync阻塞当前线程,直到提交成功,且会自动失败重试(由不可控因素导致,也会提交失败);commitAsync没有失败重试机制,有可能提交失败。
commitSync(同步提交)和commitAsync(异步提交)都可能造成数据的漏消费或重复消费。先提交offset后消费,可能造成数据的漏消费;先消费后提交offset,可能造成数据的重复消费。

6、Kafka高效读写数据
①顺序写磁盘:Kafka中producer生产的数据写入log文件中,写的过程是一直追加到文件末端,顺序写入。顺序写磁盘快速的原因是省去了大量磁头寻址的时间。
②零复制技术
数据拷贝(四次拷贝)
在这里插入图片描述
系统将数据拷贝到内核缓冲区 –> 内核缓冲区中的数据拷贝到用户空间缓冲区 –> 用户空间缓冲区中的数据拷贝到socket缓存区 –> socket缓存区中的数据拷贝到协议引擎中
零拷贝
在这里插入图片描述
③分布式(分区)存储:并发读写。

7、Zookeeper在Kafka中的作用
Kafka集群中的一个broker会被选举为Controller,负责管理集群中broker的上下线,所有topic的分区副本分配leader选举等工作。Controller的管理工作都依赖于Zookeeper。

8、Kafka事务
消息事务是实现分布式事务的一种方案,可以确保分布式场景下的数据最终一致性。事务可保证Kafka在Exactly Once语义的基础上,生产和消费可以夸分区和跨会话,要么全部成功,要么全部失败。
Producer事务
为实现跨分区跨会话的事务,需引进全局唯一的Transaction ID,并将Producer获得的PID和Transaction ID绑定。当Producer重启后,可通过正在运行的Transaction ID获得原PID。
为管理Transaction,Kafka引入了一个新的组件Transaction Coordinator,Producer通过和Transaction Coordinator交互获得Transaction ID对应的任务状态。Transaction Coordinator还负责将事务写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可得到恢复,从而继续运行。

四、Kafka API

Producer API
1、消息发送流程
Kafka中Producer发送消息采用的是异步发送方式,在消息发送的过程中,包括两个线程——main线程Sender线程一个线程共享变量——RecordAccumulator。main线程将消息发送给RecordAccumulator,Sender线程不断从RecordAccumulator中拉取消息发送到Kafka broker。
在这里插入图片描述
Python编写Producer

import msgpack
from kafka import KafkaProducer
from kafka.errors import KafkaError
from pandas._libs import json
from traitlets import log

#1.创建Kafka生产者配置信息
#2.指定连接的Kafka集群
#3.ACK应答级别(acks)
#4.重试次数(retries)
#5.批次大小(batch.size)
#6.等待时间(linger.ms)
#7.RecordAccumulator缓冲区大小(buffer.memory)
#8.Key、Value序列化
#9.创建生产者对象
#10.发送数据
#11.关闭资源

2、Flume对接Kafka
配置flume(flume-kafka.conf):Kafka生产者

#Name
a1.sources = r1
a1.channels = c1
a1.sinks = k1

#Source
a1.sources.r1.type = netcat
a1.sources.r1.bind = Master
a1.sources.r1.port = 6666

#Channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

#Sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = test
a1.sinks.k1.kafka.bootstrap.servers = Master:9092,Slave1:9092, Slave2:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.kafka.producer.linger.ms = 1

#Bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

启动kafka消费者
./bin/kafka-console-consumer.sh --bootstrap-server Master:9092 --topic test --from-beginning
启动flume
./bin/flume-ng agent -c conf/ -f $FLUME_HOME/conf/flume-kafka.conf -n a1
发送数据(telnet Master 6666)

spark streaming 是基于 spark 引擎的实时数据处理框架,可以通过集成 kafka 来进行数据流的处理。然而,在使用 spark streaming 进行 kafka 数据流处理时,可能会遇到一些坑。 首先,要注意 spark streaming kafka 版本的兼容性。不同版本的 spark streaming kafka 可能存在一些不兼容的问题,所以在选择版本时要特别留意。建议使用相同版本的 spark streaming kafka,以避免兼容性问题。 其次,要注意 spark streaming 的并行度设置。默认情况下,spark streaming 的并行度是根据 kafka 分区数来决定的,可以通过设置 spark streaming 的参数来调整并行度。如果并行度设置得过高,可能会导致任务处理过慢,甚至出现 OOM 的情况;而设置得过低,则可能无法充分利用集群资源。因此,需要根据实际情况进行合理的并行度设置。 另外,要注意 spark streaming kafka 的性能调优。可以通过调整 spark streaming 缓冲区的大小、批处理时间间隔、kafka 的参数等来提高性能。同时,还可以使用 spark streaming 的 checkpoint 机制来保证数据的一致性容错性。但是,使用 checkpoint 机制可能会对性能产生一定的影响,所以需要权衡利弊。 最后,要注意处理 kafka 的消息丢失重复消费的问题。由于网络或其他原因,可能会导致 kafka 的消息丢失;而 spark streaming 在处理数据时可能会出现重试导致消息重复消费的情况。可以通过配置合适的参数来解决这些问题,例如设置 KafkaUtils.createDirectStream 方法的参数 enable.auto.commit,并设置适当的自动提交间隔。 总之,在使用 spark streaming 进行 kafka 数据流处理时,需要留意版本兼容性、并行度设置、性能调优消息丢失重复消费等问题,以免踩坑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值