高性能
-
消息的顺序性、顺序写磁盘
-
零拷贝
-
RocketMQ内部主要是使用基于mmap实现的零拷贝,用来读写文件
-
减少cpu的拷贝次数和上下文切换次数,实现文件的高效读写操作
-
- Kafka
零拷贝
- Kafka 使用到了 mmap 和 sendfile 的方式来实现零拷贝。分别对应 Java 的 MappedByteBuffer 和 FileChannel.transferTo
顺序写磁盘
- Kafka 采用顺序写文件的方式来提高磁盘写入性能。顺序写文件,基本减少了磁盘寻道和旋转的次数
- 完成一次磁盘 IO,需要经过寻道、旋转和数据传输三个步骤,如果在写磁盘的时候省去寻道、旋转可以极大地提高磁盘读写的性能。
- Kafka 中每个分区是一个有序的,不可变的消息序列,新的消息不断追加到 Partition 的末尾,在 Kafka 中 Partition 只是一个逻辑概念,Kafka 将 Partition 划分为多个 Segment,每个 Segment 对应一个物理文件,Kafka 对 segment 文件追加写,这就是顺序写文件
页缓存技术
- 应当使用本地磁盘作为存储介质。Page Cache 的存在就可以提升消息的读取速度,
批量传输与压缩消息
- 生产端有两个重要的参数:batch.size和linger.ms。这两个参数就和 Producer 的批量发送消息有关。
网络模型
- Kafka 自己实现了网络模型做 RPC。底层基于 Java NIO,采用和 Netty 一样的 Reactor 线程模型。
- Kafka 即基于 Reactor 模型实现了多路复用和处理线程池。
- Reactor 模型基于池化思想,避免为每个连接创建线程,连接完成后将业务处理交给线程池处理;基于 IO 复用模型,多个连接共用同一个阻塞对象,不用等待所有的连接。遍历到有新数据可以处理时,操作系统会通知程序,线程跳出阻塞状态,进行业务逻辑处理
分区并发
- Kafka 的 Topic 可以分成多个 Partition,每个 Paritition 类似于一个队列,保证数据有序。同一个 Group 下的不同 Consumer 并发消费 Paritition,分区实际上是调优 Kafka 并行度的最小单元,因此,可以说,每增加一个 Paritition 就增加了一个消费并发。
高效的文件数据结构
- 每个 Topic 又可以分为一个或多个分区。每个分区各自存在一个记录消息数据的日志文件。Kafka 每个分区日志在物理上实际按大小被分成多个 Segment。
- segment file 组成:由 2 大部分组成,分别为 index file 和 data file,此 2 个文件一一对应,成对出现,
- index 采用稀疏索引,这样每个 index 文件大小有限,Kafka 采用mmap的方式,直接将 index 文件映射到内存,这样对 index 的操作就不需要操作磁盘 IO
- 分段和索引的策略:利用偏移量和时间索引文件实现快速消息查找
高可用
-
Kafka
- Kafka 从 0.8 版本开始提供了高可用机制,可保障一个或多个 Broker 宕机后,其他 Broker 能继续提供服务
分区副本、备份机制
同一个 Partition 存在多个消息副本,每个 Partition 的副本通常由 1 个 Leader 及 0 个以上的 Follower 组成,
- Kafka 会尽量将所有的 Partition 以及各 Partition 的副本均匀地分配到整个集群的各个 Broker 上
- 多副本机制
- 分区(Partition)引入了多副本(Replica)机制。
- 多分区、多副本机制好处呢?
- 1. Kafka 通过给特定 Topic 指定多个 Partition分区, 而各个 Partition 可以分布在不同的 Broker 上, 这样便能提供比较好的并发能力(负载均衡)。
- 2. Partition 可以指定对应的 Replica 数, 这也极大地提高了消息存储的安全性, 提高了容灾能力,不过也相应的增加了所需要的存储空间。
ACK 机制
-
-
-
- 生产者发送消息中包含 acks 字段,该字段代表 Leader 应答生产者前 Leader 收到的应答数
- 「acks=0」
- 生产者无需等待服务端的任何确认,因此 acks=0 不能保证服务端已收到消息
- 「acks=1」默认值
- 只要 Partition Leader 接收到消息而且写入本地磁盘了,就认为成功了,不管其他的 Follower 有没有同步
- 「acks=all or -1」
- 服务端会等所有的 follower 的副本受到数据后才会收到 leader 发出的 ack,这样数据不会丢失
- Broker 有个配置项min.insync.replicas(默认值为 1)代表了正常写入生产者数据所需要的最少 ISR 个数
- 发送的 acks=1 和 0 消息会出现丢失情况,为了不丢失消息可配置生产者acks=all & min.insync.replicas >= 2
-
-
ISR 机制
-
-
-
- ISR 中的副本都是与 Leader 同步的副本,不在 ISR 中的Follower副本就被认为是没有资格的
- Follower 周期性地向 Leader 发送 FetchRequest 请求,发送时间间隔配置在replica.fetch.wait.max.ms中,默认值为 500
- 每个分区的 Leader 负责维护 ISR 列表并将 ISR 的变更同步至 ZooKeeper,被移出 ISR 的 Follower 会继续向 Leader 发 FetchRequest 请求,试图再次跟上 Leader 重新进入 ISR
- ISR 中所有副本都跟上了 Leader,通常只有 ISR 里的成员才可能被选为 Leader
-
-
主从同步
-
-
-
- 1、Follower副本通过发送Fetch请求来同步Leader副本上的数据。
- LEO(Log End Offset)
- 对于Leader副本和每个Follower副本来说,它们都有各自的LEO
- LEO是下一个要写入的消息的偏移量
- HW(High Watermark)
- HW是分区中所有副本的已提交消息的最大偏移量。是分区中所有ISR(In-Sync Replicas)副本的LEO中的最小值
- 只要分区的Leader副本和至少一个Follower副本保持同步,消费者就能看到所有已提交的消息,即使Leader副本发生故障
- 确保了Kafka在分区的Leader副本发生故障时,可以从ISR中选举出一个Follower副本作为新的Leader,
- Unclean 领导者选举
- 当 Kafka 中unclean.leader.election.enable配置为 true(默认值为 false)且 ISR 中所有副本均宕机的情况下,
- 开启 Unclean 领导者选举可能会造成数据丢失,但好处是,它使得分区 Leader 副本一直存在,不至于停止对外提供服务,因此提升了高可用性,
-
-
Leader 选举 & 故障恢复机制
-
-
-
- 「Kafka 从 0.8 版本开始引入了一套 Leader 选举及失败恢复机制」
- 在集群所有 Broker 中选出一个 Controller,负责各 Partition 的 Leader 选举以及 Replica 的重新分配
- Controller
- 集群中的 Controller 也会出现故障,因此 Kafka 让所有 Broker 都在 ZooKeeper 的 Controller 节点上注册一个 Watcher。
- 当出现 Leader 故障后,Controller 会将 Leader/Follower 的变动通知到需要为此作出响应的 Broker。
- Kafka 使用 ZooKeeper 存储 Broker、Topic 等状态数据,Kafka 集群中的 Controller 和 Broker 会在 ZooKeeper 指定节点上注册 Watcher(事件监听器),以便在特定事件触发时,由 ZooKeeper 将事件通知到对应 Broker
- 当 Broker 发生故障后,由 Controller 负责选举受影响 Partition 的新 Leader 并通知到相关 Broker
-
-