Kafka基本原理和使用

Kafka基本原理和使用

(1)kafka解决什么问题?

kafka的出现主要是为了实现生产者消费者系统的桥梁。实现了生产者和消费者之间的无缝连接。

(2)kafka的特性

高吞吐量、低延迟:每秒可以处理几十万条消息,它的延迟最低只有几毫秒

可扩展性:kafka集群支持热扩展

持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失

容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)

高并发:支持数千个客户端同时读写

(3)场景应用

日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。

消息系统:解耦和生产者和消费者、缓存消息等

用户活动追踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。

运营指标:记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告

(4)kafka的设计核心特性

Consumergroup:各个consumer可以组成一个组,每个消息只能被组中的一个consumer消费,如果一个消息可以被多个consumer消费的话,那么这些consumer必须在不同的组。

消息状态:在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。

消息持久化:Kafka中会把消息持久化到本地文件系统中,并且保持极高的效率。

消息有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。

批量发送:Kafka支持以消息集合为单位进行批量发送,以提高push效率。

push-and-pull:Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。

Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。

负载均衡方面: Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)。

同步异步:Producer采用异步push方式,极大提高Kafka系统的吞吐率(可以通过参数控制是采用同步还是异步方式)。

分区机制partition:Kafka的broker端支持消息分区,Producer可以决定把消息发到哪个分区,在一个分区中消息的顺序就是Producer发送消息的顺序,一个主题中可以有多个分区,具体分区的数量是可配置的。分区的意义很重大,后面的内容会逐渐体现。

消息队列通信模式

通信模式主要分为两种,主要区别在于消费测(Consumer)如何获取到消息。

点对点模式

image-20240120235853141

可以看到,其需要Consumer主动去向消息队列通过Pull方式来拉取信息。

模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。点对点模型的的优点是消费者拉取消息的频率可以由自己控制。但是消息队列是否有消息需要消费,在消费者端无法感知,所以在消费者端需要额外的线程去监控。

发布订阅模式

image-20240121000013363

这种模式的特点是Consumer去告诉消息队列,我需要什么类型的消息,然后消息队列收到该类型的消息后,转发给Consumer。

其模型特点是消费者被动接收推送,所以无需感知消息队列是否有待消费的消息!但是consumer1、consumer2、consumer3由于机器性能不一样,所以处理消息的能力也会不一样,但消息队列却无法感知消费者消费的速度!所以推送的速度成了发布订阅模模式的一个问题!假设三个消费者处理速度分别是8M/s、5M/s、2M/s,如果队列推送的速度为5M/s,则consumer3无法承受!如果队列推送的速度为2M/s,则consumer1、consumer2会出现资源的极大浪费!

Kafka架构原理

image-20240121000226549

  • Producer:Producer即生产者,消息的产生者,是消息的入口。

  • Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……

  • Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。

  • Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!

  • Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。

  • Message:每一条发送的消息主体。

  • Consumer:消费者,即消息的消费方,是消息的出口。

  • Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!

  • Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。

工作流程分析

(1)发送数据

image-20240121000817857

注意点:Producer在写入数据的时候永远的找leader,不会直接将数据写入follower。

消息写入leader后,follower是主动的去leader进行同步的!producer采用push模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内的数据是有序的!

image-20240121001011618

kfaka在选择partition时候,主要依据下面的几个原则:

  1. partition在写入的时候可以指定需要写入的partition,如果有指定,则写入对应的partition。

  2. 如果没有指定partition,但是设置了数据的key,则会根据key的值hash出一个partition。

  3. 如果既没指定partition,又没有设置key,则会轮询选出一个partition。

那么如何确保kafka的消息不会丢失?

Ack应答机制:在生产者向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可设置的值为0、1、all

  1. 0代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
  2. 1代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
  3. all代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。

磁盘保存:Producer将数据写入kafka后,集群就需要对数据进行保存了!kafka将数据保存在磁盘,可能在我们的一般的认知里,写入磁盘是比较耗时的操作,不适合这种高并发的组件。Kafka初始会单独开辟一块磁盘空间,顺序写入数据(效率比随机写入高)

kafka的存储结构

Partition结构

kafka的每个topic会分成若干个partition, 每个partition会存在多个segment组(相当于文件夹),每组segment中包含.index、.log、.timeindex三个文件。其中 log文件就实际是存储message的地方,而index和timeindex文件为索引文件,用于检索消息。

image-20240121123324088

这个partition有n组segment文件,每个log文件的大小是一样的,但是存储的message数量是不一定相等的(每条的message大小不一致)。文件的命名是以该segment最小offset来命名的,如000.index存储offset为0~368795的消息,kafka就是利用分段+索引的方式来解决查找效率的问题。

Message结构

image-20240121123712895

  • offset:offset是一个占8byte的有序id号,它可以唯一确定每条消息在parition内的位置!

  • 消息大小:消息大小占用4byte,用于描述消息的大小。

  • 消息体:消息体存放的是实际的消息数据(被压缩过),占用的空间根据具体的消息而不一样。

消费数据

多个消费者可以组成一个消费者组(consumer group),每个消费者组都有一个组id!同一个消费组者的消费者可以消费同一topic下不同分区的数据,但是不会组内多个消费者消费同一分区的数据

image-20240121123845838

图示是消费者组内的消费者小于partition数量的情况,所以会出现某个消费者消费多个partition数据的情况,消费的速度也就不及只处理一个partition的消费者的处理速度!如果是消费者组的消费者多于partition的数量,那会不会出现多个消费者消费同一个partition的数据呢?上面已经提到过不会出现这种情况!多出来的消费者不消费任何partition的数据。所以在实际的应用中,建议消费者组的consumer的数量与partition的数量一致

至于如何找到对应offset的消息,其实就是利用offset去计算在哪个segment文件当中,通过.index文件得到在segment中偏移量。即可得到消息本身。

image-20240121124247051

那每个消费者又是怎么记录自己消费的位置呢?在早期的版本中,消费者将消费到的offset维护zookeeper中,consumer每间隔一段时间上报一次,这里容易导致重复消费,且性能不好!在新的版本中消费者消费到的offset已经直接维护在kafk集群的__consumer_offsets这个topic中!

posted @   xyfyy  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示