目录
非同步状态副本OSR(Outof-sync Replicas)
partition中leader replication的选举:
Kafka 为何不采用大多数投票机制(quorum算法)来选举leader 。
Unclean 领导者选举(Unclean Leader Election)
管理 Broker 、Consumer Group、Consumer、Producer
官方文档:
一、简介:
- 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。
高性能
分区的设计
负载均衡:
- kafka将分区均匀地分布在Kafka集群中的每个服务器上,每个服务器在处理数据和请求时,共享这些分区。
分区容错性:
- 每一个分区都会在已配置的服务器上进行备份,当生产者向对应主题传递消息,消息通过负载均衡机制传递到不同的分区以减轻单个服务器实例的压力。
消费组并行消费:
- 一个Consumer Group中可以有多个consumer,多个consumer可以同时消费不同分区的消息,大大的提高了消费者的并行消费能力。注意:但是一个分区中的消息只能被一个Consumer Group中的一个consumer消费。
顺序读写
- kafka将消息追加到日志文件中,利用了磁盘的顺序读写高效的特性,来提高读写效率。
- 磁盘的顺序写大多数情况下比随机写内存还要快。
零拷贝技术
- 零拷贝将文件内容从磁盘(通过DMA引擎)复制到内核缓冲区,而且没有把数据复制到socket缓冲区,只是将数据位置和长度信息的描述符复制到了socket缓存区,然后直接将数据传输到网络接口,最后发送。
- 这样大大减小了拷贝的次数,提高了效率。
-
mmap 和 sendfile总结
- 都是Linux内核提供、实现零拷贝的API;
- sendfile 是将读到内核空间的数据,转到socket buffer,进行网络发送;
- mmap将磁盘文件映射到内存,支持读和写,对内存的操作会反映在磁盘文件上。(RocketMQ 在消费消息时,使用了 mmap)
- kafka中producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入;
- kafka中customer从broker读取数据,采用sendfile,将磁盘文件读到OS内核缓冲区后,直接转到socket buffer进行网络发送(调用linux系统给出的sendfile系统调用来使用零拷贝)。
减少网络传输上的开销
批量发送:
- kafka会先将消息缓存在内存中,当超过一个的大小或者超过一定的时间,那么会将这些消息进行批量发送。
- 在发送消息的时候,kafka不会直接将少量数据发送出去,否则每次发送少量的数据会增加网络传输频率,降低网络传输效率。
端到端压缩:
-
kafka将批量的数据进行压缩后才会发送给broker服务器,数据在broker上还是一压缩的形式存储的,消费者拉取数据时也是直接获取这些压缩后的数据。这样整个传输过程中,数据都是以压缩后的形式来传输的。
基础组件:
kafka节点:broker
- broker是消息的代理,producers往brokers里面的指定topic中写消息,consumers从brokers里面拉取指定topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站。
- 一个kafka节点就是一个broker,多个broker组成一个Kafka集群。
主题:topic
- 逻辑上的概念,代表了一类消息,每个消息都会对应一个topic。
分区:partition
- 物理上的概念,每个topic包含一个或多个partition,partition是用来存储消息的队列,同一个partition中消息是按序存储的。
- parttion上的每条消息都会被分配一个唯一的偏离量(offset),这个偏离量是从0开始递增的整数,我们可以通过<topic,partition,offset>三元组定位到任意一条消息。
- 作用:提高系统的吞吐量。每个单独的parttion都受限于主机的文件大小限制,一个topic可以有多个partition,因此kafka可以处理无限量的数据。
- 高可用:每个partition都是冗余存储的,每个partition都会有一个或多个副本(Replication)。
副本:Replication
- 每个partition都有一个 leader replication(下文直接称为leader)和零或多个 followers replication(下文直接称为follower)。
- 所有的读写操作都由 leader处理。
- 各分区的 leader 均匀的分布在brokers 中。
- replication 和 ZooKeeper 的连接没有断掉则认为replication是存活状态。
同步副本集合ISR(in-sync replicas)
概念:
- 数据与leader保持同步的replication被称为同步状态的副本,所有同步状态的replication组成同步副本集合(a set of in-sync replicas) ,简称ISR。
特点:
- ISR中的节点都是和 leader 保持高度一致的,只有ISR的成员才有资格被选举为 leader,一条消息必须被ISR中所有的副本读取并追加到日志中后,这条消息才能视为提交。
- leader会追踪所有同步状态的replication,如果有replication挂掉了或比leader落后太多,则leader就会把它从ISR中移除。
- ISR发生的变化会在 ZooKeeper 中进行持久化,正因为如此,ISR中的任何一个replication都有资格被选为 leader。
- 只要ISR至少有一个replication存活,那么提交的消息就不会丢失。
非同步状态副本OSR(Outof-sync Replicas)
- 概念:非同步状态的replication组成的集合,简称OSR(Outof-Sync Replicas)。
- 说明:
- 新加入的follower replication会先存放在OSR中。
- leader replication会将超过阈值的follower replication 踢出ISR,然后将其添加到 OSR中。
- AR(Assigned Replicas)
- partition中所有的replication组成的集合称为 AR(Assigned Replicas)。
- AR=ISR+OSR
partition中leader replication的选举:
Kafka 为何不采用大多数投票机制(quorum算法)来选举leader 。
- quorum算法的缺点是:冗余单点故障需要三份数据,冗余两个故障则需要五份的数据,quorum算法的代价是比较高的。故quorum算法常常用于数据量不大的共享集群配置(如 ZooKeeper),而不适用于原始数据的存储。
- 如果kafka采用quorum算法,那么避免单点故障的代价就是系统吞吐量降低到1/3,这对于kafka这种处理海量数据的场景是不切实际的。
Unclean 领导者选举(Unclean Leader Election)
- 当ISR中所有的副本都挂掉时,kafka支持有两种策略:
- 等待一个 ISR 副本重新恢复正常服务,并选择这个副本作为领 leader,因为挂掉的ISR有极大可能拥有全部数据。
- 选择一个正常服务的OSR副本作为leader,这个选举的过程称为 Unclean 领导者选举。
- 开启 Unclean 领导者选举,不至于服务长时间宕机,提升了服务的高可用性,但是可能会造成数据丢失。
- 禁止 Unclean 领导者选举,可以避免消息丢失,保证数据的一致性,但是牺牲了服务的高可用性。
follower同步leader的数据:
同步方式:
- kafka认为ISR中的follower都同步完数据后,就认为消息被commit了,这样的方式很好的均衡了确保数据不丢失以及吞吐率。
- 若所有follower都复制完才认为消息被commit,则严重影响kafka集群的吞吐率。
- 若leader写入log后消息就被认为commit,则当leader挂掉后,会造成数据丢失。
优点:
- follower可以批量的从leader复制数据,而且leader充分利用磁盘顺序读以及send file(zero copy)机制,这样极大的提高复制性能,内部批量写磁盘,大减少了follower与leader的消息量差。
常见配置:
- 两个集群,每个集群n个分区,每个分区两个同步副本(ISR集合大小为2)
producer
概念:消息生产者,向broker发送消息的客户端。
数据发送方式:
- producer 把数据 push 到 broker,然后 consumer 从 broker 中 pull 数据。
特点:可以大批量生产要发送给 consumer 的数据。
consumer
接收数据方式:
-
kafka consumer采用拉模式(pull-based)消费消息,consumer通过向 broker 发出一个“fetch”请求来获取它想要消费的 partition。
拉模式的优点:
-
consumer 可自主控制消费消息的速率,同时 Consumer 可以自己控制消费方式——即可批量消费也可逐条消费。
-
支持消息回溯:consumer请求时会指定partition对应的offset,并接收从该位置开始的一大块数据。通过这样的方式,consumer可以在需要的时候通过回退到该位置再次消费对应的数据。
推模式(push-based)消费的缺点:
- 推模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。
- 推模式的目标是尽可能以最快速度传递消息,但是这样很容易造成 Consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。
consumer group
概念:
-
每个consumer属于一个特定的consumer group,一条消息可以发送到多个不同的consumer group,但是同一个consumer group中只能有一个consumer能够消费该消息。
说明:
- kafka默认一个partition在同一个group内只能被一个consumer消费,将partition调整为1可以保证topic中所有的消息有序。
- consumer group中consumer的数量通常不超过partition的数量。
配置
Producer配置
acks:
概念:
- 此配置是 Producer 在确认一个请求发送完成之前需要收到的反馈信息的数量,这个配置是为了保证发送请求的可靠性。
取值:
acks=0:
producer 不会等待服务器的反馈。该消息会被立刻添加到 socket buffer 中并认为已经发送完成。在这种情况下,服务器是否收到请求是没法保证的,并且参数retries
也不会生效(因为客户端无法获得失败信息)。每个记录返回的 offset 总是被设置为-1。acks=1:
leader节点会将记录写入本地日志,并且在所有 follower 节点反馈之前就先确认成功。在这种情况下,如果 leader 节点在接收记录之后,并且在 follower 节点复制数据完成之前产生错误,则这条记录会丢失。acks=all 或
acks=-1:
leader节点会等待所有同步状态的副本确认之后再确认这条记录是否发送完成。只要至少有一个同步副本存在,记录就不会丢失。这种方式是对请求传递的最有效保证。。
batch.size
概念:
- 将多个记录被发送到同一个分区时, producer会将多个记录组合到一个请求中发送。批量发送的方式有助于提高生产者和消费者的性能。
- batch.size 控制一个批次的默认大小,单位是字节。
取值:
- 当记录的大小超过了配置的字节数, producer 将不再尝试往批次增加记录。
- batch.size如果设置的太小,可能会降低吞吐量(batch.size=0 表示禁用批处理)。
- batch.size如果设置的太大,可能造成内存浪费。
Broker配置
-
num.replica.fetchers:从源broker复制消息的拉取器的线程数。增加这个值可以增加follow broker的I/O并行度。
-
unclean.leader.election.enable:控制是否允许 Unclean 领导者选举。
优化
producer如何优化打入速度
- 增加更多 producer 实例、增加分区(partition)数量。
- 适当调大 batch.size
- 跨数据中心的传输:增加 socket 缓冲区设置以及 OS tcp 缓冲区设置。
consumer如何优化消费速度
- 并行消费:consumer收到消息后,将消费逻辑放到线程池中并行执行。
Kafka中的ZooKeeper
管理 Broker 、Consumer Group、Consumer、Producer
-
记录Broker
-
路径为
/brokers,
Kafka 会将该 Broker 相关的信息存入其中,包括broker.name
、端口号。
-
-
记录topic:
-
路径为/brokers/topics/{topic_name} 。
-
-
记录Consumer Group
-
Consumer Group 注册路径为
/consumers/{group_id},该节点是一个目录
-
-
记录Consumer
-
路径
/consumers/{group_id}/ids/{c
onsumer_id}
-
-
记录消费进度 Offset
-
路径:/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]
-
说明:节点内容就是Offset的值。
-
在 Kafka 的最新版本 Kafka 2.0 中,Offset 信息不再记录于 ZooKeeper,而是保存于 Kafka 的 Topic 中,路径如下:__consumer_offsets(/brokers/topics/__consumer_offsets)
-
-
记录 Partition 与 Consumer 的关系:
-
同一个 Group 订阅的 Topic 下的任一 Partition 都只能分配给一个 Consumer。
-
路径:/consumers/[group_id]/owners/[topic]/[broker_id-partition_id] 该节点为临时节点。
-
-
Producers 启动后同样也要进行注册(依然是创建一个专属的临时节点)
思考
为什么Kafka不支持读写分离?
- 在Kafka集群中,如果存在多个副本,经过合理的配置,可以让leader副本均匀的分布在各个broker上面,使每个 broker 上的读写负载都是一样的,故也就没有必要支持读写分离了。
- 另一方面:读写分离还会带来主从延迟的问题,这样就更加没有理由要支持读写分离了。