大家好,我是 yes。

这是我的第三篇Kafka源码分析文章,前两篇讲了日志段的读写二分算法在kafka索引上的应用

今天来讲讲 Kafka Broker端处理请求的全流程,剖析下底层的网络通信是如何实现的、Reactor在kafka上的应用。

再说说社区为何在2.3版本将请求类型划分成两大类,又是如何实现两类请求处理的优先级。

叨叨

不过在进入今天主题之前我想先叨叨几句,就源码这个事儿,不同人有不同的看法。

有些人听到源码这两个词就被吓到了,这么多代码怎么看。奔进去就像无头苍蝇,一路断点跟下来,跳来跳去,算了拜拜了您嘞。

而有些人觉得源码有啥用,看了和没看一样,看了也用不上。

其实上面两种想法我都有过,哈哈哈。那为什么我会开始看Kafka源码呢?

其实就是我有个同事在自学go,然后想用go写个消息队列,在画架构图的时候就来问我,这消息队列好像有点东西啊,消息收发,元数据管理,消息如何持久一堆问题过来,我直呼顶不住。

这市面上KafkaRocketMQ都是现成的方案,于是乎我就看起了源码。

所以促使我看源码的初始动力,竟然是为了在同事前面装逼!!

我是先看了RocketMQ,因为毕竟是Java写的,而Kafka Broker都是scala写的。

梳理了一波RocketMQ之后,我又想看看Kafka是怎么做的,于是乎我又看起了Kafka

在源码分析之前我先总结性的说了说Kafka底层的通信模型。应对面试官询问Kafka请求全过程已经够了。

Reactor模式

在扯到Kafka之前我们先来说说Reactor模式,基本上只要是底层的高性能网络通信就离不开Reactor模式。像Netty、Redis都是使用Reactor模式

像我们以前刚学网络编程的时候以下代码可是非常的熟悉,新来一个请求,要么在当前线程直接处理了,要么新起一个线程处理。

在早期这样的编程是没问题的,但是随着互联网的快速发展,单线程处理不过来,也不能充分的利用计算机资源。

而每个请求都新起一个线程去处理,资源的要求就太高了,并且创建线程也是一个重操作。

说到这有人想到了,那搞个线程池不就完事了嘛,还要啥Reactor

池化技术确实能缓解资源的问题,但是池子是有限的,池子里的一个线程不还是得候着某个连接,等待指示嘛。现在的互联网时代早已突破C10K了。

因此引入的IO多路复用,由一个线程来监视一堆连接,同步等待一个或多个IO事件的到来,然后将事件分发给对应的Handler处理,这就叫Reactor模式

网络通信模型的发展如下

单线程 => 多线程 => 线程池 => Reactor模型

Kafka所采用的Reactor模型如下

Kafka Broker 网络通信模型

简单来说就是,Broker 中有个Acceptor(mainReactor)监听新连接的到来,与新连接建连之后轮询选择一个Processor(subReactor)管理这个连接。

Processor会监听其管理的连接,当事件到达之后,读取封装成Request,并将Request放入共享请求队列中。

然后IO线程池不断的从该队列中取出请求,执行真正的处理。处理完之后将响应发送到对应的Processor的响应队列中,然后由ProcessorResponse返还给客户端。

每个listener只有一个Acceptor线程,因为它只是作为新连接建连再分发,没有过多的逻辑,很轻量,一个足矣。

Processor 在Kafka中称之为网络线程,默认网络线程池有3个线程,对应的参数是num.network.threads。并且可以根据实际的业务动态增减。

还有个 IO 线程池,即KafkaRequestHandlerPool,执行真正的处理,对应的参数是num.io.threads,默认值是 8。IO线程处理完之后会将Response放入对应的Processor中,由Processor将响应返还给客户端。

可以看到网络线程和IO线程之间利用的经典的生产者 - 消费者模式,不论是用于处理Request的共享请求队列,还是IO处理完返回的Response。

这样的好处是什么?生产者和消费者之间解耦了,可以对生产者或者消费者做独立的变更和扩展。并且可以平衡两者的处理能力,例如消费不过来了,我多加些IO线程。

