Kafka 原理简介
Kafka 是一种高吞吐的分布式发布订阅的消息系统,可以处理消费者规模较大的网站流数据,具有高性能的,持久化,多副本,横向扩展能力。
Kafka 的组成结构
Kafka 的基础架构图:
- Producer Producer 生产者,消息的生产者。
kafka cluster
- Broker : Broker 是 kafka 的实例,每个服务器有一个或者多个 Kafka实例。Kafka 集群内的 broker 有不重复的编号。
- Topic: 消息主题,可以理解为消息的分类,Kafka 的数据保存在 topic 中,有点类似队列,每个broker 可以创建多个 topic 。
- Partition: Topic 的分区,每个topic 可以有多个分区。分区的作用是负载,提高 kafka 的吞吐量。同一个 Topic 在不同分区上的的数据是不重复的,partion 的表现形式是一个个文件夹。
- Replication:每个分区有多个副本,当主分区(Leader)出现故障是,会选择一个副本(Follower)上位。成为新Leader 。Kafka 默认副本数为10 个,副本数量不能大于 Broker 的数量,follower 和leader 在不同机器。
- Message 消息主体
- Consumer 消息消费者
- Consumer Group ,可以将多个消费者组成一个消费者组,同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个 topic 的不同分区的数据。提高 Kafka 的吞吐量。
- zookeeper kafka 集群依赖 zookeeper 保存集群信息,保证系统的可用性。
工作流程
生产者发送数据
producer 是生产者,也是数据的入口,Producer 在写入数据时,写入leader , 不会将数据写入 follower。
producer 是采用 push 模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内数据是有序的。
- 一个topic可以有有多个partion ,可以提高系统的扩展性。
- 消费者以partion 读写单位,可以多个消费者同时消费数据,提高消息处理速率。
Partion 结构
Partion 文件夹下有很多组 segment 文件,每组 segement 文件包含 .index 、.log 文件、.timeindex 文件,这三个文件。
- log 文件是实际存储 message 的地方
- index 和 timeindex 文件为所有文件,用于检索消息。
每个partion 有多个 segement ,每个 segment 以 最小offset 来命名,如000.index存储offset为0~368795的消息,kafka就是利用分段+索引的方式来解决查找效率的问题。
发送过程如何保证消息不丢失?
producer 向 kafka 发送消息时,要集群保证消息不丢失,其实是通过 ACK 机制, 当生产者写入数据,可以通过设置参数来确定 Kafka 是否接收到数据。
- 0 代表 producer 往集群发送数据,不需要等待集群返回,不确保消息发送成功。安全性低,效率高。
- 1 代表 producer 往集群发送数据,只需要leader 应答即可,只确保了leader 接收到了消息数据。
- all 代表 producer 往集群发送数据,需要所有的 follower 与leader 完成数据同步,生产者 producer 才会发送下一条消息。安全性最高,效率最低。
Message 结构
Message 是存储在log 里面的,Message 结构主要分成几个部分,消息体,消息大小,offset、压缩类型等。
- offset: offset 是一个有序 id ,可以为其确定每条消息在 partion 内的位置,占 8Byte
- 消息大小,描述消息的大小,占4byte
- 消息体,消息存放的实际消息数据
保留策略
Redis 有个缓存淘汰策略,Kafka 有个存储策略, 无论消息是否被消费,Kafka 都会保存所有的消息,这个和Rabbitmq不一样, kafka 是删除旧消息策略:
- 基于时间策略,默认配置 168小时(7天)
- 基于大小策略,当topic 所占日志大小大于一个阀值时,则可以开始删除最旧的消息了。
清理超过指定时间清理: log.retention.hours=16 超过指定大小后,删除旧的消息: log.retention.bytes=1073741824
消费者消费消息
消息存储在 Log 中,消费者可以进行消费了,消费者是从 Leader 中去拉取消息的。kafka 不决定何时,如何消费消息,而是通过 Consumer 决定何时,如何消费消息。
多个消费者可以组成一个消费组,每个消费组有一个组 id, 同一个消费组者的消费者可以消费同一个 topic 下不同分区的数据,但是不会组内多个消费者消费同一个分区的数据。一个分区只能被一个消费者消费。一个消费者可以消费多个分区。
怎么根据 segment + offset 查找到对应消息呢?
- 先找到offset的368801message所在的segment文件(利用二分法查找),这里找到的就是在第二个segment文件。
- 打开找到的segment中的.index文件(也就是368796.index文件,该文件起始偏移量为368796+1,我们要查找的offset为368801的message在该index内的偏移量为368796+5=368801,所以这里要查找的相对offset为5)。由于该文件采用的是稀疏索引的方式存储着相对offset及对应message物理偏移量的关系,所以直接找相对offset为5的索引找不到,这里同样利用二分法查找相对offset小于或者等于指定的相对offset的索引条目中最大的那个相对offset,所以找到的是相对offset为4的这个索引。
- 根据找到的相对offset为4的索引确定message存储的物理偏移位置为256。打开数据文件,从位置为256的那个地方开始顺序扫描直到找到offset为368801的那条Message。