读书笔记之《深入理解kafka: 核心设计与实践原理》

bootstrap.servers ,分割,这里并非需要所有的broker地址清单,因为生产者会从给定的broker里查找到其他broker信息,不过建议
至少要设置两个以上broker地址信息

broker端接收的消息必须以字节数组( byte[] )形式存在,在发往broker之前需要将消息中对应的 key 和 value 做相应的序列化操作
来转化成字节数据
生产者需要用序列化器把对象转换成字节数组才能通过网络发送给kafka,而在对侧,消费者需要用反序列化器把kafka中收到的字节数据转化
成相应的对象
生产者和消费者的序列化器需要一一对应的
不建议自定义序列化器或反序列化器,会增加生产者和消费者之间的耦合度。
在实际应用中,在kafka提供序列化器和反序列化器满足不了应用需求的前提下,推荐使用 avro json thrift、protobuf等通过的序列化包

在不改变主题分区数量的情况下,key与分区之间的映射可以保持不变。不过,一旦主题中增加了分区,那么就难以保证key与分区之间的映射关系了

默认分区,当key不为null时,那么默认的分区器会对key进行哈希,如果key为null,轮询

kafka producer 线程安全的

回调函数也可以保证分区有序

发送消息三种方式:1.发后即忘 send() 2.同步(sync) send().get() 3.异步(async) send(,callback)

生产者客户端的整体架构:
在这里插入图片描述

RecordAccumulator主要用来缓存消息以便Sender线程可以批量发送,进而减少网络传输的资源消耗以提升性能,其大小可以通过生产者客户端参数 buffer.memory配置,默认是32M

batch.size

max.blocks.ms

max.in.flight.requests.pre.connection 默认 5,每个连接(客户端与Node之间的连接)最多只能缓存5个未响应的请求,超过该数值之后就不能再向这个连接发送更多的请求了,除非有缓存的请求收到了响应

元数据的更新:

metadata.max.age.ms 默认 5min

acks=all 并不意味着消息就一定可靠,因为 ISR 中可能只有 leader 副本,这样就退化成了 acks=1 的情况。要获得更高的消息可靠性需要配合 min.insysc.replicas 等参数的联动.

max.request.size 限制生产者客户端能发送的消息的最大值 默认 1M message.max.bytes

retries 默认值 0 和retry.backoff.ms 默认值 100

compression.type 默认 none 对消息进行压缩可以极大的减少网络传输量、降低网络I/O,从而提高整体性能。消息压缩是一种使用时间换空间的优化方式,如果对时延有一定的要求,则不推荐对消息进行压缩

connections.max.idle.ms 多久之后关闭空闲连接 默认 9min

linger.ms 生产者发送 ProducerBatch 之前等到更多消息(ProducerRecord)加入 ProducerBatch 的时间。 默认 生产者客户端会在 ProducerBatch 被填满或者等待时间超过 linger.ms 值时发送出去。增大这个参数的值会增加消息的延迟,但同时能提升一定的吞吐量( 当不为0的时候,适当调大batch.size 才有价值跟意义)

receive.buffer.bytes 设置 socket接收消息缓冲区(SO_RECBUF)的大小,默认 32K,如果设置 -1,则使用操作系统默认值。如果 producer 与kafka 处于不同机房,则可以适当调大这个参数

send.buffer.bytes 同上 默认128K

request.timeout.ms producer 等待请求响应的最长时间 默认 30s 注意这个参数要比 replica.lag.time.max.ms 的值要大,这样可以减少因客户端重试而引起消息重复的概率.

enble.idempotence 默认 false 是否开启幂等性

消费者

partition.assignment.strategy来设置消费者与订阅消费者与订阅主题之间的分区分配策略

Replicas AR集合

inSynReplicas ISR集合

offlineReplicas OSR集合

通过 subscribe()方法订阅主题具有消费者自动再均衡的功能,在多个消费者的情况下可以根据分区分配策略来自动分配各个消费者与分区的关系。而通过 assign() 方法订阅分区时,是不具备消费者自动均衡的功能的

Kafka 消费者是基于拉模式的( 消息的消费一般有两种模式:推模式和拉模式。 推模式是服务端主动将消息推送给消费者,而拉模式是消费者主动向服务端发起请求来拉消息 )

对于 poll()方法而言,如果某些分区中没有可供消费的消息,那么此分区对应的消息拉取的结果就为空。

/*
					可以获取消息集中的指定分区的消息
					可以获取消息集中的指定topic的消息
					可以获取消息集中所有的分区
					 */
//					records.records()
					
					/*
					count() 方法计算出消息集中的消息个数 int
					isEmpty() 判断消息集是否为空   boolean
					empty()   获取一个空消息集
					 */

kafka中它的每天消息都有唯一的offset,用来表示消息在分区中对应的位置 偏移量。对于消费者而言,它也有一个offset,消费者使用 offset 来表示消费到分区中某个消息所在的位置 位移 消费者消费到的位置 lastConsumerOffset

在这里插入图片描述

position=commited offset =lastConsumedOffset+1 position, commited offset 也不会一直相同

enable.auto.commit 默认 true enable.auto.interval.ms默认 5s

enable.auto.commit 默认 true enable.auto.interval.ms 默认 5s 每隔5s拉取到每个分区中最大的消息位移进行提交。

自动位移提交的动作是在 poll()方法的逻辑中完成的,在每次真正向服务端发起拉取请求之前会检查是否可以位移提交,如果可以,那么就会提交上一次轮询的位移。无法做到精确的饿位移管理

commitSync()方法会根据poll()方法拉取的最新位移来进行提交,它提交消费位移的频率和拉取批次消息、处理批次消息的频率一样。

KafkaConsumer 提供了对消费者速度进行控制的方法,在有些应用场景下我们可能需要暂停某些分区的消费而先消费其他分区,当到达一定条件时再恢复对某些分区的消费 pause() resume()

wakeup()方法是 kafkaConsumer中唯一可以从其他线程中安全调用的方法,调用 wakeup()方法后可以退出poll()逻辑,并抛出wakeupExeception 的异常,我们也不需要处理 WakeupExeception 的异常,它只是一种跳出循环的方式

auto.offset.reset默认值 latest earliest

seek()方法为我们提供了了从特定位置读取消息的能力,也可以从特定的外部存储介质

再均衡

再均衡是指分区的所属权从一个消费者转移到另一个消费者的行为。它为消费组具备高可用性和伸缩性提供保障。不过在再均衡发生期间,消费组内的消费者是无法读取消息的。

再均衡监听器

fetch.min.bytes 一次拉取请求中能从 kafka中拉取的最小数据量 默认值为 1B。 kafak 在收到 consumer 的拉取请求时,如果返回给 consumer的数据量小于这个参数所配置的值,那么它就需要进行等待,知道数据量满足这个参数配置大小。可以适当调大这个参数的值以提高一定的吞吐量,不过也会造成额外的延迟。

fetch.max.bytes 一次拉取请求中能从kafka拉取的最大数据量 默认 50M 。但当一条消息的大小超过这个值,消息仍然可以被消费。

kafka 中绝对最大值,message.max.bytes

fetch.max.wait.ms 默认是500 ms 如果kafka 中没有足够多的消息而满足不了 fetch.min.bytes 参数的要求,那么最终会等待 500ms

max.partition.fetch.bytes 从每个分区里返回给 consumer 的最大数据量,默认值 1MB 同样如果消息体的大小比这个参数大,也会继续正常消费

max.poll.records consumer在一次拉取请求中拉取的最大消息数 默认是500 条。如果消息的大小都比较小,则可以适当的调大这个参数值来提升一定的消费速度

connections.max.idle.ms 空闲多久后关闭连接 默认9min

exclude.internal.topic 指定kafka内部的topic是否可以向消费者公开 默认 true _consumer_offsets和 _transaction_state 如果为true 则只能使用subscribe(Collection)的方式而不能使用subscribe(pattern)的方式来订阅内部topic

receive.buffer.bytes 同生产者

send.buffer.bytes

request.timeout.ms consumer等待请求相应的最长时间 默认30s

metadata.max.age.ms 元数据的过期时间 默认 5min 如果元数据在此范围内都没有进行更新,则强制更新

reconnect.backoff.ms 尝试重新连接指定主机之前的等待时间,避免频繁的连接主机 默认 50ms 适用于消费者向broker发送的所有请求

