kafka整体架构
主要包含三大模块:
- 生产者:发送消息的进程集合
- 消费者:消费消息的进程集合
- kafka集群: 包含broker集合,作为消息引擎的服务器,接收发送者的消息并存储,接收消费者的pull请求并发挥消息,保证消息的可靠性等工作
主题(topic) & 分区(partition):
topic相当于是一个队列,每条消息必须指定发送哪个队列。 为了使kafka的吞吐率能水平扩展,物理上把topic分成 一个或多个partition,每个partition对应一个文件夹,存储所有这个partition的消息和索引文件。
pull模式 vs push模式:
push模式能够让消费者及时的获取到消息,但是很难适应不同消费速率的消费者。
pull模式消费者根据自己的消费能力主动去拉取消息,但是会有一定程度的消息延迟。
消息分区(partition)机制
- 分区策略
所谓分区策略,就是决定生产者将消息发送到哪个分区的算法。常见分区策略有如下几种:
1)轮询策略: kafka生产者提供的默认策略, 将消息均匀的放入多个分区中。
2) 随机策略: 随机将消息放入一个分区中。
3) 按消息key保序策略: 生产者在发送消息的时候,需要指定消息的key, 这个key下的所有消息都会放入同一个分区中,并且都是有序的。
消费组(Consumer Group)
消费组(Consumer Group) 是kafka提供的可扩展且具有容错性的机制。有以下两个个特性:
1) Consumer Group 下可以由一个或多个Consumer 实例,用Group Id唯一标志消费组;
2) 主题的一个分区,只能分配给这个Consumer Group下的一个消费者实例消费, 这个分区也可以被其他Consumer Group下的一个消费者实例消费。
Consumer Group与传统消费队列和发布订阅/模式的区别
1)传统消费队列,一旦某条消息被消费,则从队列里删除,并且下游多个消费者竞争消费一条消息;
2) 发布/订阅,允许一条消息被多个消费者消费,但是消费者需要订阅主题下的所有分区.
Consumer Group实例数量设置
理想情况下,Consumer 实例数量应该等于该group订阅主题的分区总数。当然也可以小于分区总数,如果多余分区总数,就会有实例没有分配到分片。
位移维护
在老版本的Kafka中,位移保存是依赖于外部的zookeeper, 目的是为了让broker服务节点做成无状态,以便自动地伸缩容。但是zookeeper不适合频繁写入的场景,在后面的版本中,将位移信息存储在broker中。位移信息类似这样一个结构:Map<topic_partition, long>,其中 TopicPartition 表示一个分区,而 Long 表示位移的类型。
reblance
reblance目的是让一个消费组的消费者能够均匀的消费所订阅的主体下的消息。reblance触发的条件有3个:
1) 消费组成员数变更
2)订阅主题数变更
3) 订阅主题分区数变更
在 Rebalance 过程中,所有 Consumer 实例都会停止消费,等待 Rebalance 完成。并且reblance的过程很慢,这是 Rebalance 为人诟病的一个方面。所以建议提前做好规划,规划好分区数和消费者节点数。
kafka高可用机制
kafka是通过副本机制来实现高可用的。每个主题下有多个分区,kafka的副本是在分区级别做的,每个分区配备有若干个副本。kafka的副本只是用来做冗余的,并没有像Mysql之类的副本还可以分担主节点的读请求,也没有为了提高读请求的局部性。kafka之所以这样设计,是因为:
1) 方便实现"read-your-writes"
当向kafka发送一条消息,能够读到最新的内容。如果从副本也提供读请求,从副本可能没有获取到最新的主副本内容。
2) 实现单调读
如果多个副本提供读请求,一个客户端第一次请求到了一个副本,下次到另外一个副本,由于副本之间不是一致性的,就会存在两次读请求数据不一致的问题。
主副本与从副本
kafka中有两类副本,领导者副本,和追随者副本,领导者副本对外提供读写,追随者副本只用来做冗余的。追随者副本不处理客户端请求,它唯一的任务就是从领导者副本异步拉取消息,并写入到自己的提交日志中,从而实现与领导者副本的同步。当领导者副本挂掉了,或者领导者所在的Broker挂了,依赖于zookeeper做选举,从追随者副本中选举一个副本作为主副本。那选择哪一个副本作为主副本呢?
ISR
Kafka 引入了 In-sync Replicas,也就是所谓的 ISR 副本集合。ISR 中的副本都是与 Leader 同步的副本,相反,不在 ISR 中的追随者副本就被认为是与 Leader 不同步的。怎么才是认为与主副本同步的呢?这个标准就是 Broker 端参数 replica.lag.time.max.ms 参数值。这个参数的含义是 Follower 副本能够落后 Leader 副本的最长时间间隔,当前默认值是 10 秒。这就是说,只要一个 Follower 副本落后 Leader 副本的时间不连续超过 10 秒,那么 Kafka 就认为该 Follower 副本与 Leader 是同步的,即使此时 Follower 副本中保存的消息明显少于 Leader 副本中的消息。
Unclean 领导者选举
ISR 是可以动态调整的,那么自然就可以出现这样的情形:ISR 为空。ISR 是空,此时该怎么选举新 Leader 呢?Broker 端参数 unclean.leader.election.enable 控制是否允许 Unclean 领导者选举。开启 Unclean 领导者选举可能会造成数据丢失,但好处是,它使得分区 Leader 副本一直存在,不至于停止对外提供服务,因此提升了高可用性。反之,禁止 Unclean 领导者选举的好处在于维护了数据的一致性,避免了消息丢失,但牺牲了高可用性。