kafka

415 阅读17分钟

前序:

今天去面试,介绍了项目,但总结下来:项目部分说的不太好,不够详细,不够高大上,没有展示亮点(亮点没点睛)。。。。待改进

被问了很多kafka和zk的原理知识,之前只是懂了皮毛,内部深意还需要补回来,所以出来混早晚是要还的。。。。

1、lafaka

磁盘:影响生产者

内存:影响消费者

网络

cpu

2、参数

顺序保证:重试场景,设置参数:max.in.flight.requests.per.connection = 1,设为1,这样在生产者尝试发送第一批消息时,就不会有其他的消息发送给broker(不允许其他消息发送到这个节点),这个值默认是5,值1使得生产者的效率很低,对顺序有严格要求的场景可以用。

3、序列化

kafaka只接收字节数组

kafka的序列化器是:avro序列化器

4、分区器

默认分区规则:根据key值

自定义分区

序列化、分区器、拦截器

5、消费者

分区再均衡

-------

总揽

------------

1、经验总结:

(1)Kafka 如何实现高可用:kafka集群

  • Zookeeper 部署 2N+1 节点,形成 Zookeeper 集群,保证高可用。

  • Kafka Broker 部署集群。每个 Topic 的 Partition ,基于【副本机制】,在 Broker 集群中复制,形成 replica 副本,保证消息存储的可靠性。每个 replica 副本,都会选择出一个 leader 分区(Partition),提供给客户端(Producer 和 Consumer)进行读写。

  • Kafka Producer 无需考虑集群,因为和业务服务部署在一起。Producer 从 Zookeeper 拉取到 Topic 的元数据后,选择对应的 Topic 的 leader 分区,进行消息发送写入。而 Broker 根据 Producer 的 request.required.acks 配置,是写入自己完成就响应给 Producer 成功,还是写入所有 Broker 完成再响应。这个,就是胖友自己对消息的可靠性的选择。

  • Kafka Consumer 部署集群。每个 Consumer 分配其对应的 Topic Partition ,根据对应的分配策略。并且,Consumer 只从 leader 分区(Partition)拉取消息。另外,当有新的 Consumer 加入或者老的 Consumer 离开,都会将 Topic Partition 再均衡,重新分配给 Consumer 。

总的来说,Kafka 和 RocketMQ 的高可用方式是比较类似的,主要的差异在 Kafka Broker 的副本机制,和 RocketMQ Broker 的主从复制,两者的差异,以及差异带来的生产和消费不同。

(2)多副本冗余的高可用机制

比如说zookeeper、kafka、redis cluster、elasticsearch、hdfs,等等,其有自己内部的一套多副本冗余的机制,多副本冗余几乎是现在任何一个优秀的分布式系统都一般要具备的功能。

在kafka集群中,每个Partition都有多个副本,其中一个副本叫做leader,其他的副本叫做follower 

(3)多副本之间数据如何同步

接着我们就来看看多个副本之间数据是如何同步的?

其实任何一个Partition,只有Leader是对外提供读写服务的 也就是说,如果有一个客户端往一个Partition写入数据,此时一般就是写入这个Partition的Leader副本。 然后Leader副本接收到数据之后,Follower副本会不停的给他发送请求尝试去拉取最新的数据,拉取到自己本地后,写入磁盘中。

(4)ISR

ISR全称是“In-Sync Replicas”,也就是保持同步的副本,他的含义就是,跟Leader始终保持同步的Follower有哪些。

所以每个Partition都有一个ISR,这个ISR里一定会有Leader自己,因为Leader肯定数据是最新的,然后就是那些跟Leader保持同步的Follower,也会在ISR里。

(5)acks

首先这个acks参数,是在KafkaProducer,也就是生产者客户端里设置的,也就是说,你往kafka写数据的时候,就可以来设置这个acks参数。

