kafka核心点学习记录【及其个人的一些思考】

组成:

生产者、消费者、kk集群,zk协调器

分布式消息队列(kafka的好处和缺点):
优点:可以削峰、 解耦、 数据持久化不丢失
缺点:增加开发复杂度

消息队列的两种模式:

拉取、推送
kk采取的是拉取,因为推送的话,如果消费端消费能力差,会导致数据堆积,拉取的话,消费者会根据自己的消费能力取处理数据

集群broker存储:

topic主题(抽象的),一个主题分为多个Partition(分区),每个分区由leader和follower组成,创建主题时,follower数据不能大于broker的数量,否则会报错,

根据index查找data的方法

图片.png

kk读写都是通过leader(这点和zk不同)。
一个Partition又分为多个segment,一个segment有两个文件注册,000000.log,000000.index分别用于存放数据和
索引的(数据的偏移量),命名分别为该segment的第一条记录命名。 分区的好处是可以提供并发和扩展

kafka基础架构:

图片.png

kafka生产者:

1.副本同步策略:目前有2中,超过半数返回ack即可(2n+1),全部返回ack(n+1)都可以保证n个挂了还能工作。kk选择了后者,前者太浪费资源,并且数据存储
过大,因为kafka都存储很多数据的。后者为了提高效率,如果其中有一台迟迟不给响应,解决这个问题,提出了isr(in-sync replica set),只要isr里面的给 ack即可,leader本身也是isr中的一员。 关于isr在0.11版本后有个调整,之前是根据和leader同步的时间长短和数据差距大小来判断是否可以进isr,
由于leader是batch操作,会出现,比如leader一次性写了100条,此时follower都还没同步,且100大于配置的10条,则follower全部被提出isr,会造成频繁的
加入剔除,所有现在只以时间为依据。

  1. ack应答机制(确定消息是否会丢失的关键因素):
    0:收到就给生产者返回ack,如果此时broker挂了,会造成数据丢失。 至多一次性
    1:broker的leader落盘成功后,就给ack,如果此时leader挂了,新选的follower作为leader(没有同步到数据),也会丢失数据。
    -1:leader和follower(isr中的)全部落盘成功后,才返回ack,此时理论上不会丢数据,如果leader在完成和follower同步够,在返回ack之前挂了,新选的 leader已经有数据了,但是生产者还会重新发送,因为没有收到ack, 此种情况会造成数据库重复。 有个极端情况会丢数据库,isr中有且只有一个,即leader本身。 至少一次性

  2. 设置生产者分区策略:
    指定Partition分区编号
    没有Partition,但有key,根据消息计算出hashhode然后和topic的Partition数量进行取余
    没有Partition,也没key,第一次生成一个数,然后每次在这个数上递增,把这个数据和topic的patition数量取余

  3. 存储策略:
    无论消息是否被消费,都会被存储所有消息,并且提供两种删除策略:
    1)基于时间:log.retention.hours=168
    2)基于大小:log.retention.bytes=1073741824

  4. 故障恢复细节:【HW高水位,是消费者可见的值,leo是broker存储的】
    1)follower故障: 会被踢出isr,当follower恢复后,会读取本地存储的上次的HW,截掉高于hw的,然后从leader同步,当该follower的leo大于partition
    hw后,则加入isr. leo=log end offerset
    2) leader故障,重新选举一个leader,follower将大于hw的数据全部截掉,然后和leader同步数据。 此过程有可能会有数据丢失和重复的情况。
    比如之前的leader 正在写50条数据,follower1 同步了49条,leader挂了,没有给producer发送ack,然后follower1又被选作了leader,此时 producer会重新发送者50条消息,前49条会重复,因为其他follower节点会同步新leader的这49个数据。

  5. 事物 <pid + partition + seqNumber> 做缓存,当具有相同主键时,broker只持久化一条,仅限于 同会话同partition中。

kafka消费者:

  1. 分区策略:
    1.1 轮询策略(RoundRobin):该策略是把消费者组看成一个整体,会把消费者组订购的所有主题,轮询的把各个partitioin分配给各个消费者
    优点:分配比较均匀,最多的和最少的只会相差一个partition
    缺点:必须要消费者都订购相同的主题才可以用,否则会造成问题,把没有订购的主题也分配了消费者。
    1.2 range策略: 是把主题看做一个整体,把topic的partitioin分配给订购了该主题的消费者,而不是消费者组,会造成分配不均匀的问题。也是kafka默认的
    消费策略。
    1.3 RangeAssignor分配策略
    RangeAssignor策略的原理是按照消费者总数和分区总数进行整除运算来获得一个跨度,然后将分区按照跨度进行平均分配, 以保证分区尽可能均匀地分配给所有的消费者。对于每一个topic,RangeAssignor策略会将消费组内所有订阅这个topic的消费者按照名称的字典序排 序,然后为每个消费者划分固定的分区范围,如果不够平均分配,那么字典序靠前的消费者会被多分配一个分区。

假设n=分区数/消费者数量,m=分区 数%消费者数量,那么前m个消费者每个分配n+1个分区,后面的(消费者数量-m)个消费者每个分配n个分区。