retry.backoff.ms 尝试重新发送失败的请求到指定的主题分区之前的等待时间 默认 100ms

isolation.level 消费者事务隔离级别 read_uncommitted(默认 可以消费到HW(Hight Watermark)处的位置) 和 read_committed 消费者忽略事务未提交的消息(LSO,LastStableOffset)

从kafka的底层来说,topic 和partition都是逻辑上的概念。分区可以有一至多个副本,每个副本对应一个日志文件,每个日志文件对应一至多个日志分段( LogSegment ),每个日志分段还可以细分为索引文件、日志存储文件和快照文件等

auto.create.topic.enable 默认 true,除非有特殊的应用需求,否则不建议将 auto.create.topic.enable 设置为true,这个参数会增加 topic的管理与维护难度

脚本中还提供了一个参数 —if-not-exists

0.10.x之后支持指定broker的机架信息

Kafka-topic.sh —alter

Kafka-topic.sh —alter —config

Kafka-config.sh 专门用来对配置进行操作的

在这里插入图片描述在这里插入图片描述在这里插入图片描述

kafka只有leader副本对外提供读写服务,follower副本只负责在内部进行消息的同步。kafka集群中一个broker中最多只能有它的一个副本

为了能够有效的治理负载失衡的情况,优先副本 AR集合列表( Replicas ) 为[1,2,0] 那么优先副本即为1.理想情况下,优先副本就是该分区的 leader 副本。kafka要确保所有主题的优先副本在 kafka 集群中均匀分布,这样就保证了所有分区的 leader 均衡分布。如果 leader 分布过于集中,就会造成集群负载不均衡。

所谓的优先副本的选举是指通过一定的方式促使优先副本选举为 leader 副本,以此来促进集群的负载均衡,这一行为也可以称为 分区平衡。分区平衡并不意味着 kafka集群负载均衡

auto.leader.rebalance.enable 默认为true 自动平衡 自动执行优先副本选举动作以求分区平衡

不过生产环境不建议将此参数设置为true

手动自动平衡 kafka-perferred-replica-election.sh

默认 zookeeper 所允许的节点数据大小为 1MB

Kafka-reassign-partition.sh 可以在集群扩容、broker节点失效的场景下对分区进行迁移

分区数会占用文件描述符,而一个进程所能支配的文件描述符是有限的,这也就是通常所说的文件句柄开销

如果集群中的某个broker节点宕机,那么就会有大量的分区需要同时进行leader角色切换,这个切换过程会耗费一笔可观的时间,并且在这个时间窗口内这些分区也会变的不可用。另外,分区越多也会让kafka 正常启动和关闭的耗时变的越长,同时,分区数越多不仅会增加日志清理的耗时,而且在被删除时也会耗费更多的时间

kafka—>topic——>partition———>一个文件夹———>Log———>防止Log变大 (日志分段) LogSegment
在这里插入图片描述
Log在物理上只以文件夹的形式存储,而每个LogSegment 对应磁盘上的一个日志文件和两个索引文件,以及可能的其他文件( 如:以 .txnindex 为后缀的事务索引文件)

偏移量索引文件 .index 时间戳索引文件 .timeindex
在这里插入图片描述

kafka消息格式的变迁:

kafka 0.8—>kafka0.10.0

在这里插入图片描述
在这里插入图片描述

timestamp的类型是由 broker端参数 log.message.timestamo.type来配置的 默认 CreateTime LogAppendTime

默认是生产者创建消息的时间戳。如果在创建ProducerRecord是没有显示指定消息的时间戳,那么 KafkaProducer 也会在发送这条消息前自动添加上

压缩

kafka将多条消息一起进行压缩,这样可以保证较好的压缩效果。在一般情况下,生产者发送的压缩数据在broker中也是保持压缩状态进行存储的,消费者从服务端获取的也是压缩消息,消费者在处理消息之前才会解压消息,保持端到端的压缩。

compression.type

其实每个从生产者发出消息集中的消息offset都是从0开始的,当然这个offset不能直接存储到日志文件中,对offset的转换是在服务端进行的,客户端不需要做这个工作

在这里插入图片描述

从 Kafka 0.11.0开始使用v2版本,消息集称为 Record Batch
在这里插入图片描述

timestamp delta 时间戳增量 保存的是与 RecordBatch的起始时间戳的差值

