本文主要内容
一、kafka架构
kafka主要由producter,consumer,broker,zookeeper组成。使用topic对消息进行分类,每个topic由多个不同broker机器上的partition构成,paritition分为leader和follower分区,follower用于数据的同步备份,当leader分区的机器出现异常后,从follower中选取新的leader。consumer按group进行分组,同一个group的consumer不能消费同一个paritition。
producter:数据的生产方,通过push的方式将数据发送到broker
consumer:数据的消费方,通过pull的方式从broker今行获取数据
broker:一个kafka独立的服务器,进行消息偏移量的保存及消息存储。多个broker构成一个kafka集群。
zookeeper:进行kafka集群的管理,配置,容错处理等。
二、kafka 特性简介
2.1、kafka 高可靠性
通过主从分区及数据持久化落盘,保证数据不丢失。并从通过ack机制保证数据处理过程中的可靠性。
2.2、kafka 高吞吐
a、分批发送:消息由producter进行分批发送,提高吞吐率。
b、消息压缩:将发送的批消息进行压缩,减少带宽及IO使用
c、顺序读写:消息顺序读写,减少磁盘寻址及IO操作
d、零拷贝:采用零拷贝方式移动数据,避免内核之间切换
2.3、kafka 水平扩展
kakfa通过扩充broker数量进行集群水平的扩展,提高吞吐及负载均衡,通过扩充partition数量和consumer数量进行扩充数据并发处理能力。
2.4、kafka 数据持久化
kafka通过数据落盘进行数据的持久化处理,数据按paritition以log文件方式进行存储,通过索引文件及offset进行获取消息。
三、kafka数据处理原理
3.1、消息生产者
3.1.1、消息生产流程:
a、producter将消息处理成ProducterRecord对象(包含topic和发送的内容,也可指定分区及主键key)并序列化为字节数组。
b、将字节数组发送到分区器(若指定分区则不处理,否则按主键进行分区),后发送到批处理缓冲区中
c、批缓冲区通过独立线程,定时将消息发送到kafka服务端
d、服务端收到消息后,返回一个RecordMetaData对象(包含topic,paritition,offset等信息)。如果服务端处理失败则返回错误,producter端会自动进行重试(消息过大及其他不可重试错误不进行重试)。若重试多次任失败,则对外抛出异常。
处理流程图:
3.1.2、消息发送方式
a、同步发送:单线程方式发送数据,发送成功返回元数据,失败进行重试,重试失败则抛异常由用户进行处理。
b、异步发送:以异步多线程方式发送消息,不等待服务端的响应,提高发送效率。异步发送通过callback进行回调方式处理异常,通过实现callback类进行回调处理(异步不支持重试)。
3.1.3、消息确认机制(ack)
消息通过ack来设置消息确认机制,从而保证消息安全可靠。
a、ack=0:不等待确认
b、ack=1:leader节点收到消息后进行确认
c、ack=-1:leader及follower节点都收到消息后进行确认。
a->b->c:可靠性越高,效率越低。在producter中通过参数 request.required.acks 进行配置
3.1.4、消息分区策略
a、顺序分区:消息按顺序均匀的分配到每个partition(默认分区方式)
b、随机分区:按parititon数量,随机选择分区发送消息
c、指定key分区:每个消息都有一个key,通过计算key进行选择分区,保证相同的key在同一分区中(即按消息键保存的策略)
3.1.5、消息压缩机制
a、压缩是对缓冲区中消息集进行压缩的,而不是单条消息。
b、压缩方式是随k,v一起发送的,所有consumer知道采用何种方式进行解压。
c、开启压缩方式: properties.put(“compression.type”, “gzip”); // gzip压缩
3.1.6、常见配置
a、bootstrap.servers:kafka brockers地址(数组)
b、key.serializer:指定键的序列化器 (键值不为null使用散列算法分区,为null使用轮询算法均衡分区)
c、value.serializer:指定值得序列化器(消息经序列化后发送到broker,默认序列化为字节)
d、partitioner.class:自定义得分区器(注意:还需使用配置对象传入分区所需得参数)
e、acks:指定有多少个分区副本收到消息,才认为处理成功(0–发送出去即成功,1–首节点收到即成功,all–所有副本收到即成功)
其他更多配置及定义分区化器参考: kafka配置及分区
3.2、消息消费者
3.2.1、消费者介绍
a、kafka支持队列模式和订阅模式消费消息。队列模式–一条消息只能被一个消费消费(配置同一group)。订阅模式–一条消息,可被多个消费消费(配置不同group)
b、kafka通过consumer采用pull的方式从broker的leader分区上获取消息。
c、每个topic上的同一个group消费者,属于同一个消费者组。
d、同一个group的consumer消费不同paritition。同一个partititon只能被一个group组中consumer消费。
e、同一个topic的group消费组消费情况:
consumer数 < paritition数:存在一个consumer消费多个paritition
consumer数 > paritition数:一个consumer消费一个paritition(多余的consumer空闲)
consumer数 = paritition数:恰好一个consumer消费一个paritition,效率最高
注:当扩充paritition数量时,只有当新消息到达,才会将数据发送到新paritition上并触发重平衡机制。
3.2.2、消息消费机制
a、轮询:consumer会轮询的请求broker获取消息,当长时间没请求broker,则broker认为该consumer下线,并进行下线处理。
b、获取数据信息:consumer通过pull的方式从broker获取一列消息,消息包括 topic,paritition,offset,键值信息等。通过遍历列表进行消息处理。
c、提交偏移量:consumer通过提交偏移量,表示该次消息处理结束
d、consumer退出时,执行close关闭socket连接,broker则会对该consumer进行下线处理,触发重平衡机制。
3.2.3、重平衡机制
消费者通过向broker发送心跳包,来维护自己是消费者组的成员及所拥有的分区。当消费者数发生变动时,会将消费者的分区转移到其他消费者上的过程,称为重平衡。重平衡实现了消费者的高可用及伸缩性。重平衡场景如下:
a、消费者主动向broker发送退出通知,broker不用等待心跳超时,直接触发重平衡机制。
b、broker一定时间没收到心跳包,超过会话期。broker认为该consumer以下线进行重平衡处理。
注:重平衡是一把双刃剑,虽能提高消费者的高可用及伸缩性,但在重平衡过程中会暂停消息的处理及其他线程,导致消费者群组不可用,产生很大影响。
3.3、消息处理及持久化
3.3.1、消息格式
消息组成:固定header + 变长body (数据消息)
header组成:header:magic (1字节) + attribute (1字节)+ crc32 (4字节)
作用:magic=1。attrubute 保存消息属性,如压缩格式。crc32:body校验
3.3.2、消息存储
kafka broker将消息以log文件方式将消息持久化到磁盘。文件主要由索引文件和日志文件组成。
a、Log存储格式:magic + offset + message
b、文件命名:每个partition作为一个文件,并以 topicname_partition_序号进行命名
c、文件结构:索引文件(存储所有日志文件得offset范围),日志文件存在日志信息。结构如下:
3.3.3、kafka 消息存储机制
a、数据管理:每个topic由多个paritition进行数据管理,每个parititio中得数据是有序不可变的,使用偏移量offset标识唯一一条数据(offset是Long类型)
b、数据落盘:paritition收到producter发送来的数据后,会产生一个递增的offset,并将数据落盘。但落盘后的数据(log.retention.[ms,minutes,hours])过期后,会将数据删除,默认保留7天
c、数据消费:consumer根据offset消费对应的parittion。(每个topic的不同paritition对应不同的offset)(kafka 服务端和客户端都保存着当前处理的offset值,并会进行定期同步(可配置))
d、数据备份:topic中的数据以paritition分区,分布式存在所有brokers机器上。每个分区可存储备份数据。备份分区存储在集群的其他brocker机器上
3.4、主从机制
3.4.1 主从原理
a、kafka将partition分为leader分区和follower分区,实现主从机制。
b、kafka每个分区(paritition)存在一个leader节点,其他brocker节点成为follower节点。
c、leader节点负责数据读写,follower节点负责从leader节点备份数据。leader挂掉后,其中一个follower节点作为leader(依赖于zookeeper)
3.4.2、leader节点选取原理
a、若follower节点落后leader节点数太多,则将follower节点从ISR中移除(ISR–后备leader节点)。防止成为leader节点
b、leader的选取基于zk的watcher机制
c、leader节点挂掉后,ISR中的follower节点通过竞争在zk中创建文件(仅一个创建成功)成为leader节点。成为leader节点会与原leader节点进行数据同步
d、若leader节点和follower节点全挂,则会等待任意一个恢复节点的作为leader节点
3.4.3、follower节点满足条件
a、follower的所有节点必须保存与zk连接。
b、follower能够及时从leader节点获取数据(通过 replica.lag.time.max.ms 设置超时时间)
注:主从机制虽会降低kafka的吞吐率,但极大的提高可用性