为了更加通俗的讲解RangeAssignor策略 , 我们不妨再举一些示例。假设消费组内有2个消费者C0和C1,都订阅了主题t0和t1,并且每个主题都有4个分区,那么所订阅的所有分区可以标识为 : t0p0、t0p1、t0p2、t0p3、t1p0、t1p1、t1p2、t1p3。最终的分配结果为:

参考文章 https://blog.csdn.net/u013256816/article/details/81123600

  1. 消费者offerset的维护:由于消费者消费过程中会出现比如挂掉,宕机的问题,所有消费者会把消费的offerset存储起来,0.11之前存储在kafka中,0.11及其后
    可以存储在borker的一个consumer_offerset主题中,共有50个分区。 存储offerset的方式是 consumerGroup + topic + partitioin的
    方式,只有这样,一个comsumer挂了,组内另外一个consumer才能继续消费,要不然没法继续消费,每个partition都有offerset。

  2. 消费者组:
    什么是消费者组?
    consumer group是kafka提供的可扩展且具有容错性的消费者机制。既然是一个组,那么组内必然可以有多个消费者或消费者实例,它们共享一个公共的ID,即group ID。组内的所有消费者协调在一起来消费订阅主题(subscribed topics)的所有分区(partition)。当然,每个分区只能由同一个消费组内的一个consumer来消费

一个消费者组内有多个消费者,如果通过命令行操作,可以通过配置文件改默认组名,要不然没启一个消费者客户端,都生成一个新组,一个partition
只能被一个组内的一个消费者消费,要不然就乱了,根据消费者offerset维护可以看出,一个consumer可以消费多个partion,多个消费者组可以消费同
一个partition。 若果消费者的个数大于分区数,则会有消费者消费不到数据

  1. controller:
    kafka集群中有一个broker被选举为controller,负责管理集群broker的上下线,所有topic的分区 副本分配和leader选举工作。controller的工作都是
    依赖zk来完成的。controller_epoch 记录了controller变化的次数,也就是切换了多少次,次数大了说明集群不稳定,controller总是重新选举.

zk在kk中的作用:

图片.png

4.1 、读取zk上,broker、topic、partition的信息进行管理,并且同步到其他broker中

4.2 、 在zk的/brokers/ids/上注册brokerChangeLinsener监听器监控broker变化

4.3、 在zk的/brokers/topics/上注册TopicChangeListener监听器监控topic变化

4.4、监听partition相关的变化。为Zookeeper中的/admin/reassign_partitions节点注册
PartitionReassignmentListener,用来处理分区重分配的动作。为Zookeeper中的/isr_change_notification节点注册 IsrChangeNotificetionListener,用来处理ISR 集合变更的动作。为Zookeeper中的/admin/preferred-replica-election节点添加 PreferredReplicaElectionListener,用来处理优先副本的选举动作。
一旦有partition leader挂了,就进行leader选举。ISR机制,优先副本等

4.5、负责topic创建时的分区分配工作,随机选择一台机器分配partition0,其他分区顺序分配,下一台机器分配partition1,以此类推。

  1. 消费者在分配问题:
    哪些情况会出现再分配?
    1.添加消费者, 删除消费者,会触发消费者再分配。
    哪些情况会重新消费?
    1.手动添加参数,from begining
    2.修改消费者组名称

  2. 生产者API:
    生产者发送消息的一些注意点:

6.1. 一共有两个线程和一个变量:一个main线程,一个发送线程(sender),一个共享变量(RecordAccumulator),main线程生成消息到共享变量中,
sender线程从共享变量中发送消息。
6.2. main线程处理消息的流程:
每条记录是一个ProducerRecord记录,回经过intercepters-->Serializer-->Partitioner ,我们可以扩展拦截器和分区器,一般都是批量发送
RecorderBatch
6.3. 发送的时候两个重要参数:
batch.size, linger.ms, 累计到多少条开始发送, 如果迟迟没到,sender等待linger.ms会发送。
producer.close()的时候也会发送。
6.4. 异步发送不能保证消息的有序性,如果用一个分区,也不行,因为有消息发送失败重试的机制【kafak生产者自己的机制,可以关闭】,一个分区
且幂等性可以保证。 另外一个方案,用一个分区,且同步发送的方式也可以。消息有序的需求场景比较少。

  1. 消费者API
    消费者发送消息的一些注意事项
    消费者消费数据,会有offerset提交的问题
    1. 自动提交:
    每条记录是consumerRecord,消费者也是批量消费。
    kafak提供了自动提交机制,自动提交的问题:会出现重复消费问题,自动提交的时间点我们没法控制。会带来如下问题:
    比如一次性拉取了10条数据,消费了3条,此时自动提交了offerset,消费者挂了,此时已经提交了offerset,再次重启消费者,会跳过这10条记录,
    因为已经提交过了,会丢数据。 如果消费了3条,还没提交,此时挂了,再次重启,还继续从10条开始消费,会重复消费。
    2. 手动提交:
    手动提交又分为同步提交和异步提交,同步提交会阻塞线程,速度较慢,一般用异步提交,手动提交不会丢数据,因为都是等消费完了再提交的。
    但是会有重复数据的问题,因为 消费操作和提交操作不在一个事物里面。所以要保证重复消费的问题,必须自定义提交,把消费和提交放在一个事物里面
    然后把offerset记录在mysql里面。
    1. 监控 Eagle
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容