KafKa原理机制

本文详细探讨了Kafka机器数量、分区设置、压测、日志保留、数据量计算、监控与分区策略。重点讲解了数据一致性保证的ack机制、ISR同步队列以及如何处理数据积压问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

十年生死两茫茫,千行代码,Bug何处藏。
纵使产品经理祭苍天,又怎样?
朝令改,夕断肠。
相顾无言,惟有泪千行。
每晚灯火阑珊处,夜难寐,加班狂

在这里插入图片描述

KafKa

kafka传统定义:Kafka是一个分布式基于发布/订阅模式的消息队列,主要应用于实时处理领域。
发布/订阅:消息的发布者不会将消息直接发送给特定的订阅者,而是将发布的消息分为不同的类别,订阅者只接收感兴趣的消息。

提供了类似于JMS的特性,作用是日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer

(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机器的数量(2n+1)

Kafka机器数量=2*(峰值生产速度20M*副本数/100)+1

kafka分区有多少个3-10个分区(分区影响消费的并发度,分区个数不建议超过集群的个数)

峰值生产速度不到50m/s 3台节点就够
	(ps:假设每条数据大小为1kb  1mb=1024条数据 也就是说峰值生产速度不高于51200条)

副本数设定

一般我们设置成2个或3个,很多企业设置为2个。
副本的优势:提高可靠性
副本劣势:增加了网络IO传输

Kafka压测

Kafka官方自带压力测试脚本(kafka-consumer-perf-test.sh、kafka-producer-perf-test.sh)。Kafka压测时,可以查看到哪个地方出现了瓶颈(CPU,内存,网络IO)。一般都是网络IO达到瓶颈。

Kafka日志保存时间

默认保存7天;生产环境建议3天

(ps:因为flume会消费kafka中的数据并上传到hdfs,正常情况下当天数据当天消费完成,顶多到凌晨30分,多出来的一天是预留量)

Kafka中数据量计算

每天总数据量100g
每天产生1亿条日志, 10000万/24/60/60=1150条/每秒钟
平均每秒钟:1150条
低谷每秒钟:50条
高峰每秒钟:1150条*(2-20倍)=2300条-23000条
每条日志大小:0.5k-2k(取1k)
每秒多少数据量:2.0M - 20MB

Kafka的硬盘大小

每天的数据量100g * 2个副本 * 3天 / 70%约等于1T数据量

Kafka监控

公司自己开发的监控器;
开源的监控器:KafkaManager、KafkaMonitor、KafkaEagle,我所采用的时kafkaEagle

Kakfa分区数

1)创建一个只有1个分区的topic
2)测试这个topic的producer吞吐量和consumer吞吐量。
3)假设他们的值分别是Tp和Tc,单位可以是MB/s。
4)然后假设总的目标吞吐量是Tt,那么分区数=Tt / min(Tp,Tc)
		(ps:取生产huo消费速率最小的值进行计算)

例如:producer吞吐量=20m/s;consumer吞吐量=50m/s,期望吞吐量100m/s;
分区数=100 / 20 = 5分区
https://blog.csdn.net/weixin_42641909/article/details/89294698
分区数一般设置为:3-10个

多少个Topic

通常情况:多少个日志类型就多少个Topic。也有对日志类型进行合并的,我这里分为业务数据和用户行为数据,大概10个topic(点赞,评论,商品的增删改查等等),每个topic5个分区。

Kafka的高效读写的原因

1.Kafka本身是分布式集群,同时采用分区技术,并发度高。
2.顺序写入磁盘

Kafka的producer生产数据,要写到log文件中,写的过程是一直追加到文件的末尾,顺序写入磁盘的速度600M/s,这个和硬盘是机械还是固态有一些关联,随机写入默认100K/s , 根据是否需要进行磁盘寻址

3.零复制技术

