利志分享
fast_forward
view_headline
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
kafka入门
kafka安装使用教程
kafka的架构设计
Kafka 消费组 Rebalance机制
全网最通俗易懂的Kafka图解入门
深入kafka的幂等性和事务
kafka深入
聊聊kafka的生成和消费的问题
go的kafka生产和消费
全网最通俗易懂的Kafka图解新建Topic,写入消息的原理
关于Kafka,你必须要知道的offset知识。
Kafka的Producer实现原理剖析
一次线上kafka磁盘扩容引发的事故分析
目录
kafka入门
kafka安装使用教程
kafka的架构设计
Kafka 消费组 Rebalance机制
全网最通俗易懂的Kafka图解入门
深入kafka的幂等性和事务
kafka深入
聊聊kafka的生成和消费的问题
go的kafka生产和消费
全网最通俗易懂的Kafka图解新建Topic,写入消息的原理
关于Kafka,你必须要知道的offset知识。
Kafka的Producer实现原理剖析
一次线上kafka磁盘扩容引发的事故分析
kafka的架构设计
阅读:649
分享次数:0
**1:kafka的架构**  如图,kafka的架构主要由**生产者,kafka集群,消费者**三部分组成。 **生产者**又名Producer,生产者生成的数据由topic进行标识管理,topic的数据可以通过设置分区写入数据到不同的分区中去。 ------------ **kafka集群包含broker,Topic,Partition,Replication,Message的部分,还有Zookeeper协助功能。** **Broker**:是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等,broker主要接受来至生产者的消息,为消息设置偏移量,并提交消息到磁盘保存,broker节点的管理是通过zookeeper来控制选举和下线。 **Topic**:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。 **Partition**:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹! **Replication**:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。 **Message**:每一条发送的消息主体。 ------------ **消费者**又名consumer,消费者是通过消费者组进行管理,一个消费者肯定有隶属的消费者组。 **Consumer**:消费者,即消息的消费方,是消息的出口。 **Consumer Group**:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量。 **Group Coordinator**:是一个服务,每个Broker在启动的时候都会启动一个该服务。Group Coordinator的作用是用来存储Group的相关Meta信息,并将对应Partition的Offset信息记录到Kafka内置Topic(consumer_offsets)中。Kafka在0.9之前是基于Zookeeper来存储Partition的Offset信息(consumers/{group}/offsets/{topic}/{partition}),因为ZK并不适用于频繁的写操作,所以在0.9之后通过内置Topic的方式来记录对应Partition的Offset。 每个Group都会选择一个Coordinator来完成自己组内各Partition的Offset信息,选择的规则如下: 1,计算Group对应在_consumer_offsets上的Partition 2,根据对应的Partition寻找该Partition的leader所对应的Broker,该Broker上的Group Coordinator即就是该Group的Coordinator **Zookeeper**:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。zookeeper是用来管理broker和consumer的。 **2:生产者架构**  如图:整个生产者客户端由两个线程协调运行,这两个线程分别为主线程和Sender线程(发送线程)。在主线程中由KafkaProducer创建消息,然后通过可能的拦截器、序列化器和分区器的作用之后缓存到消息累加器(RecordAccumulator,也称为消息收集器)中。Sender线程负责从RecordAccumulator中获取消息并将其发送到Kafka中。 RecordAccumulator主要用来缓存消息以便Sender线程可以批量发送,进而减少网络传输的资源消耗提升性能。RecordAccumulator缓存的大小可以通过生产者客户端参数buffer.memory的配置,默认值为32MB。如果生产者发送消息的速度超过发送到服务器的速度,则会导致生产者空间不足,这个时候KafkaProducer的send()方法调用要么被阻塞,要么抛出异常,这个取决于参数max.block.ms的配置,此参数的默认值为60000,即60秒。 主线程中发送过来的消息都会被追回到RecordAccumulator的某个双端队列(Deque)中,在RecordAccumulator的内部为每个分区都维护了一个双端队列,队列中的内容就是ProducerBatch,即Deque<ProducerBatch>。消息写入缓存时,追回到双端队列的尾部;Sender读取消息时,从双端队列的头部读取。 消息在网络上都是以字节(Byte)的形式传输的,在发送之前需要创建一块内存区域来保存对应的消息。在Kafka生产者客户端中,通过java.io.ByteBuffer实现消息内存的创建和释放。不过频繁的创建和释放是比较耗费资源的,在RecordAccumulator的内部还有一个BufferPool,它主要是用来实现ByteBuffer的复用,以实现缓存的高效利用。 不过BufferPool只针对特定大小的ByteBuffer进行管理,而其它大小的ByteBuffer不会缓存进BufferPool中,这个特定的大小由batch.size参数指定,默认值为64KB,可以适当地调大batch.size参数以便多缓存一些消息。 ProducerBatch的大小和batch.size参数也有着密切的关系。当一条消息(ProducerRecord)流入RecordAccumulator时,会先寻找与消息分区所对应的双端队列(如果没有则创建),再从这个双端队列的尾部获取一个ProducerBatch(如果没有则创建),查看ProducerBatchk中是否还可以写入这个ProdcucerRecord,如果可以则写入,如果不可以则需要创建一个新的ProducerBatch。在新建ProducerBatch时评估这条消息的大小是否超过batch.size参数的大小,如果不超过,那么就以batch.size参数的大小来创建ProducerBatch,这样在使用完这段内存区域后,可以通过BufferPool的管理来进行复用;如果超过,那么就以评估的大小创建ProducerBatch,这段内存区域不会被复用。 Sender从RecordAccumulator中获取缓存的消息之后,会进一步将原本<分区,Deque<ProducerBatch>>的保存形式转变成<Node, List<ProducerBatch>>的形式,其中Node表示Kafka集群的broker节点。对象网络连接来说,生产者客户端是与具体的broker节点建立的连接,就是向具体的broker节点发送消息,而并不关心消息属于哪一个分区;而对于KafkaProducer的应用逻辑而言,我们只关注向哪个分区中发送哪些消息,所以这里需要做一个应用逻辑层面到网络I/O层面的转换。 在转换成<Node, List<ProducerBatch>>的形式之后,Sender还会进一步封装成<Node, Request>的形式,这样就可以将Request请求发往各个Node了,这里的Request是指Kafka的各种协议请求,对于消息发送而言就是指具体的ProducerRequest。 请求在从Sender线程发往Kafka之前还会保存到InFlightRequests中,InFlightRequest保存对象的具体形式为Map<NodeId, Deque<Request>>,它的主要作用是缓存了已经发出去但还没有收到响应的请求(NodeId是一个String类型,表示节点的id编号)。与此同时,InFlightRequests还提供了许多管理类的方法,并且通过配置参数还可以限制每个连接(即客户端与Node之间的连接)最多缓存的请求数。这个配置参数为max.in.flight.requests.per.connection,默认值为5,即每个连接最多只能缓存5个未响应的请求,超过该数值之后就不能向这个连接发送更多的请求了,除非有缓存的请求收到了响应(Response)。通过比较Deque<Request>的size与这个参数的大小来判断对应的Node中是否已经堆积了很多未响应的消息,如果真是如此,那么说明这个Node节点负载较大或网络连接有总是,再继续向其发送请求会增大请求超时的可能。 **3:消费者架构** 消费者相对来说比较简单,只有消费者和消费者组的概念,一个consumer可以消费多个partitions中的消息。
感觉本站内容不错,读后有收获?
attach_money
我要小额打赏,鼓励作者写出更好的教程
扫码关注公众号:talk_lizhi