作者简介陈晨,基础架构工程师,目前就职于中国银联。主要负责IaaS平台、容器平台和运维管理平台的建设。本文将重点介绍运维人员学习源码的一些技巧。一、准备阶段1、制定计划看源码和看书一样,要有时间计划,截止日期就是最好的生产力。一个合理的计划可能需要你对代码的结构,以及每个功能的重要性和难度有一个全局的把握。2.选择一本好书作为学习资料,书一定是最好的。网上资料太分散,学习可能不系统;比较系统的书籍一般都会详细讲解开源代码的配置和集成;然后介绍一些常用的模块,最后跟踪分析每个组件或流程的代码。选书的时候也要注意取舍。通过本书每一章的介绍,我们可以看出这本书是不是按照这个逻辑讲的。比如笔者在学习openstack的时候,根据目录选择了这样一本书:他的四章是基础-安装-代码-二次开发。这是一本非常好的循序渐进的书。3.选择一个好的IDE作者除了Java什么都用Vim。当然,这完全取决于每个人的习惯。笔者一般比较喜欢轻量级的IDE,所以推荐一些轻量级的:VimSublimeSourceInsightIDE全称IntegratedDevelopmentEnvironment。如果你只是想运行代码,你只需要一个编译器或解释器。代码在纯文本上是完全可编辑的。IDE提供了更多的开发辅助功能,让开发者专注于代码的逻辑。最常见的功能是自动纠错、代码补全和函数查询。C的很多IDE也会自动生成makefile,这样也省去了很多繁琐的内容。尽管如此,IDE的功能性和简单性始终是一个悖论。读者在选择IDE的时候,应该选择符合自己需求的IDE,不要过于追求强大的功能。一般来说,我们在使用IDE时可能会有哪些辅助需求:集成测试工具、自动打包、代码定位、自定义、丰富的插件、错误检查、调试项目模板4、下载完整版本库完整代码库参考反映代码迭代过程的各个历史版本。这样做有很多好处:您可以获得代码更改的记录。您还可以获得完整的测试代码。当你要提交补丁时,可以使用版本管理工具生成不同版本的补丁。二、初识代码1、阅读项目文档。大多数开源项目都会对其架构进行一定的描述。通读它将使您对项目有更深入的了解。重点关注Gettingstarted和Example等文档,学习下载、安装和使用项目所需的知识。比如openstack,官网上的网络拓扑解释是最全面准确的:2.分类文件,明确区分代码库中各个文件的功能。在合适的时候,对所有文件做一个整体的把握,有助于后面阅读代码时选择优先级。知道什么是核心,什么是可定制的。以下是笔者收集的nova部分源码文件:/nova/api/auth.py:通用认证中间件,接入keystone;/nova/api/manager.py:元数据管理初始化;/nova/api/ec2/__init__.py:AmazonEC2API绑定,路由EC2请求的起点;/nova/api/ec2/apirequest.py:APIRequest类;/nova/api/metadata/__init__.py:Nova元数据服务;......刚开始写笔记的时候,其实有些事情我是拿不准的。这样的注释也不会最终让您非常清楚地了解代码中所有文件的关系。不过没关系,在前期尝试做这样的事情是有好处的,这可能是你掌握源码整体结构的第一步。3.掌握开发框架框架的目的是为了简化开发。但它也使代码不那么直观。比如很多用spring开发的开源软件,如果你连spring都不懂,你会发现连代码入口都找不到。因为开发框架下的代码已经被“劫持”了!举个例子,spring+springmvc+mybatis开发web应用的时候。如果了解了这三个基本框架,就可以清楚地知道以下文件的作用:所有URL对应的控制器都在com.dc.controller中,所有的数据接口都在com.dc.dao中,所有的实体都在com.dc.dao中。dc.dao对象在com.dc.entity中所有的数据接口和sql语句对应都在com.dc.dao.mapper中所有的服务定义都在com.dc.service和com.dc.service.Impl中,当我看到这样一个函数:立马知道是spring中处理url路径的controller函数。因此,如果您确定开源代码使用了成熟的开发框架,请务必先熟悉框架。三、熟悉代码行为1、组件执行过程比较复杂的系统被分解成组件,分别熟悉每个组件,理清它们之间的关系。例如openstack的执行流程图:虚拟机启动流程如下:接口或命令行通过RESTfulAPI从keystone获取认证信息。b.Keystone通过用户请求认证信息,生成auth-token返回给对应的认证请求。C。接口或命令行通过RESTfulAPI向nova-api发送启动实例请求(携带auth-token)。d.nova-api接受请求后,向keystone发送认证请求,检查token是否为有效用户和token。2.使用示例代码和单元测试示例代码可以帮助您学习使用相关开源项目的API。大多数开源项目在开发过程中,为了验证实现的功能,会编写大量的单元测试代码。这些代码其实都是很好的示例代码。阅读单元测试的好处太多了。这里罗列一下知乎网友总结的好处:由于一个单元测试通常需要几个小时的开发工作,你可以很容易地理解相关代码。每个单元测试都可以独立运行,从而节省您跟踪和调试的时间。单元测试在很大程度上定义了软件的功能,可以帮助你快速掌握项目的相关API。如果你修改了一个开源项目的代码,你可以通过修改单元测试来验证你的修改是否正确。注1:原文链接https://www.zhihu.com/question/19637879/answer/13545260如果项目提供了现成的示例工程:首先按照启动文档的介绍尝试运行示例。如果运行顺利,恭喜你。一个好的开始;如果遇到问题,首先尝试在项目的FAQ和其他文档中寻找答案。第三,可以将问题(如异常信息)作为关键词搜索相关解决方案。你遇到了,别人一般都会遇到。热心的朋友记录一下解决过程。***,你可以提交问题到项目的邮件列表,请给你看一下。不要在没有成功运行示例的情况下尝试修改示例。运行第一个例子后,尝试根据自己的理解和需求修改例子,测试高级功能等。3.跟踪分析几乎没有一个复杂的开源软件是一个过程到最后。这时候我们就需要选择一个主进程。比如openstack,作者从一开始就花了不少心思去梳理创建虚拟机的过程。第一步,沿着创建虚拟机的过程,从代码入口开始逐行注释:当流程的基本注释完成,掌握了之后,就可以抽茧总结了,比较直观简洁表达方式:当你逐渐了解一两个主流程后,你通常会发现其他分支流程非常相似。这为掌握整个过程打下了良好的基础。4.对需要详细了解的功能进行排序。在安排自己的深度阅读时,要根据预估的工作量合理安排。一般来说,初始化、读取参数等都是次要的,比较简单。核心模块要复杂得多。仍然以haproxy为例,main函数中的核心代码是run_poll_loop()。笔者曾尝试从init()函数入手,结果发现一大堆初始化的数据根本不知道干什么,看一遍就什么都想不起来了。但是直接从main函数开始,发现在处理一些参数的时候更容易理解,更容易向后追溯它的初始化过程。四、掌握数据状态1、掌握数据流从数据流的角度来看,所有的代码逻辑都是在处理数据。比如openstack,从一开始用户输入的虚拟机名称、配置等数据开始,openstack处理、处理、过滤、选择数据的代码逻辑,最后传递给libvirt,最终创建虚拟机。因此,掌握数据的组织方式对于理解代码逻辑非常有帮助,也是进行二次开发的前提。所以,在学习代码的时候,不断问自己,我是否掌握了数据的组织方式?我是否掌握了贯穿整个过程的连续数据处理过程?2.使用debug观察数据的状态。在这个过程中,一定要注意数据传输的方式和内容。数据流是理解流程的基础,扩展数据流也是二次开发的常用技能。例如在eclipse中,通过debug断点,获取进程中某个点的数据内容:3.使用标准输出观察数据状态。有时作者也喜欢直接用控制台输出打印对象的一些信息。这在验证某段代码是否执行过,或者查看某条数据时也很有效。比如通过chrome的标准输出查看javascript的输出:五、从一个实例到其他三个阶段的推论1、研究底层调用研究底层调用往往是一种常见的运维手段。比如在openstack操作之初,我们对openstack的源码不熟悉,怎么办?直接研究openstack的底层调用。Openstack底层是调用libvirt的接口,我们学习了创建虚拟机等基本操作。因此,对于大多数openstack问题,我们可以直接到问题现场进行恢复和排查。那么研究底层调用对理解源码有什么好处呢?在笔者基本熟悉了openstack的所有底层调用之后,我带着这样一个疑问查看了源码:“代码是如何从入口逐渐运行到我所知道的底层调用的?”Whataboutit?”,笔者很快梳理了代码的执行过程。2.学会在社区或者stackoverflow提问,社区热心的人还是挺多的,当然笔者认为提问提问也是需要一定技巧的,这里引用知乎网友的一句话:stackoverflow上很多人提问的共同点,就是对提问的问题先发表自己的看法,描述一下自己的思路,到了什么地方。是对所有受访者的尊重,你是在陈述你走了多远,你是在展示你做了什么,是你对问题的诚意。这样,受访者会觉得回答有价值,也许因为他想起了自己小白却努力奋斗的那些年,也许是因为他觉得你们有互相帮助的价值,等等。所谓的自助人帮助无外乎。链接到原文:http://www.zhihu.com/question/24228283/答案/271026463。学会画流程图,可以更轻松地展示代码执行的逻辑。忽略不重要的代码,强调主要功能。概要设计中常用的框图:思维导图:
