Kafka学习记录

简介

Kafka 是一个分布式的( distributed )、多分区的( partitioned )、多副本的( plicated )、提交日志( commitlog )的消息流服务

“分布式”是所有分布式系统的特性 ;

“分区”指消息会按照分区分布在集群的所有节点上;

“副本”指每个分区都会有多个副本存储在不同的节点上;

“提交日志”指新的消息总是以追加的方式进行存储。

而Kafka直接使用提交日志作为最终的存储格式。


一、基本概念

节点Broker,一个 kafka 实例,称为一个节点。

集群Cluster,由一组 kafka 节点组成的节点群。

分区Partition,消息的存储空间,每个 topic 将被分成多个(区)。(用于扩展,和 并行处理)

副本Replication,partition 的备份。(用于容错)

片段Segment,partition 物理上由多个 segment 组成,每个 segment 存着 index 信息和 message 信息。

消息Message,在消费者和生产者之间传递的数据流。

主题Topic,通过对消息指定主题可以将消息分类,消费者可以只关注自己需要的 topic 中的消息。

生产者Producer,向 kafka 集群发送消息,在发送消息之前,会对消息进行分类,即 topic。

消费者Consumer,消费者通过与 kafka 集群建立长连接的方式,不断地从集群中拉取消息,然后可以对这些消息进行处理。

分组Consumer Group,在 kafka 的设计中,可以有多个不同的消费者分组来同时消费同一个 topic 下的消息。

提交日志Commit log,.log 文件,消息数据存储,存在于segment中。

索引.index 文件,消息索引,存在于segment中。

偏移量Offset,在 partition 内的每一条消息都有一个有序的id号,这个id号被称为 offset,它可以唯一确定消息在 partition 中的位置,即 offset 表示 partition 中的第多少条消息。


分区的每个副本存储在不同的broker节点上,每个副本都对应一个日志 在将分区存储到底层 文件系统上时,每个分区对应一个目录,

分区目录下有多个日志分段( LogSegment), 同一个目录下, 所有的日志分段都属于 一个分区。

每个日志分段在物理上 由一个数据文件和 一个索引文件组成 ,数据文件存储的是消息的真正内容,

索引文件存储的是数据文件的索引信息 为数据文件建立索引文件的目的是更快地访问数据文件。


二、架构

Kafka学习记录_数据



Kafka学习记录_zookeeper_02



三、Zookeeper 在 kafka 的作用

  元数据管理:Broker 注册、Topic 注册、Producer 和 Consumer 负载均衡、维护 Partition 与 Consumer 的关系、记录消息消费的进度以及 Consumer 注册等。

      leader选举:

      集群容错:


四、运行原理

Kafka 的大致工作模式:

1、启动 ZooKeeper 的 server

2、启动 Kafka 的 server,即 Broker

3、Producer 生产数据,然后通过 ZooKeeper 找到 Broker,再将数据 push 到 Broker 保存

4、Consumer 通过 ZooKeeper 找到 Broker,然后再主动 pull 数据


五、核心机制

broker controller选举:

  broker 启动或者旧的 controller 故障后,最先写成功 Zookeeper 中 /controller临时节点 数据的 broker 即成为新的 controller。


  • 从Zookeeper中读取当前分区的所有ISR(in-sync replicas)集合
  • 调用配置的分区选择算法选择分区的leader


分区分配策略;

分区的 leader 选举:

  controller会将leader的改变直接通过RPC的方式(比ZooKeeper Queue的方式更高效)通知需为此作为响应的Broker。不使用 zookeeper,避免 脑裂,羊群效应,zookeeper watch负载过高问题。

  分区leader选择算法:


  • NoOpLeaderSelector–偏爱分区(SR中的第一个),并将leader发送给为此做出改变的broker,
  • OfflinePartitionLeader–也是选择偏爱分区作为leader
  • ReassignedPartitionLeader
  • PreferredReplicaPartitionLeader
  • ControlledShutdownLeader

副本同步机制:LEO,HW

ISR机制:IN-SYNC Replication。ISR(同步副本集合), 维护了与 leader 信息一致的 follower 副本的信息,当 leader 挂掉的时候 就从这个 ISR 中选举新的 leader 。

文件存储机制:.log文件, .index 文件,稀疏索引,二分法

分片算法:hash取余 ?

限流机制:Quota 参数设置

consumer 心跳机制:

Kafka是通过心跳机制来控制超时,心跳机制对于消费者客户端来说是无感的,它是一个异步线程,当我们启动一个消费者实例时,心跳线程就开始工作了。

在org.apache.kafka.clients.consumer.internals.AbstractCoordinator中会启动一个HeartbeatThread线程来定时发送心跳和检测消费者的状态。

每个消费者都有个org.apache.kafka.clients.consumer.internals.ConsumerCoordinator,

而每个ConsumerCoordinator都会启动一个HeartbeatThread线程来维护心跳,心跳信息存放在org.apache.kafka.clients.consumer.internals.Heartbeat中。


幂等性:ProducerID和SequenceNumber

ProducerID:在每个新的Producer初始化时,会被分配一个唯一的ProducerID,这个ProducerID对客户端使用者是不可见的。

SequenceNumber:对于每个ProducerID,Producer发送数据的每个Topic和Partition都对应一个从0开始单调递增的SequenceNumber值。

事务:

  Kafka中的事务与数据库的事务类似,Kafka中的事务属性是指一系列的Producer生产消息和消费消息提交Offsets的操作在一个事务中,即原子性操作。对应的结果是同时成功或者同时失败。

  对Kafka来说,操作事务是指一系列的生产和消费等原子性操作。 



控制器 - Controller

控制器,负责集群管理和协调,分区状态管理,副本状态管理。


更新集群元数据信息。

创建 topic。

删除 topic。

分区重分配。

preferred leader 副本选举。

topic 分区扩展。

broker 加入集群。

broker 崩溃。

受控关闭。

controller leader选举。


分区及副本分配

目标


  • 在brokers之间均分replicas
  • partition与它的其他replicas不再同一个broker上
  • 如果broker有rack信息,则partition的replicas尽量分配在不同rack上面


算法


  • 一种是rack unware
  • 一种是rack-ware


分区分配

1、producer -> 分区

2、broker -〉分区

3、consumer -> 分区


  • RangeAssignor分配策略;
  • RoundRobinAssignor分配策略;
  • StickyAssignor分配策略


Leader 选举


副本同步机制

所谓同步,必须满足如下两个条件:


  • 副本节点必须能与zookeeper保持会话(心跳机制)
  • 副本能复制leader上的所有写操作,并且不能落后太多。(卡住或滞后的副本控制是由 replica.lag.time.max.ms 配置)

ISR机制

Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。

事实上,同步复制要求所有能工作的follower都复制完,这条消息才会被commit,这种复制方式极大的影响了吞吐率。

而异步复制方式下,follower异步的从leader复制数据,数据只要被leader写入log就被认为已经commit,这种情况下如果follower都还没有复制完,落后于leader时,突然leader宕机,则会丢失数据。

而Kafka的这种使用ISR的方式则很好的均衡了确保数据不丢失以及吞吐率。

副本不同步的异常情况:


  • 慢副本:在一定周期时间内follower不能追赶上leader。最常见的原因之一是I / O瓶颈导致follower追加复制消息速度慢于从leader拉取速度。
  • 卡住副本:在一定周期时间内follower停止从leader拉取请求。follower replica卡住了是由于GC暂停或follower失效或死亡。
  • 新启动副本:当用户给主题增加副本因子时,新的follower不在同步副本列表中,直到他们完全赶上了leader日志。


文件存储机制

稀疏索引、二分法

通过offset查找message

1、使用offset 通过二分法定位对应的.index文件和.log 文件。

2、通过 .log文件顺序查找到对应的offset偏移对应的消息。


数据可靠性和一致性保证

ISR机制;

request.required.acks 参数;

min.insync.replicas 参数。


类似 PacificA 算法。



kafka消息传递语义

消息传递保障


  • At most once: 消息可能会丢,但绝不会重复传输
  • At least once:消息绝不会丢,但可能会重复传输
  • Exactly once:每条消息肯定会被传输一次且仅传输一次

消息去重


  • 业务端去重


六、高性能

顺序读写、

page cache、

零拷贝:senfile。


page cache

用作缓存磁盘文件的内存就叫做page cache。

  CPU如果要访问外部磁盘上的文件,需要首先将这些文件的内容拷贝到内存中,由于硬件的限制,从磁盘到内存的数据传输速度是很慢的,

如果现在物理内存有空余,可以用这些空闲内存来缓存一些磁盘的文件内容,这部分用作缓存磁盘文件的内存就叫做page cache。 

  用户进程启动read()系统调用后,内核会首先查看page cache里有没有用户要读取的文件内容,如果有(cache hit),那就直接读取,

没有的话(cache miss)再启动I/O操作从磁盘上读取,然后放到page cache中,下次再访问这部分内容的时候,就又可以cache hit,不用忍受磁盘的龟速了(相比内存慢几个数量级)。 

和CPU里的硬件cache是不是很像?两者其实都是利用的局部性原理,只不过硬件cache是CPU缓存内存的数据,而page cache是内存缓存磁盘的数据,这也体现了memory hierarchy分级的思想。 

相对于磁盘,内存的容量还是很有限的,所以没必要缓存整个文件,只需要当文件的某部分内容真正被访问到时,再将这部分内容调入内存缓存起来就可以了,

这种方式叫做demand paging(按需调页),把对需求的满足延迟到最后一刻,很懒很实用。


七、消息可靠性保障(消息数据不丢失)

1、生产端:重试机制 + ACK(acknowledge)

2、服务端:多副本

3、消费端:手动提交


ACKS

配置生产端 ACK