offset delta 同

Kafka中索引以 稀疏索引 的方式构建,并不保证每个消息在索引文件中都有对应的索引项。每当写入一定量( broker 参数 log.index.interval.bytes 默认4KB )的消息时,偏移量索引文件和时间索引文件分别增加一个偏移量索引项和时间戳索引项,增大或者减少此参数可以增加或缩小索引项的密度

如果指定的偏移量不在索引文件中,会返回小于指定偏移量的最大偏移量。时间戳,查找不大于该时间戳的最大偏移量,然后根据偏移量索引文件再次定位

稀疏索引的方式是在磁盘空间、内存空间、查找时间等多方面的一个折中 可以借鉴

日志分段:

1.broker 参数 log.segment.bytes 默认 1GB

2.当前日志分段中消息的最大时间戳与当前系统的时间戳差值大于 log.roll.ms(优先级高)/log.roll.hours 默认 168 7天

3.偏移量索引文件或时间戳索引文件的大小 broker参数 log.index.size.max.bytes 默认 10M

4.追加消息的偏移量与当前日志分段的偏移量差值大于 Integer.MAX_VALUE

kafka在创建索引文件的时候会为其预分配 log.index.size.max.bytes 大小的空间,只有当索引文件进行切分时,kafka才会把该索引文件裁剪到实际的数据大小

偏移索引
在这里插入图片描述在这里插入图片描述

如果我们要查找偏移量为23的消息?首先通过二分查找在偏移量索引文件中找到不大于23的最大索引项,即[22,656],然后从日志分段文件中的物理位置656开始顺序查找偏移量为23的消息

根据偏移量或位移 定位到日志分段( 利用跳跃表 )———>计算相对偏移量relativeOffset ———>查找对应索引文件index—>根据索引文件中的position定位到具体logSegment的文件位置——>查找目标消息———>查找到消息开始消费

时间戳索引
在这里插入图片描述

已经知道每当写入一定量的消息时,就会在偏移量索引文件中和时间戳索引文件中分别增加一个偏移量索引项和时间戳索引项,两个文件增加索引项是同时进行的,但并不意味着偏移量中的relativeOffset和时间戳索引项中的relativeOffset是同一个值

在这里插入图片描述

问题:时间戳乱序如何解决?是否为不大于?是否可以保证消息的正确性?

kafka快

1.消息顺序增加 ( 磁盘顺序写 )

2.使用了大量的页缓存

3.零拷贝 (将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手)

在这里插入图片描述在这里插入图片描述

在kafka集群中会有一个或多个broker,其中一个 broker 会被选举为控制器 (kafka controller),它负责管理整个集群中所有分区和副本的状态。

监听分区相关的变化、监听主题的相关变化、监听broker相关变化、从zk中获取当前所有与主题、分区及broker有关的信息并进行相应管理、启动并管理分区状态机和副本状态机、更新集群的元数据信息、如果 auto.leader.rebalance.enable true 定时维护分区的优先副本均衡。

每个broker会对 /controller节点添加监听器

kafka 分区分配策略:

partition.assignment.strategy来设定消费者与订阅主题之间的分区分配策略 默认 RangeAssignor 可以指定多个分配策略,彼此以逗号分隔, RoundRobinAssignor StickyAssignor

__consumer_offset

broker offsets.retention.minutes 保留时长 默认 7天,2.0.0版本之前默认 1天 消费位移会消失

幂等性不能跨区操作,而事务可以

对于每个PID,消息发送到的每一个分区都有对应的序列号,这些序列化从0开始单调递增。生产者每发送一条消息就会将<PID,分区>对应的序列号的值加1

生产者重复生产消息。生产者进行retry会产生重试时,会重复产生消息。有了幂等性之后,在进行retry重试时,只会生成一个消息。

replica.lag.time.max.ms 默认 10000 当 ISR 集合中的一个 follower副本滞后leader副本的时间超过此参数指定的值时,则判定为同步失败,此follower副本剔除出 ISR 集合

LEO 每个分区最后一条消息的下一个位置

深入理解kafak:核心设计与实践原理

生产者、消费者 拦截器

发布了94 篇原创文章 · 获赞 47 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/jsjsjs1789/article/details/92089129
今日推荐