学习开源项目的若干建议

  • 崔康

2014 年 4 月 11 日

话题:架构语言 & 开发

随着国内开源社区和项目的不断发展,学习、应用、贡献开源项目的开发人员越来越多。最近,研究过多个开源项目 (包括 KVM/QEMU、libvirt、OpenStack、Ceph、Zabbix 等) 的业内专家章宇在其博客中分享了学习开源项目的若干建议,值得读者借鉴。

章宇认为,学习开源项目,可以划分为五个层次,分别是:

  1. 了解项目的基本概念、基本用途、逻辑结构、基本原理、产生背景、应用场景等基本知识。这个层次的基本定位其实就是“科普”。如果对于一个项目只需要有些基本了解,且短期内并不需要上手进行实际技术工作,则学习到这个层次也就可以先应付一下了。
  2. 掌握项目的基本安装流程和使用方法。这个层次的基本定位是“入门”,以便对这个项目获得直观认识,对其安装和使用获得亲身体验。如果只是需要以 as-is 方式使用这个项目,则初步学习到这个层次即可。
  3. 了解代码的组织,找到各个主要逻辑 / 功能模块与代码文件之间的对应关系,通过代码分析走通几个关键的、有代表性的执行流程。这个层次的基本定位是“深入”,开始理解这个项目的实际实现,能够真正将项目的功能、工作原理和代码实现对应起来,获得对这个项目工作过程的直观认识。这个层次是学习开源项目代码的真正开始。如果希望基于这一项目进行应用开发,或者针对与这一项目密切相关的其他项目进行工作时,则对项目本身的代码进行这一层次的理解,会很有帮助。
  4. 了解该项目所有代码模块、程序文件的作用,走通所有主要执行流程。这个层次的基本定位是“掌握”,能够比较全面、系统地理解这个项目的设计和实现,并且熟悉项目各个部分的代码。如果希望对项目进行深度定制修改,或者对社区有所贡献,则应当以达到这个层次作为目标。
  5. 钻研、领悟该项目的各种设计思想与代码实现细节。这个层次的基本定位是“精通”,精益求精,学无止境。这是大神们追求的境界。如果希望成为项目社区的重要贡献者乃至核心贡献者,则应当以这个层次作为努力的目标。

学习开源项目,必须要掌握一些基础知识,章宇指出了三点:

  • 该项目涉及的技术领域的背景知识。举例而言,分析 Linux Kenrel,则应该了解操作系统原理;学习 OpenStack,则应该知道什么是云计算。如果没有这些背景知识作为基础,上来就死磕源代码,只能是事倍功半。
  • 该项目开发使用的语言及其各种开发调试工具。
  • 英语。很遗憾,目前为止真正流行的开源项目大部分不是起源于国内。因此,除了学习个别极其流行、文档完备的项目之外,大家还是需要自行搜集阅读英文资料参考。学好英语很重要。

有了学习的目标和基础知识,接下来就是学习的思路和过程,章宇总结了一套由表及里、逐渐深入的学习方法。

在刚开始接触一个项目的时候,我们看到的其实就是一个黑盒子。根据文档,我们一定会发现盒子上具有若干对外接口。通常而言,这些接口可以被分为三类:

  • 配置接口:用于对盒子的工作模式、基本参数、扩展插件等等重要特性进行配置。这些配置往往是在盒子启动前一次性配好。在盒子的工作过程中,这些配置或者不变,或者只在少数的情况下发生改变。
  • 控制接口:用于在盒子的工作过程中,对于一些重要的行为进行操纵。这是盒子的管理员对盒子进行控制命令注入和状态信息读取的通路。
  • 数据接口:用于盒子在工作过程中读取外部数据,并在内部处理完成后向外输出数据。这是盒子的用户真正关心的数据通路。

因此,在分析一个开源项目的代码时,可以围绕重要的配置、控制、数据接口展开分析工作,特别应该注意理解一个关键的接口背后隐藏的操作流程。例如,针对数据接口,至少应当走通一条完整的数据输入输出流程,也即在代码中找到数据从输入接口进入盒子后,经过各种处理、转发步骤,最终从输出接口被传输出去的整个执行过程。一旦走通了这样一条流程,则可以将与数据处理相关的各个主要模块、主要步骤贯穿起来,并将逻辑模块图上和文档中的抽象概念对应到代码实现之中,可以有效推进对于项目的深入理解。

在实践这一思路的过程中,笔者建议可以优先从控制接口和数据接口中各自选择一二重要者进行背后的执行流程详细分析,力争找到其中每一步的函数调用及数据传递关系(对于一些系统、应用库提供的底层函数可以先行跳过以节省时间)。这一工作完成之后,则第三层次的学习目标即可初步达成。

配置接口在不同的项目中的重要程度不同。对于一些架构极为灵活、配置空间甚大的项目(如 OpenStack 的 Ceilometer),则可以适当多花些时间加以研究,否则简单了解即可。

作者以“OpenStack Cinder”为例,讲述了如何学习开源项目:

  1. 首先,想对 Cinder 进行分析,一定要了解若干相关的基础知识。什么是云计算?什么是块存储?什么是 OpenStack?Cinder 在 OpenStack 里的作用?等等等等。如果对这些东西没有概念,则后续学习是很难开展下去的。
  2. 在此基础上,如果有条件,则最好能够亲自部署和实际操作一下 Cinder(包括必要的其他 OpenStack 组件),以便对 Cinder 获得一个直观的认识和体验,为后续分析提供一些参考。此处假定 Cinder 使用的后端是 Ceph,而 OpenStack 上运行的虚拟机是 KVM。
  3. 然后,应该从概念上对我们要分析的系统的逻辑框架有个理解。从总体的范畴上讲,应该了解 Horizon 和 Nova 各自的逻辑模块结构,以及它们和 Cinder 的协同工作方式、关系。这部分与 Cinder 的控制接口及执行路径分析密切相关。此外,还应该了解 Cinder 和 KVM/QEMU、Ceph 之间的相互关系。这对于真正理解 Cinder 很有帮助。从 Cinder 自身而言,应该了解其内部逻辑模块构成、各自的功能、相互间的控制、数据连接关系等。
  4. 在完成上述准备之后,则可以开始对 Cinder 的代码进行分析了。如前所述,应该考虑在控制接口和数据接口中各自选择一两个关键的、有代表性的加以分析。至于配置接口,假定其实现了某一配置即可,暂时不需要过多花费时间。Cinder 的核心功能其实是 OpenStack 上的 volume 管理。至少在 Cinder+Ceph 方案中,Cinder 自身并不在数据传输关键路径上。因此,控制接口的分析就是 Cinder 源代码分析的重中之重。就入手阶段而言,则有两个接口及其对应执行流程可以作为 Cinder 分析的起点,即 volume 的 create 和 attach 操作。如果能够彻底打通这两个操作的执行流程(至少要看到 Cinder 与 Ceph 通过 librbd 交互的层面),则对于真正理解 Cinder 的功能与实现大有帮助。虽然基于 KVM 的虚拟机在通过 QEMU 访问 Cinder 创建的、Ceph 提供的 volume 时并不通过 Cinder,也即,这一部分的源代码其实已经超出了 Cinder 源代码学习的范畴,但是,如果希望真正彻底地理解 Cinder,则对于这一部分知识还是应该有所涉猎,至少应该有概念上的了解。

除此之外,作者还提供了一些建议,比如过好笔记、不要过分纠缠于细节等,完整的内容可以查章宇的博客。InfoQ 的读者对学习开源项目有何心得,欢迎发表自己的看法。

架构语言 & 开发