Kafka 原理总结

概念 

关键名词解释

生产过程分析

Broker 保存消息

Kafka 集群为什么需要集成 zookeeper

消费者组

消费方式

Consumer API 的使用

Producer拦截器(interceptor)

Kafka Streams

Kafka 与 Flume


概念 

Apache Kafka 是一个开源消息系统,由 Scala 写成,由 LinkedIn 公司开发,是一个分布式消息队列

Kafka 对消息保存时根据 Topic 进行归类,发送消息者称为 Producer,消息接受者称为 Consumer,kafka 集群有多个 kafka 实例组成,每个实例(server)称为 broker

无论是 kafka 集群,还是 consumer 都依赖于 zookeeper 集群保存一些 meta 信息,来保证系统可用性

0.8 版本之前 生产者向 broker 传消息需要先向 zookeeper 通信, 在 zookeeper 上储存元数据信息, 0.8 之后便不需要, 直接把元数据信息存放在 broker 上, 目的为减少不必要的连接, 提高效率

 

关键名词解释

Broker :一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker 可以容纳多个 topic

Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的 id(offset)。kafka 只保证按一个 partition 中的顺序将消息发给consumer,不保证一个 topic 的整体(多个 partition 间)的顺序;

Offset:kafka 的存储文件都是按照 offset.kafka 来命名,用 offset 做名字的好处是方便查找。例如你想找位于 2049 的位置,只要找到 2048.kafka 的文件即可。当然 the first offset 就是 00000000000.kafka

 

生产过程分析

  • 写入方式

producer 采用推(push)模式将消息发布到 broker,每条消息都被追加(append)到分区( patition)中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 吞吐率)

主要实现步骤

  1. 首先创建一个 ProducerRecord 对象,ProducerRecord 对象需要包含目标主题(Topic)和要发送的内容(Value),也可以指定键或分区。

  2. 发送 ProducerRecord 对象需要序列化成字节数组,这样才能够在网络上传输。

  3. 然后数据被传给分区器。如果在 ProducerRecord 对象里指定了分区,那么分区器不做任何事情,直接返回指定分区。 如果没有指定分区,分区器会根据 ProducerRecord 对象的键来选择一个分区。

  4. 选好分区以后,生产者就知道该往哪个主题和分区发送这条记录了。 这条记录被添加到一个记录批次里,这个批次里的所有消息会被发送到相同的主题和分区 broker 上。

  5. 服务器在收到这些消息时会返回一个响应。如果消息成功写入 Kafka,就返回一个RecordMetaData 对象, 它包含了主题(Topic)和分区(Partition)信息, 以及记录在分区里的偏移量。 如果写入失败, 则会返回一个错误。 生产者在收到错误之后会尝试重新发送消息,几次之后如果还是失败,就返回错误信息。

  • 分区(Partition)

消息发送时都被发送到一个 topic,其本质就是一个目录,而 topic 是由一些 Partition Logs (分区日志)组成,每个 Partition 中的消息都是有序的,生产的消息被不断追加到 Partition log 上,其中的每一个消息都被赋予了一个唯一的 offset 值。

 

不同消费者组中的消费者可以消费同一个分区的数据, 可以选择从哪个 offset 开始消费, 也可以选择消费到哪个 offset 结束, (需要编写 java 程序并使用低级API实现) 

分区的原因

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

(2)可以提高并发,因为可以以 patition 为单位读写了。Kafak 会尽量均衡的分布 leader 所在分区

分区的原则

(1)指定了 patition,则直接使用;

(2)未指定 patition 但指定 key,通过对 key 的 value 进行 hash 出一个 patition;

(3)patition 和 key 都未指定,使用轮询选出一个 patition

 

  • 副本(Replication)

对应 server.properties 配置中的 default.replication.factor=N, 提高数据的安全性。同一个 partition 可能设置多个 replication,需要在这些 replication 之间选出一个leader,producer 和 consumer 只与这个 leader 交互,其它 replication 作为 follower 从 leader中复制数据。

  • producer 写入流程(0.8版之前, 新版本会在后面说明)

1)producer 先从 zookeeper 的 "/brokers/.../state"节点找到该 partition 的 leader

2)producer 将消息发送给该 leader

3)leader 将消息写入本地 log

4)followers 从 leader pull 消息,写入本地 log 后向 leader 发送 ACK(Acknowledgement 确认字符/命令正确应达)

5)leader 收到所有 ISR(in-sync replicas 同步副本) 中的 replication 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset)并向 producer 发送 ACK

6 )根据配置的ACK值 动作不同, ACK 可以为 0, 1, all, 表示 leader 写入完成即发送ACK/一个/全部follower写入完成发送ACK

 

Broker 保存消息

  • 存储方式

物理上把 topic 分成一个或多个 patition(对应 server.properties 中的 num.partitions=3 配置),每个 patition 物理上对应一个文件夹(该文件夹存储该 patition 的所有消息和索引文件, 后缀为 .index, .log, .timeindex 和 leader-epoch-checkpoint 文件)

  • 存储策略

无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据:

1)基于时间:log.retention.hours=168

2)基于大小:log.retention.bytes=1073741824

Kafka 读取特定消息的时间复杂度为 O(1),与文件大小无关,即删除过期文件与提高 Kafka 性能无关

 

Kafka 集群为什么需要集成 zookeeper

zookeeper 为 kafka 提供了集群的元数据保存管理, 解决分布式一致性, 并提供负载均衡, 提高集群可用性和稳定性

注意: 灰框中的信息 0.8 版本之前维护在 zk, 0.8 版之后维护在 broker, 减少了一次连接(生产者写数据不需要与 zk 通信再转到 broker, 直接与 broker 通信并将元数据保存在 broker 上), 提高效率