当生产者向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:

  • 1(默认) 数据发送到Kafka后,经过leader成功接收消息的的确认,就算是发送成功了。在这种情况下,如果leader宕机了,则会丢失数据。

  • 0 生产者将数据发送出去就不管了,不去等待任何返回。这种情况下数据传输效率最高,但是数据可靠性确是最低的。

  • all(-1) producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。

(6)Kafka Producer 有哪些发送模式?

Kafka 的发送模式由 Producer 端的配置参数 producer.type来设置。

  • 这个参数指定了在后台线程中消息的发送方式是同步的还是异步的,默认是同步的方式,即 producer.type=sync

  • 如果设置成异步的模式,即 producer.type=async ,可以是 Producer 以 batch 的形式 push 数据,这样会极大的提高 Broker的性能,但是这样会增加丢失数据的风险。(生产者如果异步发送,会造成消息丢失,发送的过程中kafka会先把消息缓存起来。然后批量发送。 若批量发送之前client宕机会造成消息丢失。生产者不丢失消息需要同步发送)

  • 如果需要确保消息的可靠性,必须要将 producer.type设置为 sync 。

(7)kafka如何保证数据的不丢失

**Broker 弄丢数据:**所以此时一般是要求起码设置如下 4 个参数:

  • 给 Topic 设置 replication.factor 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。

  • 在 Kafka 服务端设置 min.insync.replicas 参数:这个值必须大于 1 ,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。

  • kafka Producer 端发送模式,配置参数 producer.type = sync;

  • 在 Producer 端设置 acks=all:这个是要求每条数据,必须是写入所有 replica 之后,才能认为是写成功了。

  • 在 Producer 端设置 retries=MAX(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里了。

生产者会不会弄丢数据:

  • 如果按照上述的思路设置了 acks=all ,一定不会丢,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。

消费者会不会丢数据

  • 关闭自动提交

  • 通过offset commit 来保证数据的不丢失,kafka自己记录了每次消费的offset数值,下次继续消费的时候,接着上次的offset进行消费即可。

Offset一般由消费者管理,当然也可以通过程序按需要设置。Offset只有commit以后,才会改变,否则,你将一直获取重复的数据。新的kafka已经将这些Offset的放到了一个专有的主题:__consumer_offsets,就是上图的紫色区域。

2、基础回顾

在bilibili看的kafka的学习视频,从入门到精通;本文只是对视频的学习做一下笔记。

一、消息队列

(1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)

(2)发布/订阅模式(一对多,数据生产后,推送给所有订阅者)

二、为什么需要消息队列

1)解耦:

2)冗余:

3)扩展性:

4)灵活性 & 峰值处理能力:

5)可恢复性:

6)顺序保证:Kafka保证一个Partition内的消息的有序性

7)缓冲:

8)异步通信:

三、什么是kafka

在流式计算中,Kafka一般用来缓存数据,Storm通过消费Kafka的数据进行计算。

  • 1)Apache Kafka是一个开源消息系统,由Scala写成。

  • 2)**Kafka****是一个分布式消息队列。**Kafka对消息保存时根据Topic进行归类,发送消息者称为Producer,消息接受者称为Consumer,此外kafka集群有多个kafka实例组成,每个实例(server)称为broker。

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

0、kafka特点 

1)吞吐量 

同时为发布和订阅提供高吞吐量。据了解,Kafka 每秒可以生产约 25 万消息(50MB),每秒处理 55 万消息(110MB)

  • 1、数据磁盘持久化:消息不在内存中 Cache ,直接写入到磁盘,充分利用磁盘的顺序读写性能。

  • 2、zero-copy:减少 IO 操作步骤

  • 3、数据批量发送

  • 4、数据压缩

  • 5、Topic 划分为多个 Partition ,提高并行度。