如果你看过其他中间件源码,你会发现生产者-消费者模式真的是太常见了,所以面试题经常会有手写一波生产者-消费者。

源码级别剖析网络通信模型

Kafka 网络通信组件主要由两大部分构成:SocketServerKafkaRequestHandlerPool

SocketServer



可以看出SocketServer旗下管理着,Acceptor 线程Processor 线程RequestChannel 等对象。

data-planecontrol-plane稍后再做分析,先看看RequestChannel是什么。

RequestChannel



关键的属性和方法都已经在下面代码中注释了,可以看出这个对象主要就是管理Processor作为传输RequestResponse的中转站

Acceptor

接下来我们再看看Acceptor

可以看到它继承了AbstractServerThread,接下来再看看它run些啥



再来看看accept(key) 做了啥

很简单,标准selector的处理,获取准备就绪事件,调用serverSocketChannel.accept()得到socketChannel,将socketChannel交给通过轮询选择出来的Processor,之后由它来处理IO事件。

Processor

接下来我们再看看Processor,相对而言比Acceptor 复杂一些。

先来看看三个关键的成员

再来看看主要的处理逻辑。

可以看到Processor主要是将底层读事件IO数据封装成Request存入队列中,然后将IO线程塞入的Response,返还给客户端,并处理Response 的回调逻辑。

KafkaRequestHandlerPool

IO线程池,实际处理请求的线程。

再来看看IO线程都干了些啥

很简单,核心就是不断的从requestChannel拿请求,然后调用handle处理请求。

handle方法是位于KafkaApis类中,可以理解为通过switch,根据请求头里面不同的apikey调用不同的handle来处理请求。

我们再举例看下较为简单的处理LIST_OFFSETS的过程,即handleListOffsetRequest,来完成一个请求的闭环。

我用红色箭头标示了调用链。表明处理完请求之后是塞给对应的Processor的。

最后再来个更详细的总览图,把源码分析到的类基本上都对应的加上去了。

请求处理优先级

上面提到的data-planecontrol-plane是时候揭开面纱了。这两个对应的就是数据类请求和控制类请求。

为什么需要分两类请求呢?直接在请求里面用key标明请求是要读写数据啊还是更新元数据不就行了吗?

简单点的说比如我们想删除某个topic,我们肯定是想这个topic马上被删除的,而此时producer还一直往这个topic写数据,那这个情况可能是我们的删除请求排在第N个...等前面的写入请求处理好了才轮到删除的请求。实际上前面哪些往这个topic写入的请求都是没用的,平白的消耗资源。

再或者说进行Preferred Leader选举时候,producerack设置为all时候,老leader还在等着follower写完数据向他报告呢,谁知follower已经成为了新leader,而通知它leader已经变更的请求由于被一堆数据类型请求堵着呢,老leader就傻傻的在等着,直到超时。

就是为了解决这种情况,社区将请求分为两类。

那如何让控制类的请求优先被处理?优先队列?

社区采取的是两套Listener,即数据类型一个listener,控制类一个listener

对应的就是我们上面讲的网络通信模型,在kafka中有两套! kafka通过两套监听变相的实现了请求优先级,毕竟数据类型请求肯定很多,控制类肯定少,这样看来控制类肯定比大部分数据类型先被处理!

迂回战术啊。

控制类的和数据类区别就在于,就一个Porcessor线程,并且请求队列写死的长度为20。

最后

看源码主要就是得耐心,耐心跟下去。然后再跳出来看。你会发现不过如此,哈哈哈。

我是yes,一个在互联网摸爬滚打且莫得感情的工具人。

