赞
踩
Kafka是一个开源的分布式流式处理平台,在这个平台上可以发布、订阅以及处理数据流,具有强大的吞吐能力,让Kafka成为了一个高性能的发布与订阅消息系统
Broker
部署Kafka进程的服务被称之为Broker,Broker会接收Producer的消息,持久化到本地,然后Comsumer通Pull的形式进行消息拉取,通常使用集群的形式进行部署
Producer
生产者,即发送消息的一方,往Broker中写入数据
Consumer
消费者,即消费消息的一方,从Broker中获取数据,一般采用群组的形式部署来提高消费性能
Topic
Topic翻译过来就是主题的意思,但它其实是个抽象概念,我们可以理解成数据集合,比如订单系统有一个Topic叫topic_order_info,这个Topic里面就是订单系统投递的订单信息,如果其他系统想要获取订单信息,就可以从这个Topic中获取。
Partition
Partion即分区,在Kafka中,创建topic通常会指定topic的partition个数,kafka会根据一定的策略进行分区分配,将分区分布在不同Broker上,Producer在发送消息时会根据分区选择器选择一个分区进行发送,这样就可以实现负载均衡,提高吞吐的效果
上图是一个常见的Kafka部署架构,Kafka使用 Zookeeper保存Broker集群的元数据信息,主要包括Broker和Topic的元数据信息,老版的Kafka的消费者信息也是使用Zookeeper进行存储,新版则使用Broker存储消费者信息。下面对架构特点进行分析
我们知道在创建Topic时,通过会指定分区的个数(num.patitions),kafka会根据一定的策略将分区分配在不同broker上来保证高吞吐,同时每个分区又可以根据复制系数(replicatlon.factor)分配多个副本到不同broker上,保证消息的可靠性。副本类型分为首领副本和跟随者副本,除了首领副本,其余都叫跟随者副本,首领副本会和跟随者副本之间进行数据同步。首领副本负责消息的写入和读取,首领副本所在的broker宕机之后,控制器会选择一个跟随者副本成为新的首领副本。控制器其实就是一个 broker,只不过它除了具有一般 broker 的功能之外,还负责分区首领的选举。
如何均匀进行分区分配?假设你有 6个 broker,打算创建一个包含 10个分区的主题,并且复制系数为 3。那么 Kafka就会有 30个分区副本, 它们可以被分配给 6个 broker。在进行分区分配时,我们从分区首领开始,依次分配跟随者副本。如果分区0的首领在broker4上,那么它的第一个跟随者副本会在 broker 5 上,第二个跟随者副本会在 broker 0上。分区1的首领在broker5上,那么它的第一个跟随者副本在 broker0上,第二个跟随者副本在 broker1上。
生产者在发送消息时,是如何知道发送到哪个分区的呢?这时候生产者就需要获取到topic的元数据,topic有哪些分区,分区首领在哪几台broker上,broker的ip.port等,生产者可以请求任一broker获取这些元数据信息,因为所有 broker都缓存了这些信息。
从上图中可以了解到生产者在消息的发送过程,会经历消息的序列化,分区器会从多个分区中选择一个分区进行消息发送,对于同一个topic的同一个分区的消息,会在缓冲区经历批次等待过程,最后通过压缩处理对消息进行批量发送。
消息在发送的过程一般会发生两类错误。其中一类是可重试错误 ,这类错误可以通过重发消息来解决,比如对于连接错误,可以通过再次建立连接来解决,“无主(noleader)” 错误则可 以通过重新为分区选举首领来解决。 KafkaProduce可以被配置成自动重试,如果在多次重试后仍无能解决问题,应用程序会收到一个重试异常。另一类错误无出通过重试解决 ,比如 序列化消息失败、缓存区已满,对于这类错误, KafkaProduce不会进行任何重试,直接抛出异常。
Broker针对每个分区会创建一个分区目录,分区目录下面存放的是日志文件(.log)和索引文件(.index),如下图所示:
日志文件存储了消息的具体内容,索引文件存储了消息的偏移量(offset),其中每个日志文件大小是可以配置的,根据log.segment.bytes参数进行配置,默认就是1G。这些日志文件和索引文件会不断被清理,依赖于topic的保留时长(log.retention.ms)和保留字节大小(log.retention.bytes)决定。
在Kafka中,消费者一般是以群组(Consumer Group)的方式进行消息消费,且一个分区只会分配给一个Consumer,这是因为消费者每次读取消息的时候,会把最后一个消息的offset保存到一个Topic,下次读取会根据上次保存的offset进行消息读取,如果多个消费读取同一个队列,就会导致偏移量保存被覆盖,进而导致消息被重复消费。
除了通过部署方式(分区分配+分区副本)对于可靠性和高性能的实现,Kafka在其他层面上也做了很多的努力,如下:
1.批量+压缩:
kafka的生产者在消息发送的时候,可以根据分批大小和分批等待时间,对消息进行批量发送,同时会使用相应的压缩算法(snappy、gzip)对消息进行压缩
2.顺序读写:
kafka中对于每个分区的消息都是顺序写入和顺序读取的,这样可以提高磁盘的读写速度
3.零拷贝技术:
kafka默认使用sendfile技术来实现消息的读取和写入,sendfile相对于mmap不仅可以减少拷贝次数,还可以减少上下文切换的次数。
4.索引文件:
kafka的文件存储形式包含了日志文件和索引文件,索引文件可以有效提高消息的读取速度
1.acks参互:
acks参数指定了必须要有多少个分区副本收到消息,生产者才会认为消息写入是成功的。这个参数对消息丢失的可能性有重要影响。
1)ack=0,生产者在成功写入悄息之前不会等待任何来自服务器的响应。
2)ack=1,只要集群的首领副本收到消息,生产者就会收到一个来自服务器的成功响应。
3)ack=all,只有当所有同步副本全部收到消息时,生产者才会收到一个来自 服务器的成功响应。
2.不完全首领选举:
不完全首领选择是指是否允许不同步副本选举称为首领副本,10s内没有请求首领副本最新消息的跟随者副本被称之为不同步副本。如果我们允许不同步的副本成为首领,那么就要承担丢失数据和出现数据不一致的风险。 如果不允许它们成为首领,那么就要接受较低的可用性,因为我们必须等待原先的首领恢复到可用状态 。通过unclean.leade.election.enable参数设置不完全首领选举是否开启
3.最小同步副本:
如果ack=all,且首领副本仅有一个同步副本,在发送消息时,同步副本不可用,数据就会丢失,如果要确保已提交的数据被写入不止一个副本,就需要把最少同步副本数量设置为大一点的值。对于一个包含3个副本的主题,如果最小同步副本被设为2,那么至少要存在两个同步副本才能向分区写入数据。通过min.insync.replicas参数设置最小同步副本个数
4.同步异步刷盘:
同步异步刷盘的区别在于,消息存储在内存(memory)中以后,是否会等待执行完刷盘动作再返回,即是否会等待将消息中的消息写入磁盘中。kafka可以通过配置flush.message和flush.ms来设置刷盘策略,如果flush.message设置为5,表示每5条消息进行一次刷盘,如果flush.message设置为1,表示每一条消息都进行一次刷盘。如果flush.ms设置为1000,表示每过1000ms进行一次刷盘,如果flush.ms设置为5000,表示每过5000ms进行一次刷盘。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。