Linux中提供的一种文件处理技术,Linux总会将系统中还没有使用到的内存挪给 Page cache 当写操作发生的时候, 他会将写入page Cache中,并在该写入位置加入dirty标志,当读操作发生的时候,它会首先查找Page cache中是否存在,如果存下就直接返回,如果没有就从磁盘中读取再写入到Page Cache中

Zookeeper在kafka中的作用

0.8版本以后的Zookeeper就不在维护偏移量offset,Zookeeper在后续的Kafka中起到的是一个选举作用

Kafka集群中有一个broker被选举为Controller,负责管理集群中broker的上下线,所有topic的分区和副本分配和leader的选举工作Controller的管理工作都是依赖于Zookeeper的
在这里插入图片描述在这里插入图片描述

Kafka如何保证数据一致性

在这里插入图片描述

数据可靠性保证(ack机制)

为了保证producer发送数据,能够可靠的发送到指定topic,topic的每个partition收到producer发送数据就会向producer发送"ack"(acknowledgement 确认收到) 如果producer收到ack,就会进行下一轮的发送,否则就重新发送数据。

为了保证Topic的partition可以正常提供服务,会提供副本机制,所以会有多个partition存在

例如:一个topic存在三个partition,topic中有一个leader两个follower当leader接收到Producer发送的消息后,是等待所有follower全部完成后再发送ack还是只要有过半机制就发送ack

Kafka选择了全部完成方案,原因如下:

Kafka的每个分区都有大量的数据,过半机制的副本保存会造成大量数据冗余

全部完成方案的网络延迟会比较高,网络延迟对Kafka的影响较小

(针对所有follower都开始同步数据,有一个follower,迟迟不能与leader进行同步的情况。采用ISR(一个存储着follower集合),如果follower长时间未向leader同步数据则该follower将被踢出ISR,如果是Leader发生故障,会从ISR中选举新的leader。)

ACK应答机制(丢不丢数据)
所以Kafka为了用户提供了三种可靠级别设置,可以根据不同雪球来修改选择acks参数配置:参数是0 ,1 和 -1

在这里插入图片描述

Kafka的ISR副本同步队列

幂等机制

幂等简单来说1的几次幂都等于1,也就是说一天消息无论发送几次都只算一次,无论多少条消息,我们只实例化一次

Kafka完成幂等性其实就是给消息添加一个唯一ID,这个ID组成PID(ProducerID),这样就可以保证每一个Producer发送的时候都是唯一,还会为Producer中每条消息添加一个消息ID,当消息发送到kafka后会暂时缓存ID,写入数据后没有收到ACK会重新发送,消息收到后会与缓存中ID进行比较,如果已存在,不再接收

水位线机制

kafka副本同步机制
在这里插入图片描述

ISR副本同步队列

ISR(In-Sync Replicas),副本同步队列。ISR中包括Leader和Follower。如果Leader进程挂掉,会在ISR队列中选择一个服务作为新的Leader。有replica.lag.max.messages(延迟条数)和replica.lag.time.max.ms(延迟时间)两个参数决定一台服务是否可以加入ISR副本队列,在0.10版本移除了replica.lag.max.messages参数,防止服务频繁的进去队列。
任意一个维度超过阈值都会把Follower剔除出ISR,存入OSR(Outof-Sync Replicas)列表,新加入的Follower也会先存放在OSR中。

offset的维护

Kafka0.9版本之前,consumer默认将offet保存在Zookeeper,从0.9版本开始后,consumer默认将offset保存在kafka这一个内置的topic中,该topic为 __consumer_offsets

手动维护(可以维护到redis中),自动维护(将偏移量维护到kafka记录偏移量的topic中)
在这里插入图片描述
Kafka中topic数量

(一般情况下一张表对应一个topic,也可以相同主题的表进行轻度聚合放在一个topic中
例如:
将商品列表,商品详情,商品点击放到一个topic中。
将广告放在一个tpoic中。
通知、前台活跃、后台活跃放到一个topic中。
评论、点击、收藏、点赞放到一个topic中。
故障日志放一个topic中)