2)负载均衡

  • 1、Producer 根据用户指定的算法,将消息发送到指定的 Partition 中。

  • 2、Topic 存在多个 Partition ,每个 Partition 有自己的replica ,每个 replica 分布在不同的 Broker 节点上。多个Partition 需要选取出 Leader partition ,Leader Partition 负责读写,并由 Zookeeper 负责 fail over 。

  • 3、相同 Topic 的多个 Partition 会分配给不同的 Consumer 进行拉取消息,进行消费。

3)拉取系统

由于 Kafka Broker 会持久化数据,Broker 没有内存压力,因此, Consumer 非常适合采取 pull 的方式消费数据,具有以下几点好处:

  • 1、简化 Kafka 设计。
  • 2、Consumer 根据消费能力自主控制消息拉取速度。
  • 3、Consumer 根据自身情况自主选择消费模式,如批量,重复消费,从尾端开始消费等。

4)可扩展性

通过 Zookeeper 管理 Broker 与 Consumer 的动态加入与离开。

  • 当需要增加 Broker 节点时,新增的 Broker 会向 Zookeeper 注册,而 Producer 及 Consumer 会根据注册在 Zookeeper 上的 watcher 感知这些变化,并及时作出调整。
  • 当新增和删除 Consumer 节点时,相同 Topic 的多个 Partition 会分配给剩余的 Consumer 们。

总结的很好,摘自芋道源码

1、kafka架构

  • 1)Producer :消息生产者,就是向kafka broker发消息的客户端;

  • 2)Consumer :消息消费者,向kafka broker取消息的客户端;

  • 3)Topic :可以理解为一个队列;

  • 4) Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个partion只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic;

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

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

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

三、Kafka工作流程分析 

1 Kafka生产过程

1.1 producer发送消息

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

1.2 分区(Partition):负载均衡 + 水平扩展

消息发送时都被发送到一个topic,其本质就是一个目录,而topic是由一些Partition Logs(分区日志)组成,其组织结构如下图所示:

可以看到,每个Partition中的消息都是有序的,生产的消息被不断追加到Partition log上,其中的每一个消息都被赋予了一个唯一的offset值。

1)分区的原因

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

  • (2)可以提高并发,因为可以以Partition为单位读写了。

2)分区的原则

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

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

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

1.3 副本(Replication)

同一个partition可能会有多个replication(对应 server.properties 配置中的 default.replication.factor=N)。没有replication的情况下,一旦broker 宕机,其上所有 patition 的数据都不可被消费,同时producer也不能再将数据存于其上的patition。引入replication之后,同一个partition可能会有多个replication,而这时需要在这些replication之间选出一个leader,producer和consumer只与这个leader交互,其它replication作为follower从leader 中复制数据。

(1)、Kafka 的副本机制是怎么样的?

  1. Kafka 的副本机制,是多个 Broker 节点对其他节点的 Topic 分区的日志进行复制。

  2. Kafka 每个主题的每个分区都有一个主副本以及 0 个或者多个副本,副本保持和主副本的数据同步,当主副本出故障时就会被替代。

选举leader策略:在 Kafka 中并不是所有的副本都能被拿来替代主副本,所以在 Kafka 的Leader 节点中维护着一个 ISR(In sync Replicas)集合,翻译过来也叫正在同步中集合,在这个集合中的需要满足两个条件:

  • 1、节点必须和 Zookeeper 保持连接。
  • 2、在同步的过程中这个副本不能落后主副本太多。

(2)数据可靠级别

当 Producer 向 Leader 发送数据时,可以通过request.required.acks 参数来设置数据可靠性的级别:

  • 1(默认):这意味着 Producer 在 ISR 中的 Leader 已成功收到的数据并得到确认后发送下一条 message 。如果 Leader 宕机了,则会丢失数据。

  • 0:这意味着 Producer 无需等待来自 Broker 的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。

  • -1:Producer 需要等待 ISR 中的所有 Follower 都确认接收到数据后才算一次发送完成,可靠性最高。但是这样也不能保证数据不丢失,比如当 ISR 中只有 Leader 时(其他节点都和 Zookeeper 断开连接,或者都没追上),这样就变成了 acks=1 的情况。

