Kafka学习之路
架构
- Producer:消息⽣产者,向 Kafka Broker 发消息的客户端。
- Consumer:消息消费者,从 Kafka Broker 取消息的客户端。Kafka支持持久化,生产者退出后,未消费的消息仍可被消费。
- Consumer Group:消费者组(CG),消费者组内每个消费者负责消费不同分区的数据,提⾼消费能⼒。⼀个分区只能由组内⼀个消费者消费,消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的⼀个订阅者。
- Broker:⼀台 Kafka 机器就是⼀个 Broker。⼀个集群(kafka cluster)由多个 Broker 组成。⼀个 Broker 可以容纳多个 Topic。
- Controller:由zookeeper选举其中一个Broker产生。它的主要作用是在 Apache ZooKeeper 的帮助下管理和协调整个 Kafka 集群。
- Topic:可以理解为⼀个队列,Topic 将消息分类,⽣产者和消费者⾯向的是同⼀个 Topic。
- Partition:为了实现扩展性,提⾼并发能⼒,⼀个⾮常⼤的 Topic 可以分布到多个 Broker上,⼀个 Topic 可以分为多个 Partition,同⼀个topic在不同的分区的数据是不重复的,每个 Partition 是⼀个有序的队列,其表现形式就是⼀个⼀个的⽂件夹。不同Partition可以部署在同一台机器上,但不建议这么做。
- Replication:每⼀个分区都有多个副本,副本的作⽤是做备胎。当主分区(Leader)故障的时候会选择⼀个备胎(Follower)上位,成为Leader。在kafka中默认副本的最⼤数量是10个,且副本的数量不能⼤于Broker的数量,follower和leader绝对是在不同的机器,同⼀机器对同⼀个分区也只可能存放⼀个副本(包括⾃⼰)。
- Message:每⼀条发送的消息主体。
- Leader:每个分区多个副本的“主”副本,⽣产者发送数据的对象,以及消费者消费数据的对象,都是 Leader。
- Follower:每个分区多个副本的“从”副本,使用发布订阅模式主动拉取Leader的数据(与redis不同),实时从 Leader 中同步数据,保持和 Leader 数据的同步。Leader 发⽣故障时,某个 Follower 还会成为新的 Leader。
- Offset:消费者消费的位置信息,监控数据消费到什么位置,当消费者挂掉再重新恢复的时候,可以从消费位置继续消费。
- ZooKeeper:Kafka 集群能够正常⼯作,需要依赖于 ZooKeeper,ZooKeeper 帮助 Kafka存储和管理集群信息。
- High Level API 和Low Level API :高水平API,kafka本身定义的行为,屏蔽细节管理,使用方便;低水平API细节需要自己处理,较为灵活但是复杂。
工作流程
Kafka集群将 Record 流存储在称为 Topic 的类中,每个记录由⼀个键、⼀个值和⼀个时间戳组成。
Kafka 中消息是以 Topic 进⾏分类的,⽣产者⽣产消息,消费者消费消息,⾯向的都是同⼀个Topic。Topic 是逻辑上的概念,⽽ Partition 是物理上的概念,每个 Partition 对应于⼀个 log ⽂件,该log ⽂件中存储的就是 Producer ⽣产的数据。Producer ⽣产的数据会不断追加到该 log ⽂件末端,且每条数据都有⾃⼰的 Offset。消费者组中的每个消费者,都会实时记录⾃⼰消费到了哪个 Offset,以便出错恢复时,从上次的位置继续消费。
存储机制
由于⽣产者⽣产的消息会不断追加到 log ⽂件末尾,为防⽌ log ⽂件过⼤导致数据定位效率低下,Kafka 采取了分⽚和索引机制。它将每个 Partition 分为多个 Segment,每个 Segment 对应两个⽂件:.index
索引⽂件和 .log
数据⽂件。这种索引思想值得我们学习应用到平时的开发中。
怎么避免重复消费
出现重复消费的情况:
Broker
存储的消息都有Offset
标记,消费者通过Offset
标记维护当前已经消费的数据,每消费一批数据,就更新一次。消费端默认5
秒后向Broker
获取消息时,自动提交Offset
。当消费者消费时,应用程序宕机,可能导致Offset
没有提交,产生重复消费。Partition Balance
机制,把多个Partition
均衡的分给多个消费者。如果Consumer
在默认的5
分钟内没有处理完这一批消息,就会触发Kafka的Rebalance
机制,导致Offset
提交失败。Rebalance
后,Consumer
端继续从未提交的Offset
位置进行消费。
解决方法:
- 提高消费端处理性能,避免处罚
Balance
。- 采用
异步
的方式处理消息,缩短单个消息消费的时长。 - 调整消息处理的超时时间。
- 减少一次性从
Broker
上拉取的数据条数。
- 采用
- 针对消息生成
md5
然后保存到mysql
或者redis
里,在处理消息之前先去mysql
或者redis
藜麦牛奶判断是否已经消费过。
如何保证信息不丢失
-
Producer
端确保消息能够到达Broker
,并且实现消息的存储。这过程如果发生网络问题,有可能消息丢失。解决方法:
- 把
异步发送
改为同步发送
,这样Producer
就能实时知道消息发送的结果。 - 添加异步回调函数来监听消息发送的结果,如果发送失败,可以在回调中重试。
- 重试参数
retries
,Producer
自动重试。
- 把
-
Broker
端将消息持久化到磁盘。Kafka为提升性能,采用异步批量
的实现机制,按照一定的消息量和时间间隔去刷盘。刷盘的动作由操作系统调度,若刷盘前系统崩溃,则数据丢失。解决方法:
Partition副本机制
以及acks机制
:producer
端设置request.required.acks = 0
;只要请求已发送出去,就算是发送完了,不关心有没有写成功。性能很好,如果是对一些日志进行分析,可以承受丢数据的情况,用这个参数,性能会很好。request.required.acks = 1
;发送一条消息,当leader partition写入成功以后,才算写入成功。不过这种方式也有丢数据的可能。request.required.acks = -1
;需要ISR列表里面,所有副本都写完以后,这条消息才算写入成功。
Kafka如何保证消息消费的顺序性
Producer
发送消息的时候,根据消息的key
进行取模,来决定把当前消息存储到哪一个Partition
中。因Consumer
是完全独立的网络节点,就可能会出现读取不是按照发送顺序来实现的。
解决方法:
- 自定义消息分区的路由算法,把指定的
key
都发送到同一个Partition
中,指定一个Consumer
去消费。 Consumer
端采用阻塞队列,将获取的消息先保存到阻塞队列,再用异步线程从阻塞队列中获取消息。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Abacteria的学习小站!