Kafka消息数据积压,Kafka消费能力不足怎么处理?

1)如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数 = 分区数。(两者缺一不可)
2)如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间 < 生产速度),使处理的数据小于生产的数据,也会造成数据积压。

Kafka参数优化

1、日志保留策略配置
保留三天,也可以更短 (log.cleaner.delete.retention.ms)
log.retention.hours=72

2、Replica相关配置
default.replication.factor:1 默认副本1个

3、网络通信延时
1)Broker参数配置(server.properties)
replica.socket.timeout.ms:30000 #当集群之间网络不稳定时,调大该参数
replica.lag.time.max.ms= 600000# 如果网络不好,或者kafka集群压力较大,会出现副本丢失,然后会频繁复制副本,导致集群压力更大,此时可以调大该参数

2)Producer优化(producer.properties)
compression.type:none gzip snappy lz4
#默认发送不进行压缩,推荐配置一种适合的压缩算法,可以大幅度的减缓网络压力和Broker的存储压力。

3)Kafka内存调整(kafka-server-start.sh)
默认内存1个G,生产环境尽量不要超过6个G。
export KAFKA_HEAP_OPTS=“-Xms4g -Xmx4g”

Kafka单条日志传输大小

Kafka对于消息体的大小默认为单条最大值是1M但是在我们应用场景中,常常会出现一条消息大于1M,如果不对Kafka进行配置。则会出现生产者无法将消息推送到Kafka或消费者无法去消费Kafka里面的数据,这时我们就要对Kafka进行以下配置:server.properties

replica.fetch.max.bytes: 1048576 broker可复制的消息的最大字节数, 默认为1M
message.max.bytes: 1000012 kafka 会接收单个消息size的最大限制, 默认为1M左右
注意:message.max.bytes必须小于等于replica.fetch.max.bytes,否则就会导致replica之间数据同步失败。

Ps:这样设置的缺点是,如果大日志只有1-2条这样日志,设置单条2M的话加载每条日志(即使单条日志不大)都会预留2M的内存,可以建议业务端改掉

Kafka中的数据是有序的吗

单分区内有序;多分区,分区与分区间无序;
扩展:kafka producer发送消息的时候,可以指定key:

这个key的作用是为消息选择存储分区,key可以为空,当指定key且不为空的时候,Kafka是根据key的hash值与分区数取模来决定数据存储到那个分区。

有序解决方案:同一张表的数据 放到 同一个 分区
=> ProducerRecord里传入key,会根据key取hash算出分区号
=> key使用表名,如果有库名,拼接上库名

Kafka如何进行分区的

在这里插入图片描述

Consumer消费数据的方式(分区分配策略)

  1. RoundRobin(轮询)将每一个分区一次发送给一个消费者组
  2. Range(范围)是默认策略。是对每个Topic而言的(即一个Topic一个Topic分),首先对同一个Topic里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。然后用Partitions分区的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。

常用命令示例

查看topic列表:
bin/kafka-topics.sh --zookeeper localhost:2181 –list
查看指定topic明细:
bin/kafka-topics.sh --zookeeper localhost:2181 --desc --topic demo

常用的kafka工具:kafkaTools

有收获?希望烙铁们来个三连击,让更多的同学看到这篇文章

1、烙铁们,关注我看完保证有所收获,不信你打我。

2、点个赞呗,可以让更多的人看到这篇文章,后续还会有很哇塞的产出。

本文章仅供学习及个人复习使用,如需转载请标明转载出处,如有错漏欢迎指出
务必注明来源(注明: 来源:csdn , 作者:-马什么梅-)
在这里插入图片描述

