kafka是一款分布式的基于发布/订阅模式的消息队列,是目前比较主流的消息中间件,Kafka对消息保存时根据Topic(主题)进行归类,发送消息者称为Producer,消息接受者称为Consumer,此外kafka集群有多个kafka实例组成,每个实例(server)称为broker。无论是kafka集群,还是consumer都依赖于zookeeper集群保存一些meta信息,来保证系统可用性,所以安装kafka需要先间搭建zookeeper集群。
kafka是基于磁盘操作的,不是基于内存操作的,为了提高数据传输性能,kafka使用到了零拷贝技术(sendfile技术);
kafka以高性能高吞吐量闻名,支撑其高性能的几个特性是:零拷贝技术、顺序写磁盘、消息分区。
- 日志聚合:Kafka 通常用于收集和聚合分布式系统中产生的日志数据,以便后续的监控、分析和故障排除。
- 数据流处理:Kafka 可以作为数据流处理平台的基础,用于处理实时数据流,例如事件处理、实时分析和机器学习模型的训练。
- 数据仓库集成:Kafka 可以将数据传输到数据仓库,如Hadoop或Elasticsearch,以进行高级分析和报告。
- 应用程序集成:许多应用程序可以使用 Kafka 作为消息中间件来实现异步通信,包括微服务架构、批处理作业等。
- 流媒体处理:Kafka 可以用于流媒体处理,例如实时监控、事件驱动的应用程序等
Kafka集群中有一个broker会被选举为Controller,负责管理集群broker的上下线,所有topic的分区副本分配和leader选举等工作。Controller的管理工作都是依赖于Zookeeper的。
- Broker 注册:在 Zookeeper 上会有一个专⻔用来进行 Broker 服务器列表记录的节点。每个 Broker 在启动时,都会到 Zookeeper 上进行注册,即到/brokers/ids 下创建属于自己的节点。每个 Broker 就会将自己的IP 地址和端口等信息记录到该节点中去
- Topic 注册:在 Kafka 中,同一个 Topic 的消息会被分成多个分区并将其分布在多个 Broker 上,这些分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护。比如我创建了一个名字为 my-topic 的主题并且它有两个分区,对应到 zookeeper 中会创建这些文件夹:/brokers/topics/my-
topic/Partitions/0、/brokers/topics/my - topic/Partitions/1- 负载均衡:上面也说过了 Kafka 通过给特定 Topic 指定多个 Partition,而各个 Partition 可以分布在不同的Broker 上,这样便能提供比较好的并发能力。对于同一个 Topic 的不同 Partition,Kafka 会尽力将这些Partition 分布到不同的 Broker 服务器上。当生产者产生消息后也会尽量投递到不同 Broker 的 Partition 里面。当 Consumer 消费的时候,Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡。
Zookeeper 是一个开放源码的、高性能的协调服务,它用于 Kafka 的分布式应用。
Zookeeper 主要用于在集群中不同节点之间进行通信。
在 Kafka 中,它被用于提交偏移量,因此如果节点在任何情况下都失败了,它都可以从之前提交的偏移量中获取。
除此之外,它还执行其他活动,如: leader 检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。
①顺序写磁盘:Kafka的producer生产数据,要写入到log文件中,写的过程是一直追加到文件末端,为顺序写。官网有数据表明,同样的磁盘,顺序写能到600M/s,而随机写只有100K/s。这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
②零拷贝技术:“零拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中(发送给不同的订阅者时,都可以使用同一个页面缓存),避免了重复复制操作。如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存。
Kafka是采用了Java提供NIO包中的的FileChannel的transfer方法实现了高性能的IO传输操作,FileChannel提供了transferTo和transferFrom方法,都是采用了调用底层操作系统的sendfile函数来实现的CPU零拷贝机制。
③Topic分区:kafka对每个Topic进行分区提高了并发,也提高了效率。
①类似于消息队列和商业的消息系统,kafka提供对流式数据的发布和订阅
②kafka提供一种持久的容错的方式存储流式数据
③kafka拥有良好的性能,可以及时地处理流式数据
④每条记录由一个键,一个值和一个时间戳组成
1.Broker
一台kafka服务器就是一个broker。一个集群由多个broker组成,每个broker就是一个kafka的实例。
2.Topic
Topic 就是数据主题,kafka建议根据业务系统将不同的数据存放在不同的topic中!Kafka中的Topics总是多订阅者模式,一个topic可以拥有一个或者多个消费者来订阅它的数据。一个大的Topic可以分布式存储在多个kafka broker中!Topic可以类比为数据库中的库!
3.Interceptor
Interceptor 为拦截器,当生产者向kafka发送数据时,数据会先经过拦截器进行拦截处理,多个拦截器可以组成拦截器链,然后再真正发送数据doSend()。
4.Partition
每个topic可以有多个分区,通过分区的设计,topic可以不断进行扩展!即一个Topic的多个分区分布式存储在多个broker;此外通过分区还可以让一个topic被多个consumer进行消费!以达到并行处理!分区可以类比为数据库中的表!kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。
经过拦截器过滤的代码后,会被进行分区,如果没有指定分区,才会走分区器,所以如果想要自定义分区,不能指定分区
5.Offset
生成者每生产一条数据都会追加到指定分区的log文件中,且存储的记录都是有序的,由于不可随机写入,所以顺序是不变的,这个顺序是通过一个称之为offset的id来唯一标识。
kafka自动维护消费者消费的主题各个分区的offset,前提是消费者消费的分区是由kafka分配的,在启动消费者时,只指定了主题,没有指定分区,kafka会将offset数据保存到一个内置主题为__consumer_offsets的主题中,如果指定了分区,那么kafka将不再自动维护offset。
6.Persistence
Persistence即持久化,Kafka 集群保留所有发布的记录,无论他们是否已被消费,都会通过一个可配置的参数:保留期限来控制。举个例子, 如果保留策略设置为2天,一条记录发布后两天内,可以随时被消费,两天过后这条记录会被清除并释放磁盘空间。
Kafka的性能和数据大小无关,所以长时间存储数据没有什么问题
7.Replication
Replication,即副本,每个分区可能会有多个副本,同一个主题每个分区之间的副本都会选出一个leader,而producer与consumer只与leader之间进行交互,其他follower副本则从leader中同步数据。
8.Producer
消息生产者,就是向kafka broker发消息的客户端。生产者负责将记录分配到topic的指定 partition(分区)中,如果没有指定分区,则都卡夫卡依据分区策略进行分配。
9.Consumer
消息消费者,向kafka broker取消息的客户端。每个消费者都要维护自己读取数据的offset。低版本0.9之前将offset保存在Zookeeper中,0.9及之后保存在Kafka的“__consumer_offsets”主题中
consumer采用pull(拉)模式从broker中读取数据
pull模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直返回空数据。针对这一点,Kafka的消费者在消费数据时会传入一个时长参数timeout,如果当前没有数据可供消费,consumer会等待一段时间之后再返回,这段时长即为timeout。
10.Consumer Group
每个消费者都会使用一个消费组名称来进行标识。同一个组中的不同的消费者实例,可以分布在多个进程或多个机器上!
如果所有的消费者实例在同一消费组中,消息记录会负载平衡到每一个消费者实例(单播)。即每个消费者可以同时读取一个topic的不同分区!
如果所有的消费者实例在不同的消费组中,每条消息记录会广播到所有的消费者进程(广播)。
如果需要实现广播,只要每个consumer有一个独立的组就可以了。要实现单播只要所有的consumer在同一个组。
一个topic可以有多个consumer group。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个partion只会把消息发给该CG中的一个consumer。
在Kafka中,Topic和Partition是两个密切相关的概念。
- Topic是Kafka中消息的逻辑分类,可以看作是一个消息的存储类别。它是按照不同的主题对消息进行分类,并且可以用于区分和筛选数据。每个Topic可以有多个Partition,每个Partition都是Topic的一个子集,包含了一部分特定的消息。
- Partition则是Kafka 中实际保存数据的单位。每个Topic可以被划分为多个Partition,而这些 Partition 会尽量平均的分配到各个 Broker 上。当一条消息发送到Kafka时,它会被分配到一个特定的Partition中,并最终写入 Partition 对应的日志文件里。这个分配过程是根据Partition的规则来完成的,比如可以按照消息的某个属性进行哈希或者按照时间戳进行排序等。
因此,Topic和Partition的关系是,Topic是消息的逻辑分类,用于区分和筛选数据,而Partition则是Topic的物理划分,用于将消息分配到不同的部分中以便于处理和存储。Topic 和 Partition 的设计对于高吞吐量和横向扩展非常有用。因为生产者和消费者只需要根据 Topic 进行具体的业务实现,而不用关心消息在集群内的分布情况。而在集群内部,这些 Partition 会尽量平均的分布在不同的 Broker节点上,从而提高了系统 整体的性能和可伸缩性。
在Kafka中,消息的传递主要涉及三个环节:生产者生产消息、broker保存消息和消费者消费消息。
- 生产者生产消息:生产者负责将消息发布到Kafka broker。在发布消息时,生产者需要指定目标主题。消息被写入后,将被存储在指定分区的当前副本中。当发送消息失败时,生产者还会提供确认以及重试机制,以保证消息能够正确的发送到 Broker 上。
- broker保存消息:Kafka broker接收到生产者发送的消息后,会将其存储在内部的缓冲区中,等待消费者拉取。当消费者向broker发送拉取请求时,broker会从缓冲区中获取消息并返回给消费者。Kafka broker能够保证消息的可靠性和顺序性,即使在异常情况下(如服务器崩溃),也能够保证消息不会丢失。
- 消费者消费消息:消费者从Kafka broker中订阅指定的主题,并拉取消息进行消费。消费者可以以同步或异步的方式拉取消息,并对拉取到的消息进行处理。当消费者处理完消息后,会向Kafka broker发送确认消息,表示消息已经被成功处理。这样可以保证消息被正确处理且不会重复消费。
总体来说,Kafka通过生产者、Kafka broker和消费者的协同工作,实现了高吞吐量、高可靠性和高可扩展性的消息传递。
Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。
生产者和消费者只与 leader 副本交互。你可以理解为其他副本只是 leader 副本的拷⻉,它们的存在只是为了保证消息存储的安全性。当 leader 副本发生故障时会从 follower 中选举出一个 leader,但是 follower 中如果有和leader 同步程度达不到要求的参加不了 leader 的竞选。
Kafka 通过给特定 Topic 指定多个 Partition,而各个 Partition 可以分布在不同的 Broker 上,这样便能提供比较好的并发能力(负载均衡)。
Partition 可以指定对应的 Replica 数,这也极大地提高了消息存储的安全性,提高了容灾能力,不过也相应的增加了所需要的存储空间。
我们在使用消息队列的过程中经常有业务场景需要严格保证消息的消费顺序,比如我们同时发了2 个消息,这2 个消息对应的操作分别对应的数据库操作是:
- 更改用户会员等级。
- 根据会员等级计算订单价格。假如这两条消息的消费顺序不一样造成的最终结果就会截然不同。 Kafka 中Partition(分区)是真正保存消息的地方,我们发送的消息都被放在了这里。而我们的 Partition(分区)又存在于 Topic(主题)这个概念中,并且我们可以给特定 Topic 指定多个
Partition。每次添加消息到 Partition(分区)的时候都会采用尾加法,如上图所示。 Kafka 只能为我们保证 Partition(分区)中的消息有序。
消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。Kafka 通过偏移量(offset)来保证消息在分区内的顺序性。所以,我们就有一种很简单的保证消
息消费顺序的方法:1 个 Topic 只对应一个 Partition。这样当然可以解决问题,但是破坏了 Kafka 的设计初衷。 Kafka 中发送1 条消息的时候,可以指定 topic, partition, key,data(数据)4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同一个 key 的消息可以保证只发送到同一个 partition,这个我们可以采用表/对象的 id 来作为 key。
总结一下,对于如何保证 Kafka 中消息消费的顺序,有了下面两种方法:
- 1 个 Topic 只对应一个 Partition。
- 发送消息的时候指定 key/Partition。
- 生产者丢失消息的情况
生产者(Producer)调用 send 方法发送消息之后,消息可能因为网络问题并没有发送过去。
所以,我们不能默认在调用 send 方法发送消息之后消息发送成功了。为了确定消息是发送成功,我们要判断消息发送的结果。但是要注意的是 Kafka 生产者(Producer)使用 send 方法发送消息实际上是异步的操作,我们可以通过 get()方法获取调用结果,但是这样也让它变为了同步操作。- 消费者丢失消息的情况
我们知道消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。偏移量(offset)表示 Consumer 当前消费到的 Partition(分区)的所在的位置。Kafka 通过偏移量(offset)可以保证消息在分区内的顺序性。
当消费者拉取到了分区的某个消息之后,消费者会自动提交了 offset。自动提交的话会有一个问题,试想一下,当消费者刚拿到这个消息准备进行真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被自动提交了。
解决办法也比较粗暴,我们手动关闭自动提交 offset,每次在真正消费完消息之后再自己手动提交 offset 。但是,细心的朋友一定会发现,这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。
为了保证消息在传递过程当中,消息不会丢失或者被重复传递,Kafka 设计了非常多的重要机制来保证消息的可靠性。例如
- 数据冗余:Kafka通过将消息副本(replica)的方式来实现数据冗余,每个topic都可以配置副本数量,副本数量越多,数据可靠性越高,但会占用更多的存储空间和网络带宽。在 Kafka 中,针对每个 Partition,会选举产生一个 Leader 节点,负责响应客户端的请求,并优先保存消息。而其他节点则作为 Follower 节点,负责备份 Master 节点上的消息。
- 消息发送确认机制:Kafka支持对生产者发送过来的数据进行校验,以检查数据的完整性。可以通过设置生产者端的参数(例如:acks)来配置校验方式。配置为 0,则不校验生产者发送的消息是否写入 Broker。配置为 1,则只要消息在 Leader 节点上写入成功后就向生产者返回确认信息。配置为-1 或 all,则会等所有 Broker 节点上写入完成后才向生产者返回确认信息。
- ISR机制:针对每个 Partition,Kafka 会维护一个 ISR 列表,里面记录当前处于同步状态的所有Partition。并通过 ISR 机制确保消息不会在Master 故障时丢失。
- 消息持久化:Kafka将消息写入到磁盘上,而不是仅在内存中缓存。这样可以保证即使在系统崩溃的情况下,消息也不会丢失。并且使用零拷贝技术提高消息持久化的性能。
- 消费者确认机制:Kafka消费者在处理完消息后会向Kafka broker发送确认消息,表示消息已经被成功处理。如果消费者未发送确认消息,则Kafka broker会保留消息并等待消费者再次拉取。这样可以保证消息被正确处理且不会重复消费。
这些机制的组合确保了 Kafka 中消息的高可靠性和持久性,使得 Kafka 成为可靠的消息传递系统,适用于各种实时数据处理和日志聚合需求。
- 节点必须可以维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每个节点的连接;
- 如果节点是个 follower,他必须能及时的同步 leader 的写操作,延时不能太久。
producer 直接将数据发送到 broker 的 leader(主节点),不需要在多个节点进行分发,为了
帮助 producer 做到这点,所有的 Kafka 节点都可以及时的告知:哪些节点是活动的,目标
topic 目标分区的 leader 在哪。这样 producer 就可以直接将消息发送到目的地了。
Kafa consumer 消费消息时,向 broker 发出"fetch"请求去消费特定分区的消息,consumer 指定消息在日志中的偏移量(offset),就可以消费从这个位置开始的消息,customer 拥有了offset 的控制权,可以向后回滚去重新消费之前的消息,这是很有意义的。
- Kafka 把 topic 中一个 parition 大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。
- 通过索引信息可以快速定位 message 和确定 response 的最大大小。
- 通过 index 元数据全部映射到 memory,可以避免 segment file 的 IO 磁盘操作。
- 通过索引文件稀疏存储,可以大幅降低 index 文件元数据占用空间大小。
topic 中的多个 partition 以文件夹的形式保存到 broker,每个分区序号从0 递增,且消息有序。Partition 文件下有多个 segment(xxx.index,xxx.log),segment 文件里的大小和配置文件大小一致可以根据要求修改,默认为1g。如果大小大于1g 时,会滚动一个新的segment 并且以上一个 segment 最后一条消息的偏移量命名。
生产者决定数据产生到集群的哪个 partition 中,每一条消息都是以(key, value)格式,Key 是由生产者发送数据传入,所以生产者(key)决定了数据产生到集群的哪个 partition。
customer 应该从 brokes 拉取消息还是 brokers 将消息推送到 consumer,也就是 pull 还 push。在这方面,Kafka 遵循了一种大部分消息系统共同的传统的设计:producer 将消息推送到 broker,consumer 从 broker 拉取消息。 push 模式,将消息推送到下游的 consumer。这样做有好处也有坏处:由 broker 决定消息推送的速率,对于不同消费速率的 consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消息,但不幸的是,push 模式下,当 broker 推送的速率远大于 consumer 消费的速率时, consumer 恐怕就要崩溃了。最终 Kafka 还是选取了传统的 pull 模式。
大部分消息系统在 broker 端的维护消息被消费的记录:一个消息被分发到 consumer 后 broker 就⻢上进行标记或者等待 customer 的通知后进行标记。这样也可以在消息在消费后立⻢就删除以减少空间占用。
由于领导者的主要⻆色是执行分区的所有读写请求的任务,而追随者被动地复制领导者。因 此,在领导者失败时,其中一个追随者接管了领导者的⻆色。基本上,整个过程可确保服务 器的负载平衡。
允许应用程序订阅一个或多个主题并处理生成给它们的记录流的 API,我们称之为消费者 API。
一种允许应用程序充当流处理器的 API,它还使用一个或多个主题的输入流,并生成一个输 出流到一个或多个输出主题,此外,有效地将输入流转换为输出流,我们称之为流 API。
- Kafka 迁移工具:它有助于将代理从一个版本迁移到另一个版本。
- Mirror Maker:Mirror Maker 工具有助于将一个 Kafka 集群的镜像提供给另一个。 - 消费者检查:对于指定的主题集和消费者组,它显示主题,分区,所有者。
连续、实时、并发和以逐记录方式处理数据的类型,我们称之为 Kafka 流处理。
保留期限保留了 Kafka 群集中的所有已记录。它不会检查它们是否已被消耗。此外,可以通 过使用保留期的配置设置来丢弃记录,而且,它可以释放一些空间。
Kafka 和 RabbitMQ 都是流行的消息中间件系统,他们各自都有一些优势和适用场景。以下是 Kafka 相对于 RabbitMQ 的一些比较明显的优势:
- 分布式架构: Kafka 是为大规模分布式流处理而设计的,具有高度可伸缩性。RabbitMQ 虽然也支持分布式架构,但相对而言,Kafka 的集群设计更完善,更适合处理大规模的消息流。
- 吞吐量: Kafka每秒可处理十几万消息,而 RabbitMQ 每秒可处理几万条消息。
- 消息复制和可用性:Kafka 允许配置多个消息副本,确保数据的冗余存储,提高可用性和容错性。RabbitMQ 也支持镜像队列以实现冗余,但是不如 Kafka 的多副本复制灵活。
- 时间溯源:Kafka 在事件溯源和事件驱动架构中非常强大。他允许事件在 Topic 中保留一段时间,以便后续的分析和回溯查询。RabbitMQ 通常用于实时消息传递,对于事件溯源不够灵活。
- 批处理和流处理: Kafka 提供了流处理 API,课用于实时数据流处理等场景。而 RabbitMQ 倾向于更专注的处理实时消息传递。
- 社区和生态系统:Kafka 有一个庞大的社区和丰富的生态系统,提供了许多与大数据和流处理相关的工具和库。RabbitMQ 也有一个活跃的社区,但是相对而言社区规模以及社区活跃性就要小很多。
如果您需要处理大规模的实时数据流或事件驱动架构,Kafka 可能更适合;如果您更关注传统的消息传递和队列处理,RabbitMQ 的高级功能更丰富,可能更合适。因此,选择哪种消息中间件还是要取决于具体的应用场景。
Kafka设计了多种机制,共同保证集群的高可用性:
- 分布式架构:Kafka集群通常由多个Broker组成,每个Broker存储部分数据副本。这样,即使某个Broker出现故障,其他Broker也可以继续处理和存储消息,从而保证整体的高可用性。
- 数据冗余:Kafka通过数据冗余来保证高可用性。每个Topic的数据会被分成多个Partition,并在多个Broker上进行复制。即使某个Broker出现故障,数据仍然可以从其他Broker中获取。
- 副本机制:副本是Kafka实现高可用性的重要手段。Kafka中的每个Partition都有多个副本,这些副本分布在不同的Broker上,从而在部分Broker故障时,仍然有足够的副本可用以保证高可用性。
- 分区领导者选举:在Kafka中,每个Partition都有一个领导者(Leader)和零个或多个追随者(Follower)。当领导者不可用时,追随者会进行领导者选举,以保证系统的可用性。
- 消费者组实现负载均衡:Kafka的消费者可以组成消费者组,通过消费者组,可以将负载均匀地分配到多个消费者上,从而避免单个消费者的性能瓶颈,提高整个Kafka集群的可用性。
- 故障检测和恢复: Kafka 会使用 Zookeeper 等组件协助监控和管理集群的状态。当检测到故障节点时,就会自动将不可用的节点从集群中排除。而等到故障节点恢复后,也会重新将节点加入到集群当中。
集群高可用性是 Kafka非常关键的设计之一。通过多项机制组合,使得 Kafka 可以成为处理关键业务数据的可信平台。
在Kafka中,消费者偏移量是指消费者在处理消息过程中所处的位置。Kafka中的消费者偏移量由两部分组成:Topic和Partition。对于每个消费者组,Kafka都会为其维护在每个 Partition 上的偏移量,以便在处理消息时可以准确地跟踪进度。
消费者偏移量的管理可以通过以下方式进行:
- 手动提交偏移量:消费者可以通过调用commitSync或commitAsync方法手动提交偏移量到Kafka。手动提交偏移量的方式需要开发者在适当的时机调用提交方法,确保消费者处理完消息后再提交偏移量。这种方式对于灵活性和精确控制偏移量非常有用,但需要开发者自行考虑提交的时机和异常处理。
- 自动提交偏移量:消费者可以配置为在后台自动提交偏移量。这意味着消费者会定期自动将已经处理的消息的偏移量提交给Kafka,而不需要开发者手动处理。通过配置参数enable.auto.commit为true,以及设置auto.commit.interval.ms参数来控制自动提交的频率。自动提交偏移量简化了管理,但可能会导致消息的重复处理或丢失,因此需要根据具体业务场景谨慎配置。
总之,Kafka 消费者的偏移量管理是确保消息传递的可靠性和一致性的重要部分。它允许消费者灵活地管理消息的消费进度,以满足不同的应用需求。无论您选择自动还是手动管理偏移量,都需要确保偏移量的正确提交,以避免消息的重复消费。
Kafka中的消息是通过分区(Partition)分配给不同的消费者的。Kafka将每个Topic划分为多个Partition,每个Partition存储一部分消息。消费者通过订阅Topic来消费消息,而Kafka将Partition中的消息按照一定的分配策略分配给消费者组中的不同消费者。
Kafka提供了多种分区分配策略,用于确定如何将分区分配给消费者。例如:
- RoundRobin 轮询策略:Kafka将Partition按照轮询的方式分配给消费者组中的不同消费者,每个消费者依次获得一个Partition,直到所有Partition被分配完毕。当消费者数量发生变化时,Kafka会重新分配Partition。
- Range 范围策略:Kafka将Partition按照Range的方式分配给消费者组中的不同消费者,每个消费者负责处理指定范围内的Partition。这种分配方式适用于Topic的Partition数量较少,而消费者数量较多的情况。
- Sticky 粘性策略: 尽量保持每个消费者在一段时间内消费相同的分区,以减少分区重新分配的频率
当消费者处理完一个Partition中的所有消息后,它会向Kafka发送心跳请求,Kafka会将该Partition分配给其他消费者进行处理。这种机制确保了消息在不同的消费者之间负载均衡,并提高了容错性。如果一个消费者出现故障,其他消费者可以继续处理Partition中的消息,而不会导致消息丢失或重复处理。
零拷贝是操作系统提供的一种优化 IO 操作的重要机制。通过零拷贝技术,操作系统可以极大的减少在一次 IO 操作中,数据从一个内存区域复制到另一个内存区域的次数,以及在此过程中对 CPU 的性能消耗。零拷贝技术可以极大的提高数据传输的效率,避免不必要的数据拷贝,从而降低系统负载。
零拷贝有两种实现方式,mmap文件映射和sendfile文件复制。
- mmap机制主要依赖于内存区域映射技术,可以减少一次 IO 操作中,内核态与用户态之间的数据传输,从而减少因为上下文切换而带来的 CPU 性能开销。mmap机制通常适合于对大量小文件的 IO 操作,Kafka 大量的运用 mmap 机制加速 Partition 日志文件的读写过程。
- sendfile主要依赖于 DMA 数据传输技术,采用一组单独的指令集来进行负责数据在内存不同区域之间的拷贝过程。这样就不再需要 CPU 来进行复制,从而减少 CPU 性能消耗,让 CPU 可以用于更重要的计算任务。sendfile通常适合于大文件的拷贝传输操作,Kafka 大量的运用 sendfile 机制,加速消息从 Partition 文件到网卡的传输过程。
总之,零拷贝是由操作系统提供的一种高效的文件读写技术,而 Kafka 则大量的运用了零拷贝技术,从而极大的提升了 Kafka 整体的工作性能。
Kafka 中的消息是以文件的方式持久化到磁盘中进行存储的,这是 Kafka 的一个关键特性,确保消息的可靠性和可用性。Kafka中的消息是通过以下方式进行存储的:
- Partition 分区:Partition是Kafka中消息存储的基本单位,每个Topic下的消息都会被划分成多个Partition进行管理。每个Partition都是一个有序的、不变的消息队列,消息按照追加的顺序被添加到队列尾部。
- Segment 分块:Partition会被进一步划分成多个Segment,Segment是逻辑上的文件组,方便进行数据的管理和查找。每个Segment里都包含多个文件,这些文件名相同且被集合在一起。
- 文件索引:Segment中的每个文件都有自己的索引文件和数据文件,索引文件存储了当前数据文件的索引信息,而数据文件则存储了当前索引文件名对应的数据信息。
- 消息偏移:Kafka中的每个消息都会被分配到一个特定的Partition中,然后根据Partition内的Segment划分,被存储到对应的数据文件中。消息的偏移量信息则会被记录在索引文件中。
- 持久化:Kafka中的每个消息都包含一个64位的偏移量,该偏移量表示消息在Partition中的位置。当消费者读取消息时,可以通过偏移量信息来确定需要从哪个位置开始读取。
Kafka 的消息存储是基于日志文件和分区的,确保了消息的可靠性、持久性和高吞吐量。消息被追加到日志文件中,每个消息都有唯一的偏移量,分区和副本机制保证了数据的冗余存储和可用性。这种设计使 Kafka 成为一个可信赖的消息传递系统,适用于各种实时数据处理、日志聚合和事件驱动应用程序。