胡夕:阅读源码,逐渐成了职业进阶道路上的“必选项”
你好,我是胡夕,友信金服商业智能部总监,同时也是Apache Kafka社区的一名代码贡献者。目前,我在社区的贡献排行榜上排在第21位,应该算是国内比较活跃的社区参与者了。
为什么要读源码?
谈到源码分析,特别是Apache Kafka这类消息引擎的源码,你可能会说:“我都已经在使用它了,也算是也比较熟练了,何必还要再花费时间去阅读源码呢?”
当然了,一些非Kafka使用者也会说:“我不用Kafka,读源码对我有什么用呢?”
其实,在没有阅读源码之前,我也是这么想的。但是,后来在生产环境上碰到的一件事,彻底改变了我的想法。
我们知道,Kafka Broker端有个log.retention.bytes参数,官网的描述是:它指定了留存日志的最大值。有了这个参数的“帮忙”,我们信誓旦旦地向领导保证,不会过多占用公司原本就很紧张的物理磁盘资源。但是,最终实际占用的磁盘空间却远远超出了这个最大值。
我们查遍了各种资料,却始终找不到问题的根因,当时,我就想,只能读源码碰碰运气了。结果,源码非常清楚地说明了,这个参数能不能起作用和日志段大小息息相关。知道了这一点,问题就迎刃而解了。
这时,我才意识到,很多棘手的问题都要借助源码才能解决。
除此之外,我还发现,在很多互联网公司资深技术岗位的招聘要求上,“读过至少一种开源框架的源码”赫然在列。这也就意味着,阅读源码正在从“加分项”向“必选项”转变,掌握优秀的框架代码实现从NICE-TO-DO变成了MUST-DO。
那,为什么读源码逐渐成为了必选项?它究竟有什么作用呢?下面我结合我自己的经历,和你说说读源码的几点收获。
1.可以帮助你更深刻地理解内部设计原理,提升你的系统架构能力和代码功力。
作为一款优秀的消息引擎,Kafka的架构设计有很多为人称道的地方,掌握了这些原理将极大地提升我们自身的系统架构能力和代码功力。
当然了,即使你不使用Kafka,也可以借鉴其优秀的设计理念,提升你在其他框架上的系统架构能力。
你可能会问,官网文档也有相应的阐述啊,我单纯阅读文档不就够了吗?
实际上,我一直认为社区官方文档的内容有很大的提升空间,Kafka有许多很棒的设计理念和特性,在文档中并未得到充分的阐述。
我简单举个例子。Kafka中有个非常重要的概念:当前日志段(Active Segment)。Kafka的很多组件(比如LogCleaner)是区别对待当前日志段和非当前日志段的。但是,Kafka官网上几乎完全没有提过它。
所以你看,单纯依赖官网文档的话,肯定是无法深入了解Kafka的。
2.可以帮你快速定位问题并制定调优方案,减少解决问题的时间成本。
很多人认为,阅读源码需要花费很多时间,不值得。这是一个非常大的误区。
实际上,你掌握的源码知识可以很好地指导你日后的实践,帮助你快速地定位问题的原因,迅速找到相应的解决方案。最重要的是,如果你对源码了然于心,你会很清楚线上环境的潜在问题,提前避“坑”。在解决问题时,阅读源码其实是事半功倍的“捷径”。
如果用时间成本来考量的话,你可以把阅读源码的时间分摊到后续解决各种问题的时间上,你会发现,这本质上是一件划算的事情。
3.你还能参加Kafka开源社区,成为一名代码贡献者(Contributor)。
在社区中,你能够和全世界的Kafka源码贡献者协同工作,彼此分享交流,想想就是一件很有意思的事情。特别是当你的代码被社区采纳之后,全世界的Kafka使用者都会使用你写的代码。这简直太让人兴奋了,不是吗?
总而言之,阅读源码的好处真的很多,既能精进代码功力,又能锤炼架构技巧,还能高效地解决实际问题,有百利而无一害。
如何用最短的时间掌握最核心的源码?
Kafka代码有50多万行,如果我们直接冲下场开始读,一定会“丈二和尚摸不着头脑”。
毕竟,面对这么多代码,通读一遍的效率显然并不高。为了避免从入门到放弃,我们要用最高效的方式阅读最核心的源码。
通常来说,阅读大型项目的源码无外乎两种方法。
自上而下(Top-Down):从最顶层或最外层的代码一步步深入。通俗地说,就是从 main 函数开始阅读,逐渐向下层层深入,直到抵达最底层代码。这个方法的好处在于,你遍历的是完整的顶层功能路径,这对于你了解各个功能的整体流程极有帮助。
自下而上(Bottom-Up):跟自上而下相反,是指先独立地阅读和搞懂每个组件的代码和实现机制,然后不断向上延展,并最终把它们组装起来。该方法不是沿着功能的维度向上溯源的,相反地,它更有助于你掌握底层的基础组件代码。
这两种方法各有千秋,不过,在学习Kafka源码的过程中,我发现,将两者结合的方法其实是最高效的,即先弄明白最细小单位组件的用途,然后再把它们拼接组合起来,掌握组件组合之后的功能。
具体怎么做呢?首先,你要确认最小单位的组件。我主要是看Kafka源码中的包结构(package structure),比如controller、log、server等,这些包基本上就是按照组件来划分的。我给这些组件确定的优先级顺序是“log-->network-->controller-->server-->coordinator-->……”,毕竟,后面的组件会频繁地调用前面的组件。
等你清楚地了解了单个组件的源码结构,就可以试着切换成自上而下的方法,即从一个大的功能点入手,再逐步深入到各个底层组件的源码。得益于前面的积累,你会对下沉过程中碰到的各层基础代码非常熟悉,这会带给你很大的成就感。比起单纯使用自上而下或自下而上的方法,这套混合方法兼具了两者的优点。
关于如何选择大的功能点,我建议你从Kafka的命令行工具开始这种串联学习,搞明白这个工具的每一步都是怎么实现的,并且在向下钻取的过程中不断复习单个组件的原理,同时把这些组件结合在一起。
随着一遍遍地重复这个过程,你会更清楚各个组件间的交互逻辑,成为一个掌握源码的高手!
知道了方法以后,我们就可以开始Kafka源码的学习了。在深入细节之前,我们先来看下Kafka的源码全景图,找到核心的源码。
从功能上讲,Kafka源码分为四大模块。
服务器端源码:实现Kafka架构和各类优秀特性的基础。
Java客户端源码:定义了与Broker端的交互机制,以及通用的Broker端组件支撑代码。
Connect源码:用于实现Kafka与外部系统的高性能数据传输。
Streams源码:用于实现实时的流处理功能。
可以看到,服务器端源码是理解Kafka底层架构特别是系统运行原理的基础,其他三个模块的源码都对它有着强烈的依赖。因此,Kafka最最精华的代码,当属服务器端代码无疑!学习这部分代码的性价比是最高的。
然后,我还想再和你说说Scala语言的问题。毕竟,Broker端源码是完全基于Scala的。
不过,这部分源码并没有用到Scala多少高大上的语法特性。如果你有Java语言基础,就更不用担心语言的问题了,因为它们有很多特性非常相似。
即使你不熟悉Scala语言也没关系。你不需要完整、系统地学习这门语言,只要能简单了解基本的函数式编程风格,以及它的几个关键特性,比如集合遍历、模式匹配等,就足够了。
“日拱一卒无有尽,功不唐捐终入海。”阅读源码是个“苦差事”,希望你别轻易放弃。毕竟,掌握了源码,你就走在了很多人的前面。
版权声明: 本文为 InfoQ 作者【极客时间】的原创文章。
原文链接:【http://xie.infoq.cn/article/b534c5e08fd464ac486548981】。未经作者许可,禁止转载。
评论