kafka随笔记

kafka如何保证有序性?看资料

需要保证有顺序的消息进入到一个分区中(这个用key来保证),要保证同一个分区中的消息是有序的(链表,新来的放后面就是了),同一个分区中的消息是顺序被消费的(分区分配与offset来保证)。

生产者

分区。每个主题topic有自己的分区。给业务定个topic。

分区器。根据key来确定进入哪个分区。一个key对应一个分区,保证有同样的key,就能保证进入到同一个分区中。分区数不变的时候,一个key对应一个分区,分区数变化会发生在手动修改配置更改分区数、数据迁移扩容的时候,这个时候一个key可能会分到别的分区,就不好保证顺序性了。

消费者:

分区分配策略。范围分配策略(Range Assignor,默认),轮询分配策略(RoundRobinAssignor)或粘性分配策略(StickyAssignor)等。 做分区与消费者组的映射,每个分区每次分配的时候,只能被一个消费者组消费。但是如果消费者没法送心跳,broker会认为消费者宕机,就会重新分配,那这个分区可能会被其他消费者消费。

offset偏移量。分区会保留消费者返回的偏移量。如果消费者切换了,从消费者1切换到消费者2,消费者2可以从offset开始消费,避免重复消费之前的消息,保证有序性。

 

分区大小管理

分区的清理策略有删除策略(Delete Policy)、压缩策略(Compact Policy)和日志清理策略(Log Cleaning Policy)等。默认是删除策略,删除策略有时间保留策略(默认是删除7天前的)、大小保留策略等。分区由多个片段组成,片段大小最大默认是1g,如果分区满了,会删除片段,从而释放内存。

 

集群化体现

Kafka其实天生就是为了集群而生,即使单个节点运行Kafka,他其实也是作为一个集群运行的。而Kafka为了保证在各种网络抽风,服务器不稳定等复杂情况下,保证集群的高性能,高可用,高可扩展三高,做了非常多的设计,核心都是为了保持整个集群中Partition内的数据一致性

zookeeper中关于kafka集群最为主要的状态信息有两个。

一个是在多个Broker中,需要选举出一个Broker,担任Controller角色。由Controller角色来管理整个集群中的分区和副本状态。

另一个是在同一个Topic下的多个Partition中,需要选举出一个Leader角色。由Leader角色的Partition来负责与客户端进行数据交互。

ControllerBroker选举机制

Controller Broker负责选举和管理所有的Partition Leader

kafka集群启动时,broker会往zookeeper中创建controller,只有一个broker能注册成功。

LeaderPartition选举机制

Leader负责处理所有的读写请求,Follower进行数据的同步和备份。

在选举Leader Partition时,会按照AR中的排名顺序,靠前的优先选举。只要当前Partition在ISR列表中,也就是是存活的,那么这个节点就会被选举成为Leader Partition。

LeaderPartition自动平衡

尽量避免一个broker中有多个leaderPartition的情况,尽量保证partitionLeader是均匀分布到各个broker中的,避免单个broker性能过载。LeaderPartition选举机制后,容易出现不均衡的情况,kafka有提供自平衡操作,controller会定期去看各个broker的情况,然后进行平衡。

但自平衡的过程是一个非常重的操作,因为要涉及到大量消息的转移与同步。并且,在这个过程中,会有丢消息的可能。所以在很多对性能要求比较高的线上环境,会选择将参数auto.leader.rebalance.enable设置为false,关闭Kafka的Leader Partition自平衡操作,而用其他运维的方式,在业务不繁忙的时间段,手动进行Leader Partiton自平衡,尽量减少自平衡过程对业务的影响。

Partition故障恢复机制

保证broker主从数据一致性,不能保证数据安全,会丢失数据。rocketMQ在数据安全这一块就做的比较好。

a6468850fbc3469ab8e7c985d501bc3b.png

每个partition都有一个LEO(Log End Offset):,就是每个Partition的最后一个Offset,当一个消息放入partition中时,leo会加一。一个broker中有多个partition,所有partiion中最小的leo就是HW(High Watermark)。hw之前的数据才能被消费者消费,并且是持久化了的。只有当所有follower完成数据同步后,leader才会向生产者发送确认ack。故障恢复与一致性就是以这个hw为基准的。

