赞
踩
目录
主题、消息、分区和副本、Leader 副本和Follower 副本、偏移量、日志段、代理、生产者、消费者和消费组、ISR、ZooKeeper
Kafka 将一组消息抽象归纳为一个主题( Topic ),也就是说,一个主题就是对消息的一个分类。生产者将消息发送到特定主题,消费者订阅主题或主题的某些分区进行消费。
消息是Kafka 通信的基本单位,由一个固定长度的消息头和一个可变长度的消息体构成。
Kafka 将一组消息归纳为一个主题,而每个主题又被分成一个或多个分区( Partition ) 。每个分区由一系列有序、不可变的消息组成,是一个有序队列。
每个分区在物理上对应为一个文件夹,分区的命名规则为主题名称后接“-”连接符,之后再接分区编号,分区编号从0 开始,编号最大值为分区的总数减1 。每个分区又有一至多个副本( Replica ),分区的副本分布在集群的不同代理上,以提高可用性。从存储角度上分析,分区的每个副本在逻辑上抽象为一个日志( Log )对象,即分区的副本与日志对象是一一对应的。每个主题对应的分区数可以在Kafka 启动时所加载的配置文件中配置,也可以在创建主题时指定。当然,客户端还可以在主题创建后修改主题的分区数。 分区使得Kafka 在并发处理上变得更加容易,理论上来说,分区数越多吞吐量越高,但这要根据集群实际环境及业务场景而定。同时,分区也是Kafka 保证消息被顺序消费以及对消息进行负载均衡的基础。
Kafka 只能保证一个分区之内消息的有序性,并不能保证跨分区消息的有序性。每条消息被追加到相应的分区中,是顺序写磁盘,因此效率非常高,这是Kafka 高吞吐率的一个重要保证。同时与传统消息系统不同的是, Kafka 并不会立即删除已被消费的消息,由于磁盘的限制消息也不会一直被存储(事实上这也是没有必要的),因此Kafka 提供两种删除老数据的策略,一是基于消息己存储的时间长度, 二是基于分区的大小。
由于Kafka 副本的存在,就需要保证一个分区的多个副本之间数据的一致性, Kafka 会选择该分区的一个副本作为Leader 副本,而该分区其他副本即为Follower 副本,只有Leader 副本才负责处理客户端读/写请求,Follower 副本从Leader 副本同步数据。副本Follower 与Leader 的角色并不是固定不变的,如果Leader 失效,通过相应的选举算法将从其他Follower 副本中选出新的Leader 副本。
任何发布到分区的消息会被直接追加到日志文件(分区目录下以“.log”为文件名后缀的数据文件)的尾部,而每条消息在日志文件中的位置都会对应一个按序递增的偏移量。偏移量是一个分区下严格有序的逻辑值,它并不表示消息在磁盘上的物理位置。由于Kafka 几乎不允许对消息进行随机读写,因此Kafka 并没有提供额外索引机制到存储偏移量,也就是说并不会给偏移量再提供索引。消费者可以通过控制消息偏移量来对消息进行消费,如消费者可以指定消费的起始偏移量。为了保证消息被顺序消费, 消费者已消费的消息对应的偏移量也需要保存。需要说明的是,消费者对消息偏移量的操作并不会影响消息本身的偏移量。旧版消费者将消费偏移量保存到ZooKeeper 当中,而新版消费者是将消费偏移量保存到Kafka 内部一个主题当中。当然,消费者也可以自己在外部系统保存消费偏移量,而无需保存到Kafka 中。
一个日志又被划分为多个日志段( LogSegment ),日志段是Kafka 日志对象分片的最小单位。与日志对象一样,日志段也是一个逻辑概念, 一个日志段对应磁盘上一个具体日志文件和两个索引文件。日志文件以“.log”为文件名后缀的数据文件,用于保存消息实际数据。两个索引文件分别以“.index”和“. timeindex”作为文件名后缀,分别表示消息偏移量索引文件和消息时间戳索引文件。
在Kafka 基本体系结构中我们提到了Kafka 集群。Kafka 集群就是由一个或多个Kafka 实例构成,我们将每一个Kafka 实例称为代理( Broker ),通常也称代理为Kafka 服务器( KafkaServer ) 。在生产环境中Kafka 集群一般包括一台或多台服务器,我们可以在一台服务器上配置一个或多个代理。每一个代理都有唯一的标识id ,这个id 是一个非负整数。在一个Kafka集群中,每增加一个代理就需要为这个代理配置一个与该集群中其他代理不同的id, id 值可以选择任意非负整数即可,只要保证它在整个Kafka 集群中唯一,这个id 就是代理的名字,也就是在启动代理时配置的broker.id 对应的值 。由于给每个代理分配了不同的brokerId ,这样对代理进行迁移就变得更方便,从而对消费者来说是透明的, 不会影响消费者对消息的消费。
生产者( Producer )负责将消息发送给代理,也就是向Kafka 代理发送消息的客户端。
消费者( Comsumer )以拉取( pull )方式拉取数据,它是消费的客户端。在Kafka 中每一个消费者都属于一个特定消费组( ConsumerGroup ),我们可以为每个消费者指定一个消费组,以groupId 代表消费组名称,通过group.id 配置设置。如果不指定消费组,则该消费者属于默认消费组test-consumer-group 。同时,每个消费者也有一个全局唯一的id , 通过配置项client.id指定,如果客户端没有指定消费者的id, Kafka 会自动为该消费者生成一个全局唯一的id ,格式为 ${groupld}-${hostName}-${timestamp}-${UUID前8位字符}。同一个主题的一条消息只能被同一个消费组下某一个消费者消费,但不同消费组的消费者可同时消费该消息。消费组是Kafka用来实现对一个主题消息进行广播和单播的手段,实现消息广播只需指定各消费者均属于不同的消费组,消息单播则只需让各消费者属于同一个消费组。
Kafka 在ZooKeeper 中动态维护了一个ISR(In-sync Replica) ,即保存同步的副本列表, 该列表中保存的是与Leader 副本保持消息同步的所有副本对应的代理节点id 。如果一个Follower副本宕机或是落后太多,则该Follower副本节点将从ISR 列表中移除。
Kafka 利用ZooKeeper 保存相应元数据信息, Kafka 元数据信息包括如代理节点信息、Kafka集群信息、旧版消费者信息及其消费偏移量信息、主题信息、分区状态信息、分区副本分配方案信息、动态配置信息等。Kafka 在启动或运行过程当中会在ZooKeeper 上创建相应节点来保存元数据信息, Kafka 通过监听机制在这些节点注册相应监听器来监听节点元数据的变化,从而由ZooKeeper 负责管理维护Kafka 集群,同时通过ZooKeeper 我们能够很方便地对Kafka 集群进行水平扩展及数据迁移。
消息持久化、高吞吐量、扩展性、多客户端支持、Kafka Streams、安全机制、数据备份、轻量级、消息压缩
Kafka高度依赖于文件系统来存储和缓存消息。说到文件系统,大家普遍认为磁盘读写慢,依赖于文件系统进行存储和缓存消息势必在性能上会大打折扣,其实文件系统存储速度快慢一定程度上也取决于我们对磁盘的用法。据Kafka 官方网站介绍: 6 块7200r/min SATA RAID-5阵列的磁盘线性写的速度为600 MB/s ,而随机写的速度为100KB/s ,线性写的速度约是随机写的6000 多倍。由此看来磁盘的快慢取决于我们是如何去应用磁盘。加之现代的操作系统提供了预读( read-ahead )和延迟写( write-behind )技术,使得磁盘的写速度并不是大家想象的那么慢。鉴于消息系统本身的作用考虑,数据的持久化队列可以建立在简单地对文件进行追加的实现方案上。因为是顺序追加,所以Kafka在设计上是采用时间复杂度O(1)的磁盘结构,它提供了常量时间的性能,即使是存储海量的信息( TB 级)也如此,性能和数据的大小关系也不大,同时Kafka将数据持久化到磁盘上,这样只要磁盘空间足够大数据就可以一直追加,而不会像一般的消息系统在消息被消费后就删除掉, Kafka提供了相关配置让用户自己决定消息要保存多久,这样为消费者提供了更灵活的处理方式,因此Kafka能够在没有性能损失的情况下提供一般消息系统不具备的特性。正是由于Kafka将消息进行持久化,使得Kafka在机器重启后,已存储的消息可继续恢复使用。同时Kafka能够很好地支持在线或离线处理、与其他存储及流处理框架的集成。
问:kafka高吞吐量(速度快)的原因?顺序读写+零拷贝+分区+批量发送+数据压缩
(1)顺序读写:kafka的消息是不断追加到文件中的,这个特性使kafka可以充分利用磁盘的顺序读写性能。顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写。
(2)零拷贝:平时从服务器读取静态文件时,服务器先将文件从复制到内核空间,再复制到用户空间,最后再复制到内核空间并通过网卡发送出去,而零拷贝则是直接从内核到内核再到网卡,省去了用户空间的复制。系统上下文切换减少为2次,可以提升一倍的性能。
(3)分区:kafka中的topic中的内容可以被分为多分partition存在,每个partition又分为多个段segment,所以每次操作都是针对一小部分做操作,很轻便,并且增加并行操作的能力。
(4)批量发送:kafka允许进行批量发送消息,producter发送消息的时候,可以将消息缓存在本地,等到了固定条件发送到kafka。a.等消息条数到固定条数; b.一段时间发送一次
(5)数据压缩:Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩。压缩的好处就是减少传输的数据量,减轻对网络传输的压力。Producer压缩之后,在Consumer需进行解压,虽然增加了CPU的工作,但在对大数据处理上,瓶颈在网络上而不是CPU,所以这个成本很值得
总结:Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。
高吞吐量是Kafka设计的主要目标, Kafka将数据写到磁盘,充分利用磁盘的顺序读写。同时, Kafka在数据写入及数据同步采用了零拷贝( zero-copy )技术,采用sendFile()函数调用,sendFile()函数是在两个文件描述符之间直接传递数据,完全在内核中操作,从而避免了内核缓冲区与用户缓冲区之间数据的拷贝,操作效率极高。Kafka 还支持数据压缩及批量发送,同时Kafka 将每个主题划分为多个分区,这一系列的优化及实现方法使得Kafka 具有很高的吞吐量。经大多数公司对Kafka应用的验证, Kafka支持每秒数百万级别的消息。
Kafka依赖ZooKeeper来对集群进行协调管理,这样使得Kafka 更加容易进行水平扩展,生产者、消费者和代理都为分布式,可配置多个。同时在机器扩展时无需将整个集群停机,集群能够自动感知,重新进行负责均衡及数据复制。
Kafka核心模块用Scala语言开发,但Kafka支持不同语言开发生产者和消费者客户端应用程序。Kafka与当前主流的大数据框架都能很好地集成,如Flume 、Hadoop 、HBase 、Hive 、Spark 、Storm 等。
Kafka在0.10之后版本中引入Kafak Streams 。Kafka Streams 是一个用Java 语言实现的用于流处理的jar文件。
通过SSL 和SASL(Kerberos), SASL/PLA时验证机制支持生产者、消费者与代理连接时的身份认证;支持代理与ZooKeeper连接身份验证;通信时数据加密;客户端读、写权限认证;Kafka支持与外部其他认证授权服务的集成。
Kafka可以为每个主题指定副本数,对数据进行持久化备份,这可以一定程度上防止数据丢失,提高可用性。
Kafka的代理是无状态的,即代理不记录消息是否被消费,消费偏移量的管理交由消费者自己或组协调器来维护。同时集群本身几乎不需要生产者和消费者的状态信息,这就使得Kafka非常轻量级,同时生产者和消费者客户端实现也非常轻量级。
Kafka支持Gzip, Snappy 、LZ4 这3 种压缩方式,通常把多条消息放在一起组成MessageSet,然后再把Message Set 放到一条消息里面去,从而提高压缩比率进而提高吞吐量。
消息系统、应用监控、网站用户行为追踪、流处理、持久性日志
Kafka 作为一款优秀的消息系统,具有高吞吐量、内置的分区、备份冗余分布式等特点,为大规模消息处理提供了一种很好的解决方案。
利用Kafka采集应用程序和服务器健康相关的指标,如CPU占用率、IO 、内存、连接数、TPS 、QPS 等,然后将指标信息进行处理,从而构建一个具有监控仪表盘、曲线图等可视化监控系统。例如,很多公司采用Kafka 与ELK (Elastic Search 、Logstash 和Kibana)整合构建应用服务监控系统。
为了更好地了解用户行为、操作习惯,改善用户体验,进而对产品升级改进,将用户操作轨迹、内容等信息发送到Kafka集群上,通过Hadoop 、Spark 或Strom等进行数据分析处理,生成相应的统计报告,为推荐系统推荐对象建模提供数据源,进而为每个用户进行个性化推荐。
需要将己收集的流数据提供给其他流式计算框架进行处理,用Kafka 收集流数据是一个不错的选择,而且当前版本的Kafka 提供了Kafka Streams 支持对流数据的处理。
Kafka可以为外部系统提供一种持久性日志的分布式系统。日志可以在多个节点间进行备份, Kafka为故障节点数据恢复提供了一种重新同步的机制。同时, Kafka很方便与HDFS和Flume进行整合,这样就方便将Kafka采集的数据持久化到其他外部系统。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。