kafka学习从源码解析开始

持续学习,持续更新中。
kafka是使用gradle管理代码。

编译kafka源码

  1. 安装scala插件,要与idea版本一致。
    使用idea远程连接下载速度较慢,这边可以在scala插件网站下载插件,要注意scala版本要与idea对应,在idea-settings-plugins里搜索scala查看版本 。然后将下载的zip(不用解压)放到idea的plugins文件夹内,重启idea在plugins中就有了。
  2. 安装gradle,配置环境变量
    安装方法与maven一模一样。前往下载gradle,注意下载binary-only,下载完成后解压,配置环境变量即可。
  3. 在idea中配置gradle
    File | Settings | Build, Execution, Deployment | Build Tools | Gradle
    在这里插入图片描述
    配置gradle的路径,一开始配置地下个Gradle | Use Gradle from 会操作,选择Specified location就可以了。
  4. 在idea中使用gradle编译源码
    可以在Terimal中输入gradle idea
    也可以在右边Gradle框内,点击右上角的刷新键编译。
    在这里插入图片描述
    这边我编译的时候遇到了几个问题:
    1.没有下载scala插件
    2.下载scala插件后,build.gradle文件中报错org.scoverage关联不到
    报Could not create an instance of type org.scoverage.ScoverageExtension的错误
    解决方法:
buildscript {
  repositories {
    mavenCentral()
    jcenter()
  }
  apply from: file('gradle/buildscript.gradle'), to: buildscript

  dependencies {
    // For Apache Rat plugin to ignore non-Git files
    classpath "org.ajoberstar:grgit:1.5.0"
    classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
    classpath 'org.scoverage:gradle-scoverage:2.1.0' //改成2.5.0后即可 
  }
}

3.可以成功编译,但是最后报错
在mvn_repository\org\slf4j\slf4j-api\1.7.21\slf4j-api-1.7.21.jar not found
下载了一个slf4j-api-1.7.21.jar放在这个路径下后,问题解决。

重新编译后,终于成功了!!

开始撸kafka源码

之前看源码都会陷入一个怪圈,看到每一行代码都想要点进去看细节,然后就把自己给绕晕了。
形成看源码的习惯:
第一遍:看大致流程
第二遍:看重要细节
第三遍:理解源码,形成脑图
看源码的方法:
1.场景驱动:先写一个生产者代码,根据代码一步步分析
2.画图分析:看源码的时候理解分析,边画图。画图工具可以使用ProcessOn免费在线作图、实时协作,持流程图、思维导图、原型图、UML、网络拓扑图、组织结构图等

kafka主要的模块如下
在这里插入图片描述

模块名描述
corekafka核心模块
clients客户端模块
examples案例、事例存放的模块

首先让我们先来看看怎么使用kafka

通过Properties类配置kafka常用的配置(有什么配置可看KafkaProducer,然后点进去看ProducerConfig看配置信息。),然后将Properties放入KafkaProducer内,再使用kafkaProducer.send(ProducerRecord)发送数据。代码如下:

private final KafkaProducer<Integer, String> producer;
    private final String topic;
    private final Boolean isAsync;

    /**
     * 构造方法,初始化生产者对象
     * @param topic 消息标题
     * @param isAsync 是否异步发送消息
     */
    public Producer(String topic, Boolean isAsync) {
        /**
         * todo:发送数据时的可以进行的配置,不一定需要全部配置
         */
        Properties properties = new Properties();
        //设置重试间隔时间,默认100ms
        properties.put("retry.backoff.ms",200);
        //设置生产者每隔一段多久获取元数据信息,默认5分钟
        properties.put("metadata.max.age.ms",5*1000*60);
        //设置生产者往服务端发送消息数据的大小,默认只有1M,基本不够用,所以这边设置10M
        properties.put("max.request.size",10*1024*1024);
        //设置缓冲区大小,默认是32M,根据情况也可以自行修改
        properties.put("buffer.memory",32*1024*1024);
        /**
         * 配置压缩格式
         * NONE GZIP SNAPPY LZ4
         * 四种压缩格式
         * 要设置小写
         */
        properties.put("compression.type","gzip");
        //设置延迟发送的时间ms,为0就不等待,一有数据就会直接发送,这种配置会降低程序的吞吐量
        properties.put("linger.ms",0);
        /**
         * NetworkClient配置,不一定必须配置
         */
        //设置网络连接最大空闲时间,如果空闲时间超过指定时间,则会断掉连接。默认9分钟
        properties.put("connections.max.idle.ms",9*60*1000);
        //最大容忍度,发送数据时,每个网络连接,最多容忍发送数据到broker没有响应的个数
        //由于kafka有重试机制,所以若有多个消息发送,可能会导致消息乱序,这时需要设置为1,保证消息的顺序,但是会降低吞吐量
        properties.put("max.in.flight.requests.per.connection",5);
        //重新连接指定主机的时间
        properties.put("reconnect.backoff.ms",50l);
        //发送数据的缓冲区大小,默认128kb
        properties.put("send.buffer.bytes",128*1024);
        //接收数据的缓冲区大小,默认32kb
        properties.put("receive.buffer.bytes",32*1024);
        /**
         * 0:只要数据发送到broker就不管了,不管有没有成功,有很大的数据丢失的风险
         * 1:数据发送到broker后,要把数据放入leader partition后,才会响应,还是有数据丢失的风险
         * -1或all:数据发送到broker后,要把数据放入leader partition后,还需要同步到follow partition后才会响应
         */
        properties.put("acks","1");
        //设置序列化
        properties.setProperty("keySerializer","org.apache.kafka.common.serialization.StringSerializer");
        properties.setProperty("valueSerializer","org.apache.kafka.common.serialization.StringSerializer");

        //初始化KafkaProducer对象
        //KafkaProducer最核心的一个类
        producer = new KafkaProducer<>(props);
        this.topic = topic;
        this.isAsync = isAsync;
    }

    public void run() {
        int messageNo = 1;
        //一直往kafka发送数据
        while (true) {
            String messageStr = "Message_" + messageNo;
            long startTime = System.currentTimeMillis();
            //判断是否同步发送
            //1为异步发送
            //0为同步发送
            if (isAsync) { // Send asynchronously
                //异步发送
                //这种方式,性能比较好
                producer.send(new ProducerRecord<>(topic,
                    messageNo,
                    messageStr), new DemoCallBack(startTime, messageNo, messageStr));
            } else { // Send synchronously
                try {
                    //同步发送,得等这条信息完成后,才能进行下一条信息的发送
                    producer.send(new ProducerRecord<>(topic,
                        messageNo,
                        messageStr)).get();
                    System.out.println("Sent message: (" + messageNo + ", " + messageStr + ")");
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            ++messageNo;
        }
    }

看到代码就知道,KafkaProducer是最核心的类,看了内部内容后,大致的流程如下:

先看流程,再看细节,最后成脑图。
在这里插入图片描述

  1. 拦截数据,对key、value的数据进行序列化。
  2. 通过分区器(Partition)将每条消息进行分区后分发到每个topic不同的分区中。
  3. 将分区器添加到RecordAccumulator缓冲区中。
  4. 更新一下元数据信息
  5. NetworkClient获取到请求然后将每个请求交给kafkaChannel缓冲区,再发送给kafka集群
  6. kafka集群响应给Selector->Networkclient->Sender
  7. 然后执行绑定的回调函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值