Kafka架构及其原理
架构图
一个kafka集群中包含一个或多个Producer、一个或多个broker、一个或多个ConsumerGrop以及一个Zookeeper集群。kafka通过Zookeeper管理kafka集群配置、leader副本的选举、生产者的负载均衡等。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。
专业术语
-
kafkaCluster : kafka集群,由一个或多个Broker节点组成。
-
Broker : 一个Kafka集群包括一个或多个服务器,一台服务器就是一个Broker节点。Broker用于保存Producer发送的消息。
-
Producer :生产者,用来发送指定的Topic的消息到Broker。生产者可以是代码,还可以是命令行工具。本质上是一个进程或者线程。
-
Consumer :消费者,用来接收/消费Kafka集群中的消息。每个Consumer属于一个ConsumerGroup(如果在创建消费者时没有指定Consumer,系统会默认分配一个ConsumerGroup),消费者可以是代码,还可以是命令行工具,本质上就是一个进程/线程。
-
ConsumerGroup :消费者组,由一个或多个Consumer组成(在同一个消费者组的消费者具有相同的
group.id
),便于管理Consumer。 -
Zookeeper :在Kafka集群中用来存储元数据,如:有Broker节点信息、分区的信息、分区与Broker的对应关系、生产者的负载均衡等等。
-
Topic :主题,主题用于区分业务,比如订单主题业务,购物车主题业务,物流主题业务……方便对消息进行分类管理
-
Partition :分区,一个Topic的消息由一个或多个Partition存储。分区的作用是提高读写并行度/读写效率。
-
Segment :分段,发送到kafka集群的消息会先存到内存中,然后划分文件夹、划分文件存入磁盘中
备注: Kafka中有分区和分段的概念,分区就是分文件夹,分段就是分文件。这个思想在Hive中也有:Hive中的分区就是分文件夹,Hive中的分桶就是分文件。
-
Replication :副本,副本的作用是保证数据的安全性,副本分为Leader(主副本)和Follower(从副本),Leader只有一个,Follower可以有多个,但是副本数一般都为1-3个(副本数过多会占用大量的存储空间)。
注意:读写都只能从Leader进行,Follower在Leader宕机后自动选举出新的Leader。
扩展: 为什么读写都只能从Leader进行?
答:保证数据的一致性,只在Leader中进行写入数据,Follow同步Leader中的数据,在写过程中避免了多个副本中存储的数据不同的问题。Leader 和 Follow之间同步数据存在延时,所以读操作也需要在Leader中进行。
-
ISR : 表示目前Alive(活着的)且与Leader能够 “Catch-up”(跟得上)的Replicas(Follower)集合。
-
Record :记录,就是发送到Kafka集群的消息。一条消息就是一条记录。
-
offset : 偏移量,用于记录消息的序号,各个分区的偏移量都是从0开始。
架构详解
1.生产者
- 生产者采用push(推模式)向集群发送消息,并且消息是被顺序写磁盘追加到分区中,提高了kafka的写效率(吞吐量)
备注:顺序写效率>>随机写效率 - 生产者只需要连接上任意一个活着的Broker就可以连接上Kafka集群
- 生产者发送消息时可以指定Topic、分区编号、key、value
- 分区编号和key都可以决定消息或者说是记录进入到哪个分区,具体规则如下:
- 没有key,默认轮询方式写入到分区
- 有key,没有分区编号,使用key的hash % 分区数得到分区编号
- 有key,有分区编号,直接使用指定的分区编号
- 也可以使用自定义分区策略,可以参考DefaultPartitioner实现Partitioner接口即可
- 分区的作用:
- 提高读写效率/并行度
- 方便集群扩展,业务扩张,数据增加的时候,可以增加机器,并增加分区数,以提升Kafka处理能力
- 分区的目的是为了提高并行度,数据的安全由副本保证,且副本是以分区来备份的!所以就有了:partition0的leader副本,partition0的follow副本! 注意:只能从leader读写,follow只负责备份
- 消息是局部有序(分区内有序)
生产者发送消息到Kafka的各个分区中,是按照offset的顺序追加的。每个主题的每个分区中offset都是从0开始。 - 消息确认机制
acks=0,意思就是KafkaProducer客户端,只要把消息发送出去,不管那条数据有没有在Partition Leader上落到磁盘,都不管他了,直接就认为这个消息发送成功了
acks=1,只要Partition Leader接收到消息,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。
acks=all/-1,意思就是说Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。
all即所有副本都同步到数据时send方法才返回, 以此来完全判断数据是否发送成功, 理论上来讲数据不会丢失