当 producer 向 leader 发送数据时,可以通过 request.required.acks 参数以及 min.insync.replicas 设置数据可靠性的级别。


  • 当 acks = 1时(默认值),生产者在 ISR 中的 leader 已成功收到数据可以继续发送下一条数据。如果 leader 宕机,由于数据可能还未来得及同步给其 follower,则会丢失数据。
  • 当 acks = 0时,生产者不等待来自 broker 的确认就发送下一条消息。这种情况下数据传输效率最高,但数据可靠性确最低。
  • 当 acks = -1或者 all 时,生产者需要等待 ISR 中的所有 follower 都确认接收到消息后才能发送下一条消息,可靠性最高。


  即使按照上述配置 ACK,也不能保证数据不丢,例如,当 ISR 中只有 leader 时(ISR 中的成员由于某些情况会增加也会减少,最少时只剩一个 leader),

此时会变成 acks = 1的情况。所以需要同时在配合 min.insync.replicas 参数(此参数可以在消息队列 CKafka 控制台 Topic 配置开启高级配置中进行配置),

min.insync.replicas 表示在 ISR 中最小副本的个数,默认值是1,当且仅当 acks = -1或者 all 时生效。


建议配置的参数值

此参数值仅供参考,实际数值需要依业务实际情况而定。


  • 重试机制:​​message.send.max.retries=3;retry.backoff.ms=10000;​
  • 高可靠的保证:​​request.required.acks=-1;min.insync.replicas=2;​
  • 高性能的保证:​​request.required.acks=0;​
  • 可靠性+性能:​​request.required.acks=1;​



八、消息分发模型 - Kafka 发布消息时如何选择 Partition

Kafka 默认(当 key 为 null) 时采用 Round-robin 策略。

但我们实际应用中为保持相关消息按序到,就必须送到指定的 Partition,方法可以有:


  • 指定 Partition 编号
  • 指定 Key
  • 自定义 Partitioner - 实现 org.apache.kafka.clients.producer.Partitioner, 并通过属性注册


消息发送模式:

发后即忘、同步、异步。 


九、再均衡的发生过程

一句话:为消费者分配分区

Kafka中消费者以消费组的形式存在,消费组来消费每个主题中分区的数据,因为主题中的分区数和消费者数量并不一一对应,

这时候就涉及到如何为每个消费者分配分区,而当有消费者在中途退出时,就会触发再均衡的发生,再重新为剩余的消费者分配分区。

每个消费组在服务端对应一个GroupCoordinator对其进行管理,而消费者客户端中的ConsumerCoordinator组件负责与GroupCoordinator进行交互,

它们负责执行分区的分配,以及消费者再均衡的操作。

目前在以下几种情况会触发再均衡操作。


  • 有新的消费者加入消费组。
  • 消费者宕机下线。消费者并不一定需要真正下线,例如遇到长时间的GC、网络延迟等情况,导致消费者长时间未向GroupCoordinator 发送心跳,GroupCoordinator认为消费者已经下线。
  • 有消费者主动退出消费组。
  • 消费组所对应的GroupCoorinator 节点发生了变更。
  • 消费组内所订阅的任一主题或者主题的分区数量发生变化。


再均衡时 cousumer 停止工作。


十、kafka扩容

1、新增节点

2、生成重新分配topic的方案

3、执行分配方案

4、查看分配进度、状态

注意:需要手动执行


十一、高级应用

注意:以下大部分功能原生不支持,需要定制开发。 

过期时间(TTL)

延时队列

死信队列

重试队列

消息路由

消息轨迹

消息审计

消息代理(proxy)


十二、其他

副本同步

ISR(in-sync replicas):同步副本集合,只有 ISR 里的成员才有被选为 Leader 的可能。

OSR(Outof-sync replicas):

AR(Assigned Replicas):所有副本的总和。

AR = ISR + OSR

HW(HighWatermark):高水位。一个partition中的ISR列表中,leader的HW是所有ISR列表里副本中最小的那个的LEO。代表partition中已提交可消费的最大offset。

LEO(log end offset):日志末端位移,代表日志文件中下一条待写入消息的offset,这个offset上实际是没有消息的。



重要参数

request.required.acks:消息发送成功确认方式。

min.insync.replicas:设定ISR中的最小副本数是多少,默认值为1,当且仅当request.required.acks参数设置为-1时,此参数才生效。可以在broker或者topic层面进行设置。

offsets.topic.replication.factor:副本因子,最小写入副本数的个数,partition 副本数。数据冗余备份数。

unclean.leader.election.enable:ISR 副本同步列表 参与选举参数。

producer.type=sync:消息生产模式,同步模式,异步模式。


安装部署

  kafka需要java运行环境,以前的kafka还需要zookeeper,新版的kafka已经内置了一个zookeeper环境,所以我们可以直接使用。


监控工具

  Kafka Eagle


刷盘落盘

  刷盘:pagecache -》硬盘

  落盘:刷盘成功,数据成功写入硬盘