即: 0.8版本之后 producer 不在 zk 中注册,只有消费者在 zk 中注册

 

消费者组

由一个或者多个消费者组成一个组,共同消费一个 topic,即为消费者组。每个分区在同一时间只能由 group 中的一个消费者读取,但是多个 group 可以同时消费这个 partition

图中是一个由三个消费者组成的 group,Consumer1 读取主题中的两个分区,另外两个分别读取一个分区。某个消费者读取某个分区,也可以叫做某个消费者是某个分区的拥有者(owner)

如果一个消费者失败了,那么其他的 group 成员会自动负载均衡读取之前失败的消费者读取的分区。

 

消费方式

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

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

它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而 pull 模式则可以根据 consumer 的消费能力以适当的速率消费消息 consumer 可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义

注意: 如果 kafka 没有数据,消费者可能会陷入循环中,一直等待数据到达。解决: 在拉请求中设置参数,允许消费者请求在等待数据的“长轮询”中进行阻塞(可指定拉取的字节数,以确保消息的传输大小)

 

Consumer API 的使用

API 分为高级和低级

高级简单易用, 但不能指定 offset, 可自定义参数有限, 低级复杂, 可定制度高

1)消费者使用低级API 的主要步骤:

步骤

主要工作

1

根据指定的分区从主题元数据中找到主副本

2

获取分区最新的消费进度

3

从主副本拉取分区的消息

4

识别主副本的变化,重试

2)方法描述:

findLeader()

客户端向种子节点发送主题元数据,将副本集加入备用节点

getLastOffset()

消费者客户端发送偏移量请求,获取分区最近的偏移量

run()

消费者低级AP I拉取消息的主要方法

findNewLeader()

当分区的主副本节点发生故障,客户将要找出新的主副本

 

Producer拦截器(interceptor)

原理

Producer 拦截器(interceptor) 在 Kafka 0.10 版本被引入,主要用于 clients 端的定制化控制逻辑,比如修改消息等。同时,producer 允许用户指定多个 interceptor 按序作用于同一条消息从而形成一个拦截链(interceptor chain)。Intercetpor 的实现接口是 org.apache.kafka.clients.producer.ProducerInterceptor,其定义的方法包括:

(1)configure(configs) 获取配置信息和初始化数据时调用。

(2)onSend(ProducerRecord): 该方法封装进 KafkaProducer.send 方法中,即它运行在用户主线程中。Producer 确保在消息被序列化以及计算分区前调用该方法。用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的 topic 和分区,否则会影响目标分区的计算

(3)onAcknowledgement(RecordMetadata, Exception): 该方法会在消息被应答或消息发送失败时调用,并且通常都是在 producer 回调逻辑触发之前。onAcknowledgement 运行在 producer 的 IO 线程中,因此不要在该方法中放入很重的逻辑,否则会拖慢 producer 的消息发送效率

(4)close: 关闭 interceptor,主要用于执行一些资源清理工作

interceptor 可能被运行在多个线程中,因此在具体实现时用户需要自行确保线程安全。另外倘若指定了多个 interceptor,则 producer 将按照指定顺序调用它们,并仅仅是捕获每个 interceptor 可能抛出的异常记录到错误日志中而非在向上传递。这在使用过程中要特别留意。

生产者拦截器, 至少需要两个类, 一个自定义拦截器类, 需要实现 ProducerInterceptor 接口, 一个producer 主程序, 如果有多个拦截器. 要在主程序中构建拦截链

List<String> interceptors = new ArrayList<>();   interceptors.add("com.rayfunc.kafka.interceptor.TimeInterceptor");  interceptors.add("com.rayfunc.kafka.interceptor.CounterInterceptor");    props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, interceptors);

 

Kafka Streams

Apache Kafka 开源项目的一个组成部分。一个功能强大,易于使用的库。用于在 Kafka 上构建高可分布式、拓展性,容错的应用程序

特点

  • 高扩展性,弹性,容错 
  • 轻量  无需专门的集群  一个库,而不是框架
  • 集成 与 Kafka 0.10.0 版本完全兼容, 易于集成到现有的应用程序 
  • 实时 毫秒级延迟 

为什么要有 Kafka Stream

  • 方便调试, Kafka Stream 提供的是一个基于 Kafka 的流式处理类库。框架具体运行方式理解难度高,调试成本高,使用受限。Kafka Stream 作为流式处理类库,直接提供具体的类供调用,运行方式主要由开发者控制
  • 作为类库,可以非常方便的嵌入应用程序中对应用的打包和部署基本没有任何要求
  • 流式处理系统基本都支持 Kafka 作为数据源。如 Spark 提供专门的 spark-streaming-kafka 模块。Kafka 基本上是主流的流式处理系统的标准数据源。大部分流式系统中都已部署了 Kafka使用 Kafka Stream 的成本非常低
  • 使用 Storm 或 Spark Streaming 时,需要为框架本身的进程预留资源,如 Storm的 supervisor 和 Spark on YARN 的 node manager。即使对于应用实例而言,框架本身也会占用部分资源,如 Spark Streaming 需要为 shuffle 和 storage 预留内存。但是 Kafka 作为类库不占用系统资源
  • Kafka 本身提供数据持久化,因此 Kafka Stream 提供滚动部署和滚动升级以及重新计算的能力
  • 由于 Kafka Consumer Rebalance 机制,Kafka Stream 可以在线动态调整并行度

 

Kafka 与 Flume

flume:cloudera 公司研发: 

适合多个生产者;

适合下游数据消费者不多的情况;

适合数据安全性要求不高的操作;

适合与 Hadoop 生态圈对接的操作。

kafka:linkedin 公司研发:

适合数据下游消费众多的情况;

适合数据安全性要求较高的操作,

支持 replication。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值