Kafka处理请求的全流程分析的更多相关文章

  1. Kafka控制器事件处理全流程分析

    前言 大家好,我是 yes. 这是Kafka源码分析第四篇文章,今天来说说 Kafka控制器,即 Kafka Controller. 源码类的文章在手机上看其实效果很差,这篇文章我分为两部分,第一部分 ...

  2. springboot 事务执行全流程分析

    springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...

  3. Nginx 多进程连接请求/事件分发流程分析

    Nginx使用多进程的方法进行任务处理,每个worker进程只有一个线程,单线程循环处理全部监听的事件.本文重点分析一下多进程间的负载均衡问题以及Nginx多进程事件处理流程,方便大家自己写程序的时候 ...

  4. 监控视频采集与Web直播开发全流程分析

    内容概要: 摄像头 => FFmpeg => Nginx服务器 => 浏览器 从摄像头拉取rtsp流 转码成rtmp流向推流服务器写入 利用html5播放 1.开发流程 1.1 通过 ...

  5. springmvc处理一个请求的全流程

    首先,用户的浏览器发出了一个请求,这个请求经过互联网到达了我们的服务器. Servlet 容器首先接待了这个请求,并将该请求委托给 DispatcherServlet 进行处理. 接着 Dispatc ...

  6. 图解 Spring:HTTP 请求的处理流程与机制【1】

    2003 年,老兵哥初到中兴开始研究生实习,Spring 就是那年诞生的,2004 年 3 月发布了 1.0 版本,到现在已经超过 15 年了.从单体式分层架构到云原生微服务架构,它稳坐在 JAVA ...

  7. Kafka工作流程分析

    Kafka工作流程分析 生产过程分析 写入方式 producer采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(patition)中,属于顺序写磁盘(顺序写磁盘 ...

  8. Kafka之工作流程分析

    Kafka之工作流程分析 kafka核心组成 一.Kafka生产过程分析 1.1 写入方式 producer采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(pa ...

  9. 全球首个全流程跨平台界面开发套件,PowerUI分析

    一.       首个全流程跨平台界面开发套件,PowerUI正式发布 UIPower在DirectUI的基础上,自主研发全球首个全流程跨平台界面开发套件PowerUI(PUI)正式发布,PowerU ...

随机推荐

  1. 如何在Linux上使用xargs命令

    大家好,我是良许. 在使用 Linux 时,你是否遇到过需要将一些命令串在一起,但是其中一个命令不接受管道输入的情况呢?在这种情况下,我们就可以使用 xargs 命令.xargs 可以将一个命令的输出 ...

  2. Java 接口简述

    Java 接口 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并 ...

  3. HTTP系列1番外之头部字段大全

    原文地址:https://www.jianshu.com/p/6e86903d74f7 常用标准请求头 字段 属性 举例 Accept 设置接受的内容类型 Accept: text/plain Acc ...

  4. Java高级特性——反射机制(第三篇)

    获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...

  5. C/C++ MFC

    C++ & MFC(转载)   C++是一种静态数据类型检查的.支持多重编程范式的程序设计语言,支持过程化程序设计.数据抽象.面向对象程序设计.制作图标等泛型程序设计的多种程序设计风格. MF ...

  6. JVM 第一篇:编译 OpenJdk14 ,我行你也行

    本文内容过于硬核,建议有 Java 相关经验人士阅读. 1 引言 从上周开始一直在看周志明的 「深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)」 ,好多年之前看过第二版的,绝对算的上是国内 ...

  7. 京东T8通过企业实例展示软件架构实际应用,带你迅速成为架构师

    在软件行业,架构师和软件工程师是非常辛苦的职业.一方面新技术层出不穷;另一方面业务需求也层出不穷,让人疲于应付.导致的后果就是常常加班,生活质量低下.只有曾经身在其中的人,才能够体会其中的酸甜苦辣. ...

  8. 图解Janusgraph系列-分布式id生成策略分析

    JanusGraph - 分布式id的生成策略 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 本次更新时间:2020-9-1 文章为作者跟踪源码和查看官方文档整理,如有任何问题,请联 ...

  9. 不要盲目使用新技术,说的就是你,JWT!

    其实我更想聊标题的前半部分,后半部分只是拉出来做典型的. 简历上写上一句,"热衷于学习新技术",孬管是不是真的,至少加分项是可以有的. 再看看标题,我是来搞笑的? 学习与使用,两回 ...

  10. unimrcp plugin 分析

    摘要: unimrcp 访问媒体资源是通过插件实现,社区的代码给出了demo plugin,但是距离一个生产插件还是有一段的距离.这边文章介绍插件的整个逻辑过程,以及如何实现我们自己的插件.