### Kafka 工作原理及架构解析 Kafka 是一个分布式流处理平台,其设计目标是提供高吞吐量、低延迟的消息传递系统[^1]。以下是 Kafka 的核心架构和工作原理的详细解析。 #### 1. 核心组件 Kafka 的架构由多个核心组件构成,每个组件在系统中扮演特定的角色: - **Producer(生产者)**:负责将消息发布到 Kafka 集群中的特定主题(Topic)。生产者可以选择分区策略以确保消息的有序性[^3]。 - **Consumer(消费者)**:从 Kafka 集群订阅消息并进行处理。消费者可以通过组(Consumer Group)的方式实现负载均衡和故障恢复[^3]。 - **Broker**:Kafka 集群中的服务器实例,负责接收、存储和转发消息。每个 Broker 可以管理多个 Topic 和 Partition[^2]。 - **Topic(主题)**:逻辑上的消息类别或提要名称。每个 Topic 可以分为多个 Partition,Partition 是 Kafka 中消息存储的基本单位。 - **Partition(分区)**:Topic 的物理分组,每个 Partition 是一个有序的日志文件。Partition 提供了 Kafka 的水平扩展能力。 - **ZooKeeper**:用于管理 Kafka 集群的元数据和协调服务。从 Kafka 2.8 开始,支持无 ZooKeeper 模式。 #### 2. 消息持久化与可靠性 Kafka 使用分布式持久化机制将消息写入磁盘,并通过多副本机制保证数据的可靠性[^3]。以下是关键点: - **多副本机制**:每个 Partition 可以配置多个副本(Replica),其中一个为主副本(Leader),其余为从副本(Follower)。只有 Leader 负责读写操作,Follower 同步 Leader 的数据[^2]。 - **ISR(In-Sync Replica)**:Kafka 维护了一个 ISR 列表,记录与 Leader 同步的所有副本。如果某个副本长时间未同步,将被移出 ISR 列表。 - **消息确认机制**:生产者发送消息时可以设置不同的 ACK 策略: - `acks=0`:不等待确认,可能丢失消息。 - `acks=1`:等待 Leader 确认,默认选项。 - `acks=all`:等待所有 ISR 副本确认,提供最高可靠性。 #### 3. 分区与负载均衡 Kafka 的分区机制是其实现水平扩展的核心。以下是分区的主要功能: - **分区选择策略**: - 指定分区:直接将消息发送到指定的 Partition。 - Key 哈希:根据消息的 Key 计算哈希值,确保相同 Key 的消息进入同一 Partition。 - 轮询:均匀分布到各 Partition,适用于无序消息。 - **负载均衡**:通过分区,Kafka 可以将消息均匀分布到多个 Broker 上,从而提高系统的吞吐量和可用性。 #### 4. 消费模式 Kafka 支持多种消费模式,满足不同场景的需求: - **At-Least-Once(至少一次)**:确保每条消息至少被消费一次,可能会出现重复消费的情况。 - **At-Most-Once(至多一次)**:确保每条消息最多被消费一次,但可能会丢失消息。 - **Exactly-Once(恰好一次)**:通过事务机制和幂等性支持,确保每条消息被消费且仅消费一次[^3]。 #### 5. 数据清理策略 为了防止无限增长的存储空间,Kafka 提供了两种主要的数据清理策略: - **基于时间的清理**:保留消息一定时间后删除。 - **基于大小的清理**:当 Partition 的日志大小超过设定阈值时,删除最早的日志段[^2]。 ### 示例代码 以下是一个简单的 Kafka 生产者和消费者的代码示例: ```python # Kafka生产者示例 from kafka import KafkaProducer producer = KafkaProducer(bootstrap_servers='localhost:9092') producer.send('my-topic', b'Hello, Kafka!') producer.close() # Kafka消费者示例 from kafka import KafkaConsumer consumer = KafkaConsumer('my-topic', bootstrap_servers='localhost:9092') for message in consumer: print(f"Received message: {message.value.decode('utf-8')}") ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一马什么梅一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值