1.4 写入流程

producer写入消息流程

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

  • 2)producer将消息发送给该leader

  • 3)leader将消息写入本地log

  • 4)followers从leader pull消息,写入本地log后向leader发送ACK

  • 5)leader收到所有ISR中的replication的ACK后,增加HW(high watermark,最后commit 的offset)并向producer发送ACK

3.2 Broker 保存消息

2.1 存储方式

物理上把topic分成一个或多个patition(对应 server.properties 中的num.partitions=3配置),每个patition物理上对应一个文件夹。

2.2 存储策略

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

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

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

需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。

2.3 Zookeeper存储结构

producer不在zk中注册,消费者在zk中注册 

3.3 Kafka消费过程分析

kafka提供了两套consumer API:高级Consumer API和低级Consumer API。

3.1 消费者组

消费者是以consumer group消费者组的方式工作,由一个或者多个消费者组成一个组,共同消费一个topic。每个分区在同一时间只能由group中的一个消费者读取,但是多个group可以同时消费这个partition。在图中,有一个由三个消费者组成的group,有一个消费者读取主题中的两个分区,另外两个分别读取一个分区。某个消费者读取某个分区,也可以叫做某个消费者是某个分区的拥有者。

在这种情况下,消费者可以通过水平扩展的方式同时读取大量的消息。另外,如果一个消费者失败了,那么其他的group成员会自动负载均衡读取之前失败的消费者读取的分区。

3.2 消费方式

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

pull模式则可以根据consumer的消费能力以适当的速率消费消息。

对于Kafka而言,pull模式更合适,它可简化broker的设计,consumer可自主控制消费消息的速率,同时consumer可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。

pull模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直等待数据到达。为了避免这种情况,我们在我们的拉请求中有参数,允许消费者请求在等待数据到达的“长轮询”中进行阻塞(并且可选地等待到给定的字节数,以确保大的传输大小)。

4、在基于 Kafka 的分布式消息队列中,ZooKeeper 的作用有:

  • 1、Broker 在 ZooKeeper 中的注册。

  • 2、Topic 在 ZooKeeper 中的注册。

  • 3、Consumer 在 ZooKeeper 中的注册。

  • 5、Consumer 负载均衡。

  • 4、Producer 负载均衡。

    主要指的是,Producer 从 Zookeeper 拉取 Topic 元数据,从而能够将消息发送负载均衡到对应 Topic 的分区中。

  • 6、记录消费进度 Offset 。

    Kafka 已推荐将 consumer 的 Offset 信息保存在 Kafka 内部的 Topic 中。

  • 7、记录 Partition 与 Consumer 的关系。

四、Kafka内部网络框架模型分析

       详情

一、总结篇

1、kafka瓶颈

在海量数据下面,会有个瓶颈:使用kafka,如果主题超过100个之后性能会急剧下降,原来kafka有50w并发,现在只有5w-3w,

原因:是由kafka的存储模型导致的,kafka每个主题的每个队列对应的是单独的文件;kafka是基于文件顺序读写的;有100w主题就有100w个文件

数据copy的时候:
1、一个文件可以顺序读写;
2、对多个文件进行写,不是严格的顺序写,这个还涉及到文件的io,cpu需要来回切换。
如果机器有16核有160个主题,cpu需要来回切换,cpu切了那就是线程切了,线程切了你的磁盘读写也要切,
称之为上下文切换,会发生的特别多,那效率全部都在上下文切换去了。

解释了:对于同样的数据量(一个G的大小),“一个文件” 与 “多个目录和多个文件”,效率是不同的。

2、改进

阿里对kafka的存储模型进行了改造

1.0 --对kafka的重写-Java版本

2.0--海量的主题只写一个文件,所有主题共享一个文件,确保了写的高效(高性能的写)。

rocketMQ是kafka的升级版本

调优

京东