目录
1. 什么是Kafka
Kafka是LinkedIn自研的消息传递系统,起初是用于解决其内部数据管道问题,后来因为高吞吐、可扩展、社区成熟度高等特点成为业内主流的分布式消息队列。
2. Kafka使用场景
Kafka可用于消息队列、日志收集与传输、流数据处理等。下面列举自己工作中使用过的2种场景:用作消息队列和日志收集。
2.1. 用作消息队列
业务场景:业务服务和大数据服务通过Kafka解耦,大数据服务将数据投递到Kafka,业务服务订阅消费。
2.2. 作为ELK日志的数据源
业务场景:为缓解ElasticSearch服务端的压力,用Kafka做数据分流,将采集的业务应用日志存储到kafka,然后LogStash消费Kafka中存储的消息数据,并将消费后的数据写入到ElasticSearch进行存储,最后我们就可以通过Kibana来查询、分析日志了。
3. 核心概念
3.1. Broker
即Kafka的服务器
3.2. partition
每个partition是1个log文件,发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量)。
log文件根据broker中的配置要求,保留一定时间后(默认7天)删除来释放磁盘空间。
Partition索引:每隔一定字节的数据建立一条索引。
3.3. offset
即消费者偏移量,kafka会自行创建_consumer_offsets的topic用于保存consumer提交的位移。
3.4. Consumer Group
即消费者分组,一个partition中的消息只会被同一group中的一个consumer消费,但可以被不同组的consumer消费。每个group中consumer消息消费互相独立。
4. 消息积压
常见原因 | 解决方法 |
consumer挂掉、消费者"消费能力"不足 | 扩容consumer,增加消费能力,从而处理积压数据 |
分区数设置太少 | 如果当前partition<consumer可以合理的增加分区 |
消息发到partition不均匀,导致发生数据倾斜 | 配置合适的消费者分区分配策略,比如roundrobin,让消息分配均匀 |
5. 消息重试
5.1. 生产者重试策略
在Spring中默认重试策略为:重试次数为0,重试间隔为100ms。可以在yml中配置,支持的属性可以查看ProducerConfig类。
5.2. 消费者重试策略
在Spring中默认重试策略为:消费逻辑抛出异常时,会快速重试10次,重试间隔100ms,如果重试完成后依旧消费失败会commit这条记录。有2种方案配置重试策略:
方案一:
全局配置重试策略RetryTopicConfiguration对所有消费者生效,或者单独在方法上使用@RetryableTopic对单个消费者生效。自动生成retry topic和dlt topic。
方案二(推荐,比较简单):
全局配置SeekToCurrentErrorHandler。
6. Rebalance
6.1. 概念
消费组里的消费者数量有变化或消费的分区数有变化,kafka会重新分配消费者消费分区的关系。
6.2. 分区分配策略
就是将topic的partition分配给consumer的方式,包含:range(范围分配,默认策略)、round-robin(轮询)、sticky(粘性)。
6.3. 影响
在重平衡过程中,所有的消费者实例均不能消费任何消息。
7. 分区分配策略
7.1. 生产者分区分配策略
》如果指定了分区则发到指定分区
》如果没指定分区且消息key不为空,则基于key的哈希值来选择一个分区
》如果没指定分区且消息key为空,则用轮询的方式选择一个分区
源码实现:org.apache.kafka.clients.producer.internals.DefaultPartitioner
7.2. 消费者分区分配策略
》range(默认):实现类org.apache.kafka.clients.consumer.RangeAssignor,先看分区能不能均分,能均分就1人1个,不能的话,字典顺序排序前面的消费者多负责1个分区,比如consumer1,consumer2,partition0,partition1,partition2,不能均分,则consumer1负责p0,p1,consumer2负责p2。
》roundrobin:实现类org.apache.kafka.clients.consumer.RoundRobinAssignor,将partition轮着分给consumer。
8. 消息消费顺序
保证消息消费顺序的方式:
方式1:发送消息的时候指定partition
方式2:业务自己写逻辑保证
比如根据消息的updateTime判断消息先后顺序
9. 消息可靠性
9.1. 发送方可靠性
发送时由于网络原因消息没有发送出去,可设置Producer的重试次数和重试间隔尽可能保证消息发送可靠性。
9.2. 消费者可靠性
默认是自动提交offset,如果消费者刚拿到这个消息还未开始处理业务逻辑机器挂了,此时offset已被自动提交,就会导致消息没消费到。可开启手动提交,注意消费逻辑做好幂等。使用自动还是手动要根据业务场景决定。
9.3. broker导致的丢失
一般情况下,kafka多副本机制保证了可靠性,但某些极端情况下仍可能出现消息丢失,比如:leader 所在的 broker 突然挂掉,就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失。可通过设置参数尽可能降低了消息丢失的可能性,比如:设置副本数replication.factor >= 3和min.insync.replicas > 1(代表消息至少要被写入到 2 个副本才算是被成功发送)
10. 延迟队列
Kafka本身并没有提供原生的延迟队列功能,需要自己设计方案处理。
方案一(实现复杂而且时间不准):利用Kafka的时间戳
生产者发送消息时,设置消息的时间戳为当前时间加上延迟时间:
在消费者的消息处理逻辑中,判断消息的时间戳是否已经超过当前时间,如果超过则进行正常的消费处理,否则将消息重新发送到延迟主题,并设置新的延迟时间:
11. Zookeeper的作用
为 Kafka 提供元数据的管理的功能,主要做了以下几点:
11.1. Broker 注册
Broker启动时会将自己的ip、端口等信息注册到zk
11.2. Topic 注册
Topic和partition信息也会注册到zk
11.3. 负载均衡
当 Consumer 消费的时候,Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡。