0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

阅读开源项目源码的实用技巧(上)

jf_78858299 来源:labuladong 作者:labuladong 2023-04-12 11:34 次阅读

本文分享一下在使用或者学习开源项目源码的过程中的一些经验技巧。

因为我最近在研究 Apache Pulsar 这款消息队列,所以就以这个项目为例, 不过本文介绍的都是通用的技巧,完全可以用在其他大型开源项目中

下面就来具体介绍一些技巧,主要分两部分:

第一部分是文档篇,即能够哪里能够获取有效的信息解决问题;

第二部分是实操篇,即如何高效打断点或借助工具理解源码。

一、文档检索技巧

想学习了解一个开源项目,文档可以帮我们解决大部分问题。当然我这里所说的不单单指官网文档,还包括 issue、PR、源码中的注释和单元测试,这些地方都可以获得大量有用的信息,所以我把它们统称为文档,下面我们从最简单的开始。

1、官网文档,着重 quickstart 和 concept 部分

官网文档无疑是最权威的资料来源,不过官网文档的问题是内容太多太全面,适合遇到问题或需求时当做功能手册去查阅。

所以官网的内容需要选择性地学习,我建议优先着重两个部分:

一是 quickstart 部分,也就是教你如何快速部署一个 demo 服务;二是 concept 部分,也就是名词解释、核心功能介绍等内容。

快速部署 demo 服务不用说了,是我们学习新技术的第一步,一般会被放在文档的第一章;而功能/名词的解释是我们接下来顺畅地学习进阶资料或参与社区讨论的重要铺垫。

对 Pulsar 这样一个消息队列来说,收发消息显然是核心功能,所以官网 Concepts and Architecture 部分中的 Messaging 章节显然是很重要的,详细介绍了 Pulsar 中诸如订阅模式、死信队列等关键功能:

图片

我在前文 Apache Pulsar 架构设计 介绍到 Pulsar 采用存算分离的架构,存储层依靠 Apache Bookkeeper。所以如果你的目标是学习 Pulsar,那么 Bookkeeper 的官网文档也是需要阅读的,因为 Pulsar 中的很多功能都会和 Bookkeeper 交互。

可以在本地启一个 Bookkeeper 集群用 client 玩一玩,阅读了解一下 Bookkeeper 中的专业术语,有助于理解 Pulsar 中的一些设计。

2、看完文档看单元测试用例,辅助我们准确理解每个功能的预期行为

一般成熟开源项目的测试用例比较完备,会覆盖所有关键功能的预期行为,所以单测用例其实也是很好的学习资料,和文档搭配食用效果最佳。

比方说,有时候文档用文字描述某个功能可能会比较繁琐,让人看的云里雾里,又或者文档中并没有介绍一些技术设计的细节。

遇到这种情况,我们大概率可以在单测文件中找到对应的功能测试代码,根据测试代码很容易反推功能,正所谓「talk is cheap, show me the code」。

举个例子,有一次我看到 consumer 打出一条关于epoch的日志,我在分布式选主的场景倒是听说过这个名词,不过显然消费消息和分布式选主没什么关系,所以这个epoch到底是干什么的?

文档里没找到答案,这应该是一个具体实现中的术语,所以我就在源码中搜索包含testEpochepochTest这两个关键词的函数名,发现了几个测试用例:

图片

PS:测试函数名的 test 关键字可能在开头也可能在最后,所以需要都搜一下。

浏览了一下这几个测试用例的内容就大致理解了,原来这个epoch是消息重投递功能(redelivery)中的一个术语,主要用于防止重复消费消息。

3、善用 GitHub,从项目的 issue/PR/wiki 列表获取有效信息

首先,issue 列表不用多说了,如果你在使用软件的过程中遇到了问题,首先考虑的就是去 issue 列表搜索。

虽然有时候搜出来的并不是直接的答案,但多换关键词搜几次,大概率就能找到一些思路解决问题了。

另外, PR 信息可以帮助我们了解某些代码片段的上下文背景

举个例子,比如你阅读某段代码时有疑惑,不明白这个代码的目的是什么,那么可以在 IDEA 中的代码左侧单击右键,打开「Annotate with Git Blame」就可看到这段代码是谁在什么时候添加上去的:

图片

然后把鼠标悬停在作者昵称上两秒,就会弹出这个代码被合进 master 分支时的 PR 标题和链接:

图片

18260就是这个 PR 的编号,点击即可跳转到对应的 PR 页面:

图片

可以看到这个 PR 是用来修复18241号 issue 的,在18241号 issue 中详细描述了 bug 信息及复现方法:

图片

有了这些上下文信息,就可以避免我们阅读源码时的障碍了。

最后, wiki 页面可以帮我们了解一些重要的功能设计或改动

拿 Pulsar 来说,如果需要做比较重要的改动,需要提出一个 PIP 提案(Pulsar Improvement Proposal),也就是一个专门讲解背景信息、设计思路的文档。

而这些 PIP 文档就收集在 wiki 页面:

图片

所以在了解某个功能模块的设计思路时,可以先去 wiki 页面看看是否有相关的 PIP 可供参考。

比如 Pulsar 的事务实现,就有一个专门的 PIP 详细介绍了设计思路,结合 PIP 的思路指引去学习源码就会容易很多:

图片

我个人觉得,好的 PIP 结合源码,带我们把一个功能从讨论设计做到落地实现,这就是很好的教科书呀,多花精力去研究,肯定会有所收获的。

以上就是最常用的有效信息的获取途径,如果你在学习使用开源项目时遇到问题,那么可以尝试上述的方法去寻找答案。

当然,熟练掌握进行信息检索的工具进行高效检索也是重要的技能,比如说 IDEA 的各种搜索、GitHub issue/PR 的搜索语法,这些技巧网上可以很容易搜到,我就不赘述了。

二、源码阅读技巧

想真正了解一个项目,看源码肯定是逃不掉的一环。阅读源码的好处不用多说了,但阅读源码肯定会花费大量时间,而且这个过程不会很轻松。

你想嘛,成熟的开源项目经过多年的发展,功能不断演进,很多人往里面写过代码,恐怕没人能保证自己完全了解系统的每个细节。我们阅读源码,就好比探索一座庞大的城市,很容易迷失在某个犄角旮旯。

对于这个问题,我可以分享一些小技巧。

技巧一、不建议看「死代码」,建议在调试实际问题的过程中理解代码

换句话说,不要拿着代码硬读,最好是通过动态调试来研究每个功能中做了什么。

拿 Pulsar 举例,我们可以在命令行启动 standalone 模式的 Pulsar broker:

$ bin/pulsar standalone

然后用 Java client 创建一个 producer 发送一条消息:

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar://localhost:6650")
        .build();

Producer<byte[]> producer = client.newProducer()
        .topic("testTopic")
        .create();

MessageId messageId1 = producer.send(("hello1").getBytes());

client.close();

我们就可以调试这个简单的场景,看看 producer 是如何创建的,消息是如何发送并存储在 Pulsar 中的。

但如果想跟踪调试这段代码,会遇到一些问题:

第一个问题是,我们自己的项目是通过 Maven 引入 client 包的,如果进入这些包看到的是反编译的 class 文件,无法直接看到源码。就算 IDEA 可以直接帮我们下载源码,但如果我们在从事 client 的开发,需要 master 分支的最新版代码,这和上传到 Maven 的源码还是不一样。

这个问题比较容易解决,我们直接从 GitHub 下载源码,在 client 包里面创建一个 test 文件写逻辑,这样就可以调试最新的 client 代码了。

第二个问题比较棘手,我们想调通整个 Pulsar 发送消息的流程,那么这里面肯定要涉及 Pulsar client 和 Pulsar broker 的交互,而 broker 是通过命令行启动的,我如何调试 broker 里面的代码呢?

我们可以观察一下,bin/pulsar这个文件其实就是个 shell 脚本,可以找到这样一段代码:

elif [ $COMMAND == "standalone" ]; then
    PULSAR_LOG_FILE=${PULSAR_LOG_FILE:-"pulsar-standalone.log"}
    exec $JAVA $LOG4J2_SHUTDOWN_HOOK_DISABLED $OPTS ${ZK_OPTS} -Dpulsar.log.file=$PULSAR_LOG_FILE -Dpulsar.config.file=$PULSAR_STANDALONE_CONF org.apache.pulsar.PulsarStandaloneStarter $@

standalone命令其实就是运行java命令,输入一大堆参数,加载了一堆 jar 包,最终启动了PulsarStandaloneStarter这个类,所以我们可以使用 JVM 远程调试功能

IDE 就给我们提供了 Remote JVM Debug 功能:

图片

我新建一个远程调试,参数填默认的就行,这里 IDE 给我们自动生成了一段 JVM 参数:

图片

我们把这段 JVM 参数复制,把其中的suspend=n改成suspend=y,然后修改bin/pulsar文件,把这段参数添加到standalone模式的启动参数中:

elif [ $COMMAND == "standalone" ]; then
    # 添加调试参数,注意 suspend=y
    OPTS="${OPTS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"

    PULSAR_LOG_FILE=${PULSAR_LOG_FILE:-"pulsar-standalone.log"}
    exec $JAVA $LOG4J2_SHUTDOWN_HOOK_DISABLED $OPTS ${ZK_OPTS} -Dpulsar.log.file=$PULSAR_LOG_FILE -Dpulsar.config.file=$PULSAR_STANDALONE_CONF org.apache.pulsar.PulsarStandaloneStarter $@

这样,我们本地命令行再执行执行bin/pulsar standalone时就会挂起:

$ bin/pulsar standalone --num-bookies 3
Listening for transport dt_socket at address: 5005

此时,你在 IDE 里可以给代码随意打断点,点击 debug 按钮后 broker 才会启动,走到断点处将暂停,我们可以在 IDE 中查看变量、堆栈等信息。

这样我们就能在 IDE 中同时调试 client 端和 broker 端的代码了。

但是需要注意的是, 进行远程调试的源代码必须和命令行启动的 broker 一致 ,否则会导致调试时行数对不上的问题。

如果出现源码对不上的情况,可以在 pulsar 项目的根目录用 maven 重新编译当前的源码:

$ mvn package -DskipTests -Dlicense.skip=true

编译好的二进制包在distribution/server/target中,我们在新的包中的bin/pulsar脚本添加远程 debug 的参数,然后再次启动即可顺利调试。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 源码
    +关注

    关注

    8

    文章

    573

    浏览量

    28589
  • 开源项目
    +关注

    关注

    0

    文章

    36

    浏览量

    7097
收藏 人收藏

    评论

    相关推荐

    LabVIEW 实用技巧.

    Labview实用技巧
    发表于 06-29 12:38

    单片机小项目开源分享

    转眼间已经工作一年,目前从事linux/android驱动工作,将大学期间单片机的小项目开源出来,供大家交流学习,比较简单。源码在git clone http://www.github.com
    发表于 09-17 11:33

    机友分享 | 导入机智云Android开源项目的正确姿势

    以下文章来源于小雨编程 ,作者小雨tt“使用机智云AIoT平台支持项目自生成APP源码,即可轻松解决Android开源项目啦,”开发者下载源码
    发表于 09-28 10:58

    【HiSpark系列】润和 HiHope 社区 开源项目集合

    本帖最后由 l_xy 于 2020-10-22 09:54 编辑 # 润和 HiHope 社区 开源项目集合 https://gitee.com/organizations/hihopeorg
    发表于 10-22 09:52

    C语言开源项目

    值得学习的C语言开源项目- 1. WebbenchWebbench是一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工
    发表于 08-20 06:15

    下载编译源码的要点和搭建源码阅读环境的方法

    下载编译源码的要点和搭建源码阅读环境的方法。下载编译源码,一方面是为了搭建源码阅读环境,另一方面
    发表于 01-10 06:49

    STM32项目开发中超级实用技巧分享

    STM32项目开发中超级实用技巧一. 利用软启动打补丁二. 优化等级尽量选择不优化三. 合理利用开关总中断所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!关于STM32其它
    发表于 01-21 06:22

    分享一个超级实用的源码阅读小技巧

    工欲善其事必先利其器; 我发现函数调用图可以让我们更加直观地了解到源码函数直接的调用和层次关系,提高阅读源码的效率 。 1 前言 看源码的时候,心血来潮想弄一下函数之前的调用关系,想起
    的头像 发表于 05-29 11:50 1753次阅读
    分享一个超级实用的<b class='flag-5'>源码</b><b class='flag-5'>阅读</b>小技巧

    模拟阅读开源分享

    电子发烧友网站提供《模拟阅读开源分享.zip》资料免费下载
    发表于 11-14 11:21 0次下载
    模拟<b class='flag-5'>阅读</b>器<b class='flag-5'>开源</b>分享

    矩阵显示器上的新闻阅读开源项目

    电子发烧友网站提供《矩阵显示器上的新闻阅读开源项目.zip》资料免费下载
    发表于 02-08 10:46 0次下载
    矩阵显示器上的新闻<b class='flag-5'>阅读</b>器<b class='flag-5'>开源</b><b class='flag-5'>项目</b>

    阅读开源项目源码实用技巧(下)

    这句话其实是高效 debug 的关键。初看源码时「猜」是很重要且很有效的手段,结合 IDE 的搜索功能,能够帮我们快速定位关键代码。
    的头像 发表于 04-12 11:37 443次阅读
    <b class='flag-5'>阅读</b><b class='flag-5'>开源</b><b class='flag-5'>项目</b><b class='flag-5'>源码</b>的<b class='flag-5'>实用技巧</b>(下)

    Java算法大全源码开源源码

    Java算法大全源码开源源码
    发表于 06-07 14:58 1次下载

    Haiku eInk阅读开源分享

    电子发烧友网站提供《Haiku eInk阅读开源分享.zip》资料免费下载
    发表于 06-15 14:45 0次下载
    Haiku eInk<b class='flag-5'>阅读</b>器<b class='flag-5'>开源</b>分享

    Raymond Roussel阅读开源分享

    电子发烧友网站提供《Raymond Roussel阅读开源分享.zip》资料免费下载
    发表于 06-15 11:25 0次下载
    Raymond Roussel<b class='flag-5'>阅读</b>机<b class='flag-5'>开源</b>分享

    如何去阅读源码,我总结了18条心法

    在一个优秀的开源项目中,设计模式处处存在,所以在你开始阅读源码之前最好先了解一下常见的一些设计模式。当你了解了一些设计模式以后,在源码中遇到
    的头像 发表于 07-17 16:00 434次阅读
    如何去<b class='flag-5'>阅读</b><b class='flag-5'>源码</b>,我总结了18条心法