如果follwer宕机,follwer会获取hw,然后向leader同步hw后的数据,至于hw之前的数据,已经持久化甚至被消费了,可以不予理会。

如果leader宕机,zookeeper会监测到,然后通过watch机制通知controller,controller会选出新的leader,新的leader,新的leader获取hw,然后所有follower中hw之后的数据都会删除,旧的leader恢复后hw后的也会删除,然后作为新的follower。所以旧leader中hw之后的数据都会丢失。但这保证了数据一致性

Epoch更新机制

如何保证hw的一致性?hw是leader维护的,follower拉取的,如果leader宕机,有的follower还没拉取最新的hw,新的leader出现,可能会出现hw不一致的情况。所以用Epoch机制。每个leader有一个epoch版本号,并记录到本地文件中,新来的leader的epoch会加一。follower同步的时候,会对比自己的epoch和leader的epoch是否相等,如果小于,则说明leader更新了,要重新获取hw。

Epoch 英文是纪元的意思

 

Kafka的文件高效读写机制

文件结构

.log(用来存partition内容的,最大1g);.timeindex/.index(索引文件,方便快速定位)

9002ed34caef4db285b82e8a8d58d324.png

顺序写

对每个Log文件,Kafka会提前规划固定的大小,这样在申请文件时,可以提前占据一块连续的磁盘空间。然后,Kafka的log文件只能以追加的方式往文件的末端添加(这种写入方式称为顺序写),这样,新的数据写入时,就可以直接往直前申请的磁盘空间中写入,而不用再去磁盘其他地方寻找空闲的空间(普通的读写文件需要先寻找空闲的磁盘空间,再写入。这种写入方式称为随机写)。由于磁盘的空闲空间有可能并不是连续的,也就是说有很多文件碎片,所以磁盘写的效率会很低。

零拷贝

sendfile:在broker把消息给consumer发过去的时候使用。数据可以直接从磁盘缓冲区通过网络传输,而不需要先将数据拷贝到应用程序的内存空间。

mmap:虽然Kafka的官方文档可能不直接提及mmap,但Kafka确实通过类似mmap的机制(如利用操作系统的页面缓存)来访问存储在磁盘上的日志文件和索引文件。这种方式允许应用程序直接访问内核缓冲区中的数据,而无需将数据从内核复制到应用程序的内存中,从而避免了不必要的数据复制。

 

日志清理

查看过期日志:每五分钟(默认,可自己设置)检查日志,如果日志保存时间超过7天(默认,可自己设置),就会认为过期

 过期日志处理:删除或者压缩。压缩会导致消息丢失,一般不建议。删除的话还可以进行选择,如果所有文件大小大于域值(可设置),才进行删除操作。

 

操作系统来决定何时刷盘

partition等信息进行持久化。信息先到内存,内存是多久才fsync到磁盘呢?

kafka提供了3中方式来触发刷盘。一是消息追加到某个阈值,二是定时刷盘,三是创建新日志时触发刷盘。但kafka默认情况下,没有用上面的一二设为空。也就是说,Kafka采用异步刷盘方式,即将数据写入页缓存后,由操作系统决定何时将其写入磁盘。这种方式可以提高写入性能,但可能会降低数据的实时持久化能力。

 

优化建议

topic:1、尽量不要使用过多的Topic,通常不建议超过3个Topic。过多的Topic会加大索引Partition文件的压力。2、每个Topic的副本数不要设置太多。大部分情况下,将副本数设置为2就可以了。

partition数量:设置多一些可以一定程度增加Topic的吞吐量。但是过多的partition数量还是同样会带来partition索引的压力。因此,需要根据业务情况灵活进行调整,尽量选择一个折中的配置。

合理对数据进行压缩:有4中压缩策略,如果压缩了,消费者消费时需要解压

生产者:一般是acks设为1,表示leaderPartition收到消息后,无需等待同步到follower就会返回给生产者。然后开启幂等性,防止重复生产

消费者:一般要解决重复消费的问题,然后会在redis中存offset,如果redis的offset比当前消息的offset大,表示这个消息已经消费过了。

最好不要异步消费,因为如果业务逻辑异步进行,而消费者已经同步提交了Offset,那么如果业务逻辑执行过程中出现了异常,失败了,那么Broker端已经接收到了消费者的应答,后续就不会再重新推送消息,这样就造成了业务层面的消息丢失。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值