赞
踩
Kafka是一个分布式、多分区、基于发布/订阅模式的消息队列(Message Queue),具有可扩展和高吞吐率的特点。
kafka中大致包含以下部分:
评价一个服务的好坏可以通过看它能否满足高可用、高性能、高并发。
高性能(High Performance)指的是程序处理速度快、耗能少。与性能相关的一些指标如下:
高并发和高性能是紧密相关的,提高应用的性能,可以提高系统的并发能力。应用性能优化时,对于计算密集型和 I/O 密集型还是有很大差别,需要分开来考虑。
高可用性(High Availability)主要目的是为了保障「业务的连续性」,即在用户眼里,业务基本是正常对外提供服务的。
kafka中的选举大致分为2类:控制器的选举、Leader的选举。
在Kafka集群中有多个broker,那么就有一个broker会被选举为控制器,这个控制器的主要责任包括监听Broker的变化、监听Topic变化、监听Partition变化、获取和管理Broker、Topic、Partition的信息、管理Partition的主从信息。同时还会负责副本的选举,当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。再比如当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。
前面我们有提起过Zookeeper,控制器的选举是由Zookeeper(协调框架)的节点的唯一性来做到的。控制器的选举过程如下:
Kafka是一个多分区,多副本的消息服务,那么每个分区的多副本由一个leader与多个follower构成。而leader负责进行数据读写,并且管理着整个follower中存储的数据状态。若某一时刻该分区leader挂掉了,Broker控制器就会对该分区进行重新选举案leader副本,其中leader的诞生只能从ISR列表中产生。
具体的选举规则:Kafka会在Zookeeper上针对每个Topic维护一个称为ISR副本的的集合,一旦Leader分区丢掉,从中随机挑选一个副本做新的Leader分区。如果ISR中的副本都宕机了,则:
在Kafka中,一个主题被划分为若干个分区,一个分区包含一个或多个副本,副本对应着消息存储的日志文件。副本机制就是通过对分区数据的冗余处理,即在不同的broker节点中存储多个副本,来实现Kafka的故障转移,从而提升可靠性。kafka的每个分区都有一个ISR列表,用于维护所有同步的、可用的副本。其中,Leader副本必是同步副本,而对于Follower副本来说,需要满足以下条件才能被认为是同步副本:
如果副本不满足上面条件的话,就会从ISR列表中移除,直到满足条件才会被再次加入。replica.lag.time.max.ms 这个参数值表示Follower副本能够落后Leader副本的最长时间间隔,当前默认值为10s,即只要一个Follower副本落后Leader副本的时间不连续超过10s, kafka就认为两者是同步的。
Kafka的Producer有三种ack机制,参数值有0、1 和 -1
Kafka SocketServer 是基于Java NIO 开发的,采用了 Reactor 的模式,包含三种角色:Acceptor;Processor;Handler。Kafka Reactor包含一个Acceptor负责接收客户端请求,N个Processor线程负责读写数据(即即为每个 Connection 创建出一个 Processor 去单独处理,每个Processor中均引用独立的Selector),M个Handler来处理业务逻辑。在Acceptor和Processor,Processor和Handler之间都有队列来缓冲请求。
操作系统本身有一层缓存叫做页缓存(Page Cache),是操作系统自己管理的内存缓存。页缓存是位于内存和文件之间的缓冲区,它实际上也是一块内存区域,所有的文件IO(包括网络文件)都是直接和页缓存交互,操作系统通过一系列的数据结构,比如inode, address_space, struct page,实现将一个文件映射到页的级别,这些具体数据结构及之间的关系我们暂且不讨论,只需知道页缓存的存在以及它在文件IO中扮演着重要角色,很大一部分程度上,文件读写的优化就是对页缓存使用的优化。
Kafka 在写入磁盘文件的时候,可以直接写入到页缓存里,由操作系统负责将页缓存里的数据刷入到磁盘文件中,这样消息写入就变成了写内存而不是写磁盘,大大提高了kafka写的性能。
在消费的时候kafka从磁盘文件上读取数据然后发送给下游的消费者,其数据流转为:
磁盘 -> os cache -> 应用进程缓存 -> socket缓存 -> 网卡 -> 消费者
可以看出来,从os cache 拷贝数据到应用进程缓存, 接着从应用进程缓存拷贝到操作系统的socket缓存这两步是没必要的,期间发生了好几次上下文切换,比较消耗性能。kafka为了解决这个问题,在读取数据的时候引入了零拷贝技术,即让操作系统的 os cache 中的数据直接发送到网卡后传出给下游的消费者,中间跳过了两次拷贝数据的步骤,减少了上下文的切换。其中,Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存。
kafka主要使用到了mmap和sendfile的方式实现了零拷贝。
压缩有助于提高吞吐量,降低延迟并提高磁盘利用率。在 Kafka 中, 压缩可能会发生在两个地方: 生产者端和Broker端, 一句话总结下压缩和解压缩, 即 Producer 端压缩, Broker 端保持, Consumer 端解压缩。
Producer、Broker、Consumer 要使用相同的压缩算法, 在 Producer 向 Broker 写入数据, Consumer 向 Broker 读取数据的时候可以不用解压缩, 只需要在最终 Consumer 到消息的时候才进行解压缩, 这样可以节省大量的网络和磁盘开销。
kafka写入数据的时候,会将数据追加到文件的末尾,而不是在文件的随机位置。追加到文件末尾的写法可以大大提升数据写入磁盘的速度。
kafka在0.8版本之后, 进行了简单的改进, 性能得到了指数级上升,即来了一条消息后不会立马发送出去, 而是先写入到一个缓存(RecordAccumulator)队列中,封装成一个个批次(RecordBatch)。这个时候会有一个sender线程会将多个批次封装成一个请求(Request), 然后进行发送, 这样会减少很多请求,提高吞吐量。
Kafka是一个分布式的消息队列系统,它通过内存池(Memory Pool)来管理内存,提高内存的利用率和系统的性能。Kafka的内存池设计如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。