生产消费基本流程
-
Producer创建时,会创建一个Sender线程并设置为守护线程。
-
生产的消息先经过拦截器->序列化器->分区器,然后将消息缓存在缓冲区。
-
批次发送的条件为:缓冲区数据大小达到batch.size或者linger.ms达到上限。
-
批次发送后,发往指定分区,然后落盘到broker;
- acks=0只要将消息放到缓冲区,就认为消息已经发送完成。
- acks=1表示消息只需要写到主分区即可。在该情形下,如果主分区收到消息确认之后就宕机了,而副本分区还没来得及同步该消息,则该消息丢失。
- acks=all (默认) 首领分区会等待所有的ISR副本分区确认记录。该处理保证了只要有一个ISR副本分区存活,消息就不会丢失。
-
如果生产者配置了retrires参数大于0并且未收到确认,那么客户端会对该消息进行重试。
-
落盘到broker成功,返回生产元数据给生产者。
Leader选举
-
Kafka会在Zookeeper上针对每个Topic维护一个称为ISR(in-sync replica)的集合
-
当集合中副本都跟Leader中的副本同步了之后,kafka才会认为消息已提交
-
只有这些跟Leader保持同步的Follower才应该被选作新的Leader
-
假设某个topic有N+1个副本,kafka可以容忍N个服务器不可用,冗余度较低
如果ISR中的副本都丢失了,则:
- 可以等待ISR中的副本任何一个恢复,接着对外提供服务,需要时间等待
- 从OSR中选出一个副本做Leader副本,此时会造成数据丢失
副本消息同步
首先,Follower 发送 FETCH 请求给 Leader。接着,Leader 会读取底层日志文件中的消 息数据,再更新它内存中的 Follower 副本的 LEO 值,更新为 FETCH 请求中的 fetchOffset 值。最后,尝试更新分区高水位值。Follower 接收到 FETCH 响应之后,会把消息写入到底层日志,接着更新 LEO 和 HW 值。
相关概念:LEO和HW。
- LEO:即日志末端位移(log end offset),记录了该副本日志中下一条消息的位移值。如果LEO=10,那么表示该副本保存了10条消息,位移值范围是[0, 9]
- HW:水位值HW(high watermark)即已备份位移。对于同一个副本对象而言,其HW值不会大于LEO值。小于等于HW值的所有消息都被认为是“已备份”的(replicated)
Rebalance
- 组成员数量发生变化
- 订阅主题数量发生变化
- 订阅主题的分区数发生变化
leader选举完成后,当以上三种情况发生时,Leader根据配置的RangeAssignor开始分配消费方案,即哪个consumer负责消费哪些topic的哪些partition。一旦完成分配,leader会将这个方案封装进SyncGroup请求中发给coordinator,非leader也会发SyncGroup请求,只是内容为空。coordinator接收到分配方案之后会把方案塞进SyncGroup的response中发给各个consumer。这样组内的所有成员就都知道自己应该消费哪些分区了。
分区分配算法RangeAssignor
- 原理是按照消费者总数和分区总数进行整除运算平均分配给所有的消费者。
- 订阅Topic的消费者按照名称的字典序排序,分均分配,剩下的字典序从前往后分配
增删改查
kafka-topics.sh --zookeeper localhost:2181/myKafka --create --topic topic_x
--partitions 1 --replication-factor 1
kafka-topics.sh --zookeeper localhost:2181/myKafka --delete --topic topic_x
kafka-topics.sh --zookeeper localhost:2181/myKafka --alter --topic topic_x
--config max.message.bytes=1048576
kafka-topics.sh --zookeeper localhost:2181/myKafka --describe --topic topic_x
如何查看偏移量为23的消息?
通过查询跳跃表ConcurrentSkipListMap,定位到在00000000000000000000.index ,通过二分法在偏移量索引文件中找到不大于 23 的最大索引项,即offset 20 那栏,然后从日志分段文件中的物理位置为320 开始顺序查找偏移量为 23 的消息。
切分文件
- 大小分片 当前日志分段文件的大小超过了 broker 端参数
log.segment.bytes配置的值 - 时间分片 当前日志分段中消息的最大时间戳与系统的时间戳的差值大于
log.roll.ms配置的值 - 索引分片 偏移量或时间戳索引文件大小达到broker端
log.index.size.max.bytes配置的值 - 偏移分片 追加的消息的偏移量与当前日志分段的偏移量之间的差值大于 Integer.MAX_VALUE
- [ 萱儿AXW ]