KAFKA:百万级吞吐量原理

转自:https://blog.csdn.net/dshf_1/article/details/81044990

kafka初衷 企业统一,高通量,低延迟。

Kafka 是一种高吞吐量的分布式发布订阅消息系统,有如下特性:

  • 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。
  • 高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万 [2] 的消息。
  • 支持通过Kafka服务器和消费机集群来分区消息。
  • 支持Hadoop并行数据加载

这篇写得也很好 
http://rdcqii.hundsun.com/portal/article/709.html

1.1. Kafka中topic的Partition

 在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。 
 每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。但每个段segment file消息数量不一定相等,这种特性方便old segment file快速被删除。默认保留7天的数据。 
这里写图片描述 
 每个partiton只需要支持顺序读写就行了,segment文件生命周期由服务端配置参数决定。(什么时候创建,什么时候删除) 
这里写图片描述 
数据有序的讨论? 
一个partition的数据是否是有序的? 间隔性有序,不连续 
针对一个topic里面的数据,只能做到partition内部有序,不能做到全局有序。 
特别加入消费者的场景后,如何保证消费者消费的数据全局有序的?伪命题。

只有一种情况下才能保证全局有序?就是只有一个partition。

其它: 
这里写图片描述

2.Kafka为什么这么快

2.1. 首先简单介绍一下Kafka的架构和涉及到的名词:

  1. Topic:用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上。
  2. Partition:是Kafka中横向扩展和一切并行化的基础,每个Topic都至少被切分为1个Partition。
  3. Offset:消息在Partition中的编号,编号顺序不跨Partition。
  4. Consumer:用于从Broker中取出/消费Message。
  5. Producer:用于往Broker中发送/生产Message。
  6. Replication:Kafka支持以Partition为单位对Message进行冗余备份,每个Partition都可以配置至少1个Replication(当仅1个Replication时即仅该Partition本身)。
  7. Leader:每个Replication集合中的Partition都会选出一个唯一的Leader,所有的读写请求都由Leader处理。其他Replicas从Leader处把数据更新同步到本地,过程类似大家熟悉的MySQL中的Binlog同步。
  8. Broker:Kafka中使用Broker来接受Producer和Consumer的请求,并把Message持久化到本地磁盘。每个Cluster当中会选举出一个Broker来担任Controller,负责处理Partition的Leader选举,协调Partition迁移等工作。
  9. ISR(In-Sync Replica):是Replicas的一个子集,表示目前Alive且与Leader能够“Catch-up”的Replicas集合。由于读写都是首先落到Leader上,所以一般来说通过同步机制从Leader上拉取数据的Replica都会和Leader有一些延迟(包括了延迟时间和延迟条数两个维度),任意一个超过阈值都会把该Replica踢出ISR。每个Partition都有它自己独立的ISR。 

生产快 
producer ——> broker 
分布式broker

存储快 
broker ——>disk 
简单说就是通过buffer控制数据的发送,有时间阀值与消息数量阀值来控制

不同于 Redis 和 MemcacheQ 等内存消息队列,Kafka 的设计是把所有的 Message 都要写入速度低、容量大的硬盘,以此来换取更强的存储能力。实际上,Kafka 使用硬盘并没有带来过多的性能损失,“规规矩矩”的抄了一条“近道”。 
首先,说“规规矩矩”是因为 Kafka 在磁盘上只做 Sequence I/O (顺序写),由于消息系统读写的特殊性,这并不存在什么问题。关于磁盘 I/O 的性能,引用一组 Kafka 官方给出的测试数据(Raid-5,7200rpm):

Sequence I/O: 600MB/s (实验室)
Sequence I/O: 400MB-500MB/s (工作场景)
Random I/O: 100KB/s

所以通过只做 Sequence I/O 的限制,规避了磁盘访问速度低下对性能可能造成的影响。

接下来我们再聊一聊 Kafka 是如何“抄近道的”。 
首先,Kafka 重度依赖底层操作系统提供的 PageCache 功能。当上层有写操作时,操作系统只是将数据写入 PageCache,同时标记 Page 属性为 Dirty。当读操作发生时,先从 PageCache 中查找,如果发生缺页才进行磁盘调度,最终返回需要的数据。 
实际上 PageCache 是把尽可能多的空闲内存都当做了磁盘缓存来使用。同时如果有其他进程申请内存,回收 PageCache 的代价又很小,所以现代的 OS 都支持 PageCache。使用 PageCache 功能同时可以避免在 JVM 内部缓存数据,JVM 为我们提供了强大的 GC 能力,同时也引入了一些问题不适用与 Kafka 的设计。 
如果在 Heap 内管理缓存,JVM 的 GC 线程会频繁扫描 Heap 空间,带来不必要的开销。如果 Heap过大,执行一次 Full GC 对系统的可用性来说将是极大的挑战。 
所有在在 JVM 内的对象都不免带有一个 Object Overhead(千万不可小视),内存的有效空间利用率会因此降低。 
所有的 In-Process Cache 在 OS 中都有一份同样的 PageCache。所以通过将缓存只放在 PageCache,可以至少让可用缓存空间翻倍。 
如果 Kafka 重启,所有的 In-Process Cache 都会失效,而 OS 管理的 PageCache 依然可以继续使用。

读取快 
消费者获取数据快 
PageCache 还只是第一步,Kafka 为了进一步的优化性能还采用了 Sendfile 技术。在解释 Sendfile 之前,首先介绍一下传统的网络 I/O 操作流程,大体上分为以下 4 步。

  1. OS 从硬盘把数据读到内核区的 PageCache。
  2. 用户进程把数据从内核区 Copy 到用户区。
  3. 然后用户进程再把数据写入到 Socket,数据流入内核区的 Socket Buffer 上。
  4. OS 再把数据从 Buffer 中 Copy 到网卡的 Buffer 上,这样完成一次发送。


这里写图片描述 
整个过程共经历两次Context Switch,四次System Call。同一份数据在内核Buffer与用户Buffer之间重复拷贝,效率低下。其中2、3两步没有必要,完全可以直接在内核区完成数据拷贝。这也正是Sendfile所解决的问题,经过Sendfile优化后,整个I/O过程就变成了下面这个样子。 
这里写图片描述 
通过以上的介绍不难看出,Kafka的设计初衷是尽一切努力在内存中完成数据交换,无论是对外作为一整个消息系统,或是内部同底层操作系统的交互。如果Producer和Consumer之间生产和 
费进度上配合得当,完全可以实现数据交换零I/O。

3.Consumer的负载均衡

当一个group中,有consumer加入或者离开时,会触发partitions均衡.均衡的最终目的,是提升topic的并发消费能力,步骤如下: 
1、 假如topic1,具有如下partitions: P0,P1,P2,P3 
2、 加入group中,有如下consumer: C1,C2 
3、 首先根据partition索引号对partitions排序: P0,P1,P2,P3 
4、 根据consumer.id排序: C0,C1 
5、 计算倍数: M = [P0,P1,P2,P3].size / [C0,C1].size,本例值M=2(向上取整) 
6、 然后依次分配partitions: C0 = [P0,P1],C1=[P2,P3],即Ci = [P(i * M),P((i + 1) * M -1)] 
这里写图片描述

猜你喜欢

转载自blog.csdn.net/bluehawksky/article/details/84796678