Kafka原理和架构特点

442 阅读7分钟

Kafka产生背景和发展

产生背景

kafka的诞生,是为了解决linkedin的数据管道问题,起初linkedin采用了ActiveMQ来进行数据交换,大约是在2010年前后,那时的ActiveMQ还远远无法满足linkedin对数据传递系统的要求,经常由于各种缺陷而导致消息阻塞或者服务无法正常访问,为了能够解决这个问题,linkedin决定研发自己的消息传递系统,当时linkedin的首席架构师jay kreps便开始组织团队进行消息传递系统的研发,kafka由此诞生。 Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

kafka的作用

一 削峰

在高并发环境下,系统的处理能力如Mysql的并发能力成为系统的短板,高并发情景将导致系统崩溃,利用kafka的高吞吐能力,将大量的请求先缓存到kafka中,再按系统能力拉取到系统处理

kafka

二解耦

使用kafka作为数据的管道,可以通过定义的统一的数据格式对外提供服务,而不对两边的服务形式进行规定,降低了系统的耦合性

image.png

三 异步通信

将信息写入kafka,并不立即去处理它,等需要再去处理它

image.png

Kafka强劲性能的来源

一 顺序读写

数据在磁盘顺序写入,机械磁盘可保证600M/s的写入速度,机械硬盘也可以满足要求

二 页缓存和零拷贝

kafka的零拷贝技术免除了应用层缓存和套接字缓存的开销,直接将数据写入网卡发送给消费者

image.png

三 分区并行

kafka可以并行消费数据,性能高

四 稀疏索引

kafka数据存储使用稀疏索引结构,可以快速定位数据,稀疏索引在kafka详细介绍

image.png

kafka的架构

kafka的架构特点(传统的架构)

kafka架构图

kafka几个名词的介绍

  • (1)Producer:消息生产者,就是向 Kafka broker 发消息的客户端。
  • (2)Consumer:消息消费者,向 Kafka broker 取消息的客户端。
  • (3)Consumer Group(CG):消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
  • (4)Broker:一台 Kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个broker 可以容纳多个 topic。
  • (5)Topic:可以理解为一个队列,生产者和消费者面向的都是一个 topic。
  • (6)Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。
  • (7)Replica:副本。一个 topic 的每个分区都有若干个副本,一个 Leader 和若干个Follower。
  • (8)Leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 Leader。
  • (9)Follower:每个分区多个副本中的“从”,实时从 Leader 中同步数据,保持和Leader 数据的同步。Leader 发生故障时,某个 Follower 会成为新的 Leader。

kafka的生产流程

生产者发送数据流程

  1. 生产者生产信息,由RecordAccumulatorRecordAccumulator的线程多队列发送给Sender线程
  2. Sender 的数据达到设定的批次大小(batch size参数配置),数据发送到broker

几个重要的生产者配置参数

生产者几个重要参数
kbootstrap.servers生产者连接集群所需的 broker 地 址 清 单 。 例 如
hadoop102:9092,hadoop103:9092,hadoop104:9092,可以
设置 1 个或者多个,中间用逗号隔开。
key.serializer 和 value.serializerkey.serializer 和 value.serializer (一般为String格式)
buffer.memoryRecordAccumulator 缓冲区总大小,默认 32m
batch.size缓冲区一批数据最大值,默认 16k。适当增加该值,可以提高吞吐量,但是如果该值设置太大,会导致数据传输延迟增加。
linger.ms如果数据迟迟未达到 batch.size,sender 等待 linger.time之后就会发送数据。单位 ms,默认值是 0ms,表示没有延迟。生产环境建议该值大小为 5-100ms 之间。
acks0:生产者发送过来的数据,不需要等数据落盘应答。1:生产者发送过来的数据,Leader 收到数据后应答。-1(all):生产者发送过来的数据,Leader+和 isr 队列里面的所有节点收齐数据后应答。默认值是-1,-1和all 是等价的。
max.in.flight.requests.per.connection允许最多没有返回 ack 的次数,默认为 5,开启幂等性要保证该值是 1-5 的数字。
retry.backoff.ms两次重试之间的时间间隔,默认是 100ms。
compression.type生产者发送的所有数据的压缩方式。默认是 none,也就是不压缩。支持压缩类型:none、gzip、snappy、lz4 和 zstd。
max.in.flight.requests.per.connection保证分区内最新倒数几条数据有序有序,建议最大设置为5

几个生产者相关的总结

幂等性的解释

幂等性默认是开启的,但是幂等性用处可以防止分区内数据的重复,判断的标准是<PID, Partition, SeqNumber>,SeqNumber单调递增

ack机制的讨论

  • ack=0,简单来说就是,producer发送一次就不再发送了,不管是否发送成功。
  • ack=-1,简单来说就是,producer只有收到分区内所有副本的成功写入的通知才认为推送消息成功了。
  • ack=1的情况下,producer只要收到分区leader成功写入的通知就会认为消息发送成功了。如果leader成功写入后,还没来得及把数据同步到follower节点就挂了,这时候消息就丢失了。

消费者消费数据的流程

消费者消费流程

分区从消费者组中选择消费者,由指定的消费者消费数据,一个分区只能由一个消费者组消费

image.png

关于分区的消费者的选择策略

kafka的Coordinator负责消费者分区的选择,具体的流程可以参考这篇文章,流程可以简化为

  • 消费者多个消费者向Coordinator发送注册信息
  • Coordinator决定leader和follower,所有consumer都往coordinator发送JoinGroup消息之后, coordinator会指定其中一个consumer作为leader,并把组成员信息以及订阅信息发给leader,其他consumer作为follower,然后由这个leader进行partition分配
  • leader会将这个方案封装进SyncGroup请求中发给Coordinator,Coordinator给它返回null,follower发送 null的 SyncGroupRequest 给Coordinator,Coordinator回给它partition分配的结果

image.png

消费者参数
group.id标记消费者所属的消费者组
enable.auto.commit默认值为 true,消费者会自动周期性地向服务器提交偏移量。
auto.commit.interval.ms如果设置了 enable.auto.commit 的值为 true, 则该值定义了消费者偏移量向 Kafka 提交的频率,默认 5s。
auto.offset.reset当 Kafka 中没有初始偏移量或当前偏移量在服务器中不存在(如,数据被删除了),该如何处理? earliest:自动重置偏移量到最早的偏移量。latest:默认,自动重置偏移量为最新的偏移量。 none:如果消费组原来的(previous)偏移量不存在,则向消费者抛异常。 anything:向消费者抛异常
offsets.topic.num.partitions__consumer_offsets 的分区数,默认是 50 个分区
heartbeat.interval.msKafka 消费者和 coordinator 之间的心跳时间,默认 3s。 该条目的值必须小于 session.timeout.ms ,也不应该高于session.timeout.ms 的 1/3。
session.timeout.msKafka 消费者和 coordinator 之间连接超时时间,默认 45s。超过该值,该消费者被移除,消费者组执行再平衡。
max.poll.interval.ms消费者处理消息的最大时长,默认是 5 分钟。超过该值,该消费者被移除,消费者组执行再平衡。
fetch.min.bytes默认 1 个字节。消费者获取服务器端一批消息最小的字节数。
fetch.max.wait.ms默认 500ms。如果没有从服务器端获取到一批数据的最小字节数。该时间到,仍然会返回数据。
max.poll.records一次 poll 拉取数据返回消息的最大条数,默认是 500 条。