在0.10版本之前, Kafka仅仅作为一个消息系统,主要用来解决应用解耦、 异步消息 、 流量削峰等问题。 不过在0 .10版本之后, Kafka提供了连接器与流处理的能力,它也从分布式的消息系统逐渐成为一个流式的数据平台 。
1.1 流式数据平台
特点:
- 消息系统:队列(点对点)和发布订阅
- 存储数据:保证数据的可靠性
- 流处理:流的聚合,连接,转换操作等
核心组件:
- 生产者:Producer
- 消费者:Consumer
- 连接器:Connector
- 处理器:Processor
1.2 基本概念
1.2.1 分区模型
kafka集群由奇数个消息代理服务器( broker server )组成,发布至 Kafka集群的每条消息都有一个类别,用主题( topic )来表示 ,Kafka集群为每个topic维护了分布式的分区( partition )日志文件,物理意义上可 以把主题看作分区的日志文件。 每个分区都是一个有序的、不可变的记录序列,新的消息会不断追加到提交日志( commit log )。 分区中的每条消息都会按照时间顺序分配到一个单调递增的顺序编号, 叫作 offset ,这个偏移量能够唯一地定位当前分区中的每一条消息 。
每个分区的偏移量都从0开始,不同分区之间 的偏移量都是独立的,不会互相影响 。 下图中,发布到 Kafka主题的每条消息包括键值和时间戳。 消息到达服务端的指定分区后,都会分配到一个自增的偏移量。 原始的消息内容和分配的偏移量以及其他一些元数据信息最后都会存储到分区日志文件中 。 消息的键也可以不用设置,这种情况下消息会均衡地分布到不同的分区 。
1.2.2 消费模型
消息的消费模型有两种:推送模型( push )和拉取模型( pull )。
Kafka采用拉取模型,由消费者自己记录消费状态,每个消费者互相独立地顺序读取每个分区的消息 。
1.2.3 分布式模型
Kafka每个主题的多个分区日志分布式地存储在Kafka集群上,同时为了故障容错,每个分区都会
以副本的方式复制到多个消息代理节点上 。 其中一个节点会作为主副本( Leader ),其他节点作为备份副本( Follower ,也叫作从副本)。 主副本会负责所有的客户端读写操作,备份副本仅仅从主副本同步数据 。 当主副本出现故障时,备份副本中的一个副本会被选择为新的主副本 。 因为每个分区的副本中只有主副本接受读写,所以每个服务端都会作为某些分区的主副本,以及另外一些分区的备份副本 ,这样Kafka集群的所有服务端整体上对客户端是负载均衡的 。
生产者发布消息时根据消息是否有键 , 采用不同的分区策略。 消息没有键时,通过轮询方式进行客户端负载均衡,消息有键时,根据分区语义确保相同键的消息总是发送到同一个分区 。
1.3 kafka的设计与实现
1.3.1 数据传输设计
消息系统内的消息从生产者保存到服务端,消费者再从服务端读取出来,数据的传输效率决定了生产者和消费者的性能。
传统读取磁盘文件的数据在每次发送到网络时,都需要将页面缓存先保存到用户缓存,然后在读取消息时再将其复制到内核空间。
具体步骤如下:
- 操作系统将数据从磁盘中读取文件到内核空间里的页面缓存 。
- 应用程序将数据从内核空间读入用户空间的缓冲区 。
- 应用程序将读到的数据写回内核空 间并放入 socket缓冲区 。
- 操作系统将数据从socket缓冲区复制到网卡接口,此时数据才能通过网络发送归去。
kafka采用的零拷贝技术,只需将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中。
1.3.2 生产者与消费者
生产者客户端有两种方式决定发布的消息归属于哪个分区:通过随机方式将请求负载到不同的消息代理节点,或者使用“分区语义函数”将相同键的所有消息发布到同一个分区。 对于分区语义,Kafka暴露了一个接口,允许用户指定消息的键如何参与分区 。
Kafka采用了基于拉取模型的消费状态处理,它将主题分成多个有序的分区,任何时刻每个分区都只被一个消费者使用 。 并且,消费者会记录每个分区的消费进度( 即偏移量)。 每个消费者只需要为每个分区记录一个整数值 ,而不需要像其他消息系统那样记录每条消息的状态 。
1.3.3 副本机制和容错处理
当集群中的某个节点出现故障时,访问故障节点的请求会被转移到其他正常节点的副本上。副本的单位是主题的分区, Kafka每个主题的每个分区都有一个主副本以及0个或多个备份副本。 备份副本会保持和主副本的数据同步,用来在主副本失效时替换为主副本。
分布式系统处理故障容错时需要明确定义节点是否处于存活状态。 kafka对节点的存活定义有两个条件:
- 节点必须和ZK保持会话;
- 如果这个节点是某个分区的备份副本,它必须对分区主副本的写操作进行复制,并且复制的进度不能落后太多 。
满足这两个条件,叫作“正在同步中”( in-sync )。 每个分区的主副本会跟踪正在同步中的备份副本节点( In Sync Replicas ,即ISR )。 如果一个备份副本挂掉、没有响应或者落后太多,主副本就会将其从同步副本集合中移除。 反之,如果备份副本重新赶上主副本,它就会加入到主副本的同步集合中 。