learn.lianglianglee.com/专栏/Kafka核心技术与实战/加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘.md.html
2022-08-14 03:40:33 +08:00

378 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/Kafka核心技术与实战/00 开篇词 为什么要学习Kafka.md.html">00 开篇词 为什么要学习Kafka</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/01 消息引擎系统ABC.md.html">01 消息引擎系统ABC</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/02 一篇文章带你快速搞定Kafka术语.md.html">02 一篇文章带你快速搞定Kafka术语</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/03 Kafka只是消息引擎系统吗.md.html">03 Kafka只是消息引擎系统吗</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/04 我应该选择哪种Kafka.md.html">04 我应该选择哪种Kafka</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/05 聊聊Kafka的版本号.md.html">05 聊聊Kafka的版本号</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/06 Kafka线上集群部署方案怎么做.md.html">06 Kafka线上集群部署方案怎么做</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/07 最最最重要的集群参数配置(上).md.html">07 最最最重要的集群参数配置(上)</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/08 最最最重要的集群参数配置(下).md.html">08 最最最重要的集群参数配置(下)</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/09 生产者消息分区机制原理剖析.md.html">09 生产者消息分区机制原理剖析</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/10 生产者压缩算法面面观.md.html">10 生产者压缩算法面面观</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/11 无消息丢失配置怎么实现?.md.html">11 无消息丢失配置怎么实现?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/12 客户端都有哪些不常见但是很高级的功能?.md.html">12 客户端都有哪些不常见但是很高级的功能?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/13 Java生产者是如何管理TCP连接的.md.html">13 Java生产者是如何管理TCP连接的</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/14 幂等生产者和事务生产者是一回事吗?.md.html">14 幂等生产者和事务生产者是一回事吗?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/15 消费者组到底是什么?.md.html">15 消费者组到底是什么?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/16 揭开神秘的“位移主题”面纱.md.html">16 揭开神秘的“位移主题”面纱</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/17 消费者组重平衡能避免吗?.md.html">17 消费者组重平衡能避免吗?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/18 Kafka中位移提交那些事儿.md.html">18 Kafka中位移提交那些事儿</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/19 CommitFailedException异常怎么处理.md.html">19 CommitFailedException异常怎么处理</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/20 多线程开发消费者实例.md.html">20 多线程开发消费者实例</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/21 Java 消费者是如何管理TCP连接的.md.html">21 Java 消费者是如何管理TCP连接的</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/22 消费者组消费进度监控都怎么实现?.md.html">22 消费者组消费进度监控都怎么实现?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/23 Kafka副本机制详解.md.html">23 Kafka副本机制详解</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/24 请求是怎么被处理的?.md.html">24 请求是怎么被处理的?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/25 消费者组重平衡全流程解析.md.html">25 消费者组重平衡全流程解析</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/26 你一定不能错过的Kafka控制器.md.html">26 你一定不能错过的Kafka控制器</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/27 关于高水位和Leader Epoch的讨论.md.html">27 关于高水位和Leader Epoch的讨论</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/28 主题管理知多少.md.html">28 主题管理知多少</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/29 Kafka动态配置了解下.md.html">29 Kafka动态配置了解下</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/30 怎么重设消费者组位移?.md.html">30 怎么重设消费者组位移?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/31 常见工具脚本大汇总.md.html">31 常见工具脚本大汇总</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/32 KafkaAdminClientKafka的运维利器.md.html">32 KafkaAdminClientKafka的运维利器</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/33 Kafka认证机制用哪家.md.html">33 Kafka认证机制用哪家</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/34 云环境下的授权该怎么做?.md.html">34 云环境下的授权该怎么做?</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/35 跨集群备份解决方案MirrorMaker.md.html">35 跨集群备份解决方案MirrorMaker</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/36 你应该怎么监控Kafka.md.html">36 你应该怎么监控Kafka</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/37 主流的Kafka监控框架.md.html">37 主流的Kafka监控框架</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/38 调优Kafka你做到了吗.md.html">38 调优Kafka你做到了吗</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/39 从0搭建基于Kafka的企业级实时日志流处理平台.md.html">39 从0搭建基于Kafka的企业级实时日志流处理平台</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/40 Kafka Streams与其他流处理平台的差异在哪里.md.html">40 Kafka Streams与其他流处理平台的差异在哪里</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/41 Kafka Streams DSL开发实例.md.html">41 Kafka Streams DSL开发实例</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/42 Kafka Streams在金融领域的应用.md.html">42 Kafka Streams在金融领域的应用</a>
</li>
<li>
<a class="current-tab" href="/专栏/Kafka核心技术与实战/加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘.md.html">加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘</a>
</li>
<li>
<a href="/专栏/Kafka核心技术与实战/结束语 以梦为马,莫负韶华!.md.html">结束语 以梦为马,莫负韶华!</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘</h1>
<p>你好,我是胡夕。</p>
<p>截止到现在,专栏已经更新了 38 讲,你掌握得怎么样了呢?如果暂时掌握得不是很好,也没有关系,慢慢来,有问题记得在留言区留言,我们一起讨论。</p>
<p>今天,我们来聊点儿不一样的。我总结了 3 个讨论热度很高的话题,现在一一来为你“揭秘”。</p>
<ol>
<li>如何搭建 Kafka 开发环境?很多人对于编译和调试 Kafka 饶有兴致,却苦于无从下手。今天我就给你完整地演示一遍搭建 Kafka 开发环境的过程。</li>
<li>如何阅读 Kafka 源码?我曾经在专栏[第 1 讲]提到过我自己阅读 Kafka 源码的经历,后来我收到很多留言,问我是如何阅读的,今天,我就跟你分享一些阅读 Kafka 源代码的比较好的法则或者技巧。</li>
<li>Kafka 的学习资料。幸运的是,我在这方面还是有过一些总结的,今天我会毫无保留地把资料全部分享给你。</li>
</ol>
<h2>Kafka 开发环境搭建</h2>
<p>现在,我先来回答第 1 个问题:如何搭建 Kafka 开发环境。我以 IDEA 为例进行说明Eclipse 应该也是类似的。</p>
<h3>第 1 步:安装 Java 和 Gradle</h3>
<p>要搭建 Kafka 开发环境,你必须要安装好 Java 和 Gradle同时在 IDEA 中安装 Scala 插件。你最好把 Java 和 Gradle 环境加入到环境变量中。</p>
<h3>第 2 步:下载 Kafka 的源码</h3>
<p>完成第 1 步之后,下载 Kafka 的源码,命令如下:</p>
<pre><code>$ cd Projects
$ git clone https://github.com/apache/kafka.git
</code></pre>
<p>这个命令下载的是 Kafka 的 trunk 分支代码,也就是<strong>当前包含所有已提交 Patch 的最新代码,甚至比 Kafka 官网上能够下载到的最新版本还要超前很多</strong>。值得注意的是,如果你想向 Kafka 社区贡献代码,通常要以 trunk 代码为主体进行开发。</p>
<h3>第 3 步:下载 Gradle 的 Wrapper 程序套件</h3>
<p>代码下载完成之后,会自动创建一个名为 kafka 的子目录,此时需要进入到该目录下,执行下面的这条命令,主要目的是下载 Gradle 的 Wrapper 程序套件。</p>
<pre><code>$ gradle
Starting a Gradle Daemon (subsequent builds will be faster)
&gt; Configure project :
Building project 'core' with Scala version 2.12.9
Building project 'streams-scala' with Scala version 2.12.9
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.3/userguide/command_line_interface.html#sec:command_line_warning
</code></pre>
<h3>第 4 步:将 Kafka 源码编译打包成 Jar 文件</h3>
<p>现在,你可以运行下列命令,将 Kafka 源码编译打包成 Jar 文件:</p>
<pre><code>./gradlew clean releaseTarGz
</code></pre>
<p>通常你需要等待一段时间,经过一系列操作之后,比如 Gradle 拉取依赖 Jar 包、编译 Kafka 源码、打包等,你可以在 core 的 build/distributions 下面找到生成的 tgz 包kafka_2.12-2.4.0-SNAPSHOT。解压之后这就是一个可以正常启动运行的 Kafka 环境了。</p>
<h3>第 5 步:把 Kafka 源码工程导入到 IDEA 中</h3>
<p>这也是搭建开发环境的最后一步。你可以先执行下面的命令去创建 IDEA 项目所需要的项目文件:</p>
<pre><code>$ ./gradlew idea # 如果你用的是 Eclipse执行./gradlew eclipse 即可
</code></pre>
<p>接着,你需要打开 IDEA选择“打开工程”然后再选择 kafka 目录即可。</p>
<p>至此,我们就在 IDEA 中搭建了 Kafka 源码环境。你可以打开 Kafka.scala 文件,右键选择“运行”,这时,你应该可以看到启动 Kafka Broker 的命令行用法说明,如下图所示:</p>
<p><img src="assets/14c7b6c978106a07a1170a2402c3443c.png" alt="img" /></p>
<p>总体来说Kafka 工程自从由使用 sbt 改为使用 Gradle 管理之后,整个项目的编译和构建变得简单多了,只需要 3、4 条命令就能在本机环境中搭建测试开发环境了。</p>
<h2>Kafka 源码阅读方法</h2>
<p>搭建好了开发环境,下一步自然就是阅读 Kafka 源码并尝试自行修改源码了。下图是 IDEA 上 Kafka 工程的完整目录列表。</p>
<p><img src="assets/6aa069bad076a0534d11d21c303a765d.png" alt="img" /></p>
<p>在这张图中,有几个子目录需要你重点关注一下。</p>
<ul>
<li><strong>core</strong>Broker 端工程,保存 Broker 代码。</li>
<li><strong>clients</strong>Client 端工程,保存所有 Client 代码以及所有代码都会用到的一些公共代码。</li>
<li><strong>streams</strong>Streams 端工程,保存 Kafka Streams 代码。</li>
<li><strong>connect</strong>Connect 端工程,保存 Kafka Connect 框架代码以及 File Connector 代码。</li>
</ul>
<p>我之前说过Kafka 源码有 50 万行之多,没有重点地进行通读,效率会特别低。最初我就是盲读源码的,深感效果极差,所以,我觉得非常有必要为你推荐几条最佳实践。</p>
<p>我建议你<strong>先从 core 包读起,也就是先从 Broker 端的代码着手</strong>。你可以按照下面的顺序进行阅读。</p>
<ol>
<li><strong>log 包</strong>。log 包中定义了 Broker 底层消息和索引保存机制以及物理格式,非常值得一读。特别是 Log、LogSegment 和 LogManager 这几个类,几乎定义了 Kafka 底层的消息存储机制,一定要重点关注。</li>
<li><strong>controller 包</strong>。controller 包实现的是 Kafka Controller 的所有功能,特别是里面的 KafkaController.scala 文件,它封装了 Controller 的所有事件处理逻辑。如果你想弄明白 Controller 的工作原理,最好多读几遍这个将近 2000 行的大文件。</li>
<li><strong>coordinator 包下的 group 包代码</strong>。当前coordinator 包有两个子 packagegroup 和 transaction。前者封装的是 Consumer Group 所用的 Coordinator后者封装的是支持 Kafka 事务的 Transaction Coordinator。我个人觉得你最好把 group 包下的代码通读一遍,了解下 Broker 端是如何管理 Consumer Group 的。这里比较重要的是<strong>GroupMetadataManager 和 GroupCoordinator 类</strong>,它们定义了 Consumer Group 的元数据信息以及管理这些元数据的状态机机制。</li>
<li><strong>network 包代码以及 server 包下的部分代码</strong>。如果你还有余力的话,可以再读一下这些代码。前者的 SocketServer 实现了 Broker 接收外部请求的完整网络流程。我们在专栏第 24 讲说过Kafka 用的是 Reactor 模式。如果你想搞清楚 Reactor 模式是怎么在 Kafka“落地”的就把这个类搞明白吧。</li>
</ol>
<p>从总体流程上看Broker 端顶部的入口类是 KafkaApis.scala。这个类是处理所有入站请求的总入口下图展示了部分请求的处理方法</p>
<p><img src="assets/be172674a8e31e6f0b094eae709453f3.png" alt="img" /></p>
<p>你可以进到不同的方法里面去看实际的请求处理逻辑。比如 handleProduceRequest 方法是处理 Producer 生产消息请求的,而 handleFetchRequest 方法则是处理消息读取请求的。</p>
<p>我们刚刚说的都是 core 代码包下的重要类文件。在客户端 clients 包下,我推荐你重点阅读 4 个部分的内容。</p>
<ol>
<li>**org.apache.kafka.common.record 包。**这个包下面是各种 Kafka 消息实体类,比如用于在内存中传输的 MemoryRecords 类以及用于在磁盘上保存的 FileRecords 类。</li>
<li>**org.apache.kafka.common.network 包。**这个包不用全看,你重点关注下 Selector、KafkaChannel 就好了,尤其是前者,它们是实现 Client 和 Broker 之间网络传输的重要机制。如果你完全搞懂了这个包下的 Java 代码Kafka 的很多网络异常问题也就迎刃而解了。</li>
<li><strong>org.apache.kafka.clients.producer 包</strong>。顾名思义,它是 Producer 的代码实现包,里面的 Java 类很多,你可以重点看看 KafkaProducer、Sender 和 RecordAccumulator 这几个类。</li>
<li>**org.apache.kafka.clients.consumer 包。**它是 Consumer 的代码实现包。同样地,我推荐你重点阅读 KafkaConsumer、AbstractCoordinator 和 Fetcher 这几个 Java 文件。</li>
</ol>
<p>另外,在阅读源码的时候,不管是 Broker 端还是 Client 端,你最好结合 Java 调试一起来做。通过 Debug 模式下打断点的方式,一步一步地深入了解 Kafka 中各个类的状态以及在内存中的保存信息,这种阅读方式会让你事半功倍。</p>
<h2>Kafka 推荐学习资料</h2>
<p>如果你暂时对搭建开发环境或阅读源码没有兴趣,但又想快速深入地学习 Kafka 的话,直接学习现成的资料也不失为一个妙法。接下来,我就向你推荐一些很有价值的 Kafka 学习资料。</p>
<p>第 1 个不得不提的当然就是<a href="https://kafka.apache.org/documentation/">Kafka 官网</a>。很多人会忽视官网,但其实官网才是最重要的学习资料。你只需要通读几遍官网,并切实掌握里面的内容,就已经能够较好地掌握 Kafka 了。</p>
<p>第 2 个是 Kafka 的[JIRA 列表](https://issues.apache.org/jira/browse/KAFKA-8832?filter=-4&amp;jql=project %3D KAFKA ORDER BY created DESC)。当你碰到 Kafka 抛出的异常的时候,不妨使用异常的关键字去 JIRA 中搜索一下,看看是否是已知的 Bug。很多时候我们碰到的问题早就已经被别人发现并提交到社区了。此时<strong>JIRA 列表就是你排查问题的好帮手</strong></p>
<p>第 3 个是<a href="https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Improvement+Proposals">Kafka KIP 列表</a>。KIP 的全称是 Kafka Improvement Proposals即 Kafka 新功能提议。你可以看到 Kafka 的新功能建议及其讨论。如果你想了解 Kafka 未来的发展路线KIP 是不能不看的。当然,如果你想到了一些 Kafka 暂时没有的新功能,也可以在 KIP 中提交自己的提议申请,等待社区的评审。</p>
<p>第 4 个是 Kafka 内部团队维护的<a href="https://cwiki.apache.org/confluence/display/KAFKA/Index">设计文档</a>。在这里,你几乎可以找到所有的 Kafka 设计文档。其中关于 Controller 和新版本 Consumer 的文章都很有深度,我建议你一定要重点读一读。</p>
<p>第 5 个是著名的<a href="https://stackoverflow.com/questions/tagged/apache-kafka?sort=newest&amp;pageSize=15">StackOverflow 论坛</a>。当今StackOverflow 论坛对程序员意味着什么,想必我不说你也知道。这里面的 Kafka 问题很有深度。事实上,从仅仅是 StackOverflow 上的一个问题,到最后演变成了 Kafka 的 Bug 修复或新功能实现的情况屡见不鲜。</p>
<p>第 6 个是 Confluent 公司维护的<a href="https://www.confluent.io/blog/">技术博客</a>。这是 Kafka 商业化公司 Confluent 团队自己维护的技术博客,里面的技术文章皆出自 Kafka Committer 之手,质量上乘,我从中受益匪浅。比如讲述 Kafka 精确一次处理语义和事务的文章,含金量极高,你一定要去看一下。</p>
<p>第 7 个是我自己的<a href="https://www.cnblogs.com/huxi2b/">博客</a>。我会定期在博客上更新 Kafka 方面的原创文章。有的是我对 Kafka 技术的一些理解,有的是 Kafka 的最新动态。虽然不是国内质量最好的,但应该是坚持时间最长的。毕竟,我这个博客就只有 Kafka 的内容,而且已经写了好几年了。</p>
<p>最后,我给推荐你 3 本学习 Kafka 的书。</p>
<p>第 1 本是我的<a href="https://book.douban.com/subject/30221096/">《Apache Kafka 实战》</a>,我在里面总结了我这几年使用和学习 Kafka 的各种实战心得。这本书成书于 2018 年,虽然是以 Kafka 1.0 为模板撰写的,而 Kafka 目前已经出到了 2.3 版本,但其消息引擎方面的功能并没有什么重大变化,因此绝大部分内容依然是有效的。</p>
<p>第 2 本是<a href="https://book.douban.com/subject/27179953/">《Kafka 技术内幕》</a>。我个人非常喜欢这个作者的书写风格,而且这本书内容翔实,原理分析得很透彻,配图更是精彩。</p>
<p>第 3 本是 2019 年新出的一本名为<a href="https://book.douban.com/subject/30437872/">《深入理解 Kafka》</a>的书。这本书的作者是一位精通 RabbitMQ 和 Kafka 的著名技术人,对消息中间件有着自己独特的见解。</p>
<p>这些资料各有侧重,你可以根据自己的实际需求,选择相应的资料进行学习。</p>
<h2>小结</h2>
<p>好了,我们来小结一下。在今天的文章里,我跟你分享了很多经验,比如如何搭建 Kafka 开发环境、如何阅读 Kafka 源码等,希望这些经验可以帮你有效地节省时间,避免走一些弯路。另外,我把我收集到的相关学习资料全部列了出来,分享给你,也希望这些资料能够帮你更好地学习 Kafka。</p>
<p>讲到这里,我想再强调一下,学习是个持续的过程。经验和外部帮助固然重要,但最关键的,还是自己要付出努力,持之以恒。</p>
<p>还是那句话Stay focused and work hard</p>
<p><img src="assets/1b0cb1332a8d6a3a8eba22e3c98a4cf1.jpg" alt="img" /></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/Kafka核心技术与实战/42 Kafka Streams在金融领域的应用.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/Kafka核心技术与实战/结束语 以梦为马,莫负韶华!.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709972292ef73d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>