本文首发于51CTO技术栈公众号
作者 陈彩华
文章转载交流请联系 caison@aliyun.com
复制代码
随着蓬勃发展的开源时代的到来,为了减少开发成本,提高开发效率,越来越多的公司使用各种开源项目,作为开发者,如果能充分利用好开源项目中的资源,不仅能提高实践能力,专业知识水平,还能从中其中学到的优秀的架构思想。
本文将提供一些学习开源项目的思路,相信看了这篇文章,小白也可学习读懂开源项目,不必再对着高大上的开源项目望而生畏,浅尝辄止。
1 学习的价值
总结起来,学习开源项目的价值主要包括以下几点:
- 专业水平的提升 很多通用的专业知识,在专业领域内去到哪个公司都能通用,特别是底层方面的知识,可以在开源项目中学到,比如多线程处理、网络通信、操作系统处理等。 举个例子,通过学习Redis 的 RDB 持久化模式的“会将当前内存中的数据库快照保存到磁盘文件中”,可以学习到其实就是在操作系统fork一个子进程来实现,再继续深入的话,就涉及到父子进程机制, copy-on-write 技术。
这些专业知识之间是可以联系起来的并且像一颗大树一样自我生长,但是当没理解透彻,自然没法产生联系,也就不能够自我生长了。当我们对开源项目的关键的点理解清晰,知识也随着自我生长,也就如滚雪球一样可以滚起来了。
- 解决问题能力的提升
通过学习开源项目的实现,出现线上问题时,可以快速定位问题症结所在,通过修改配置或者修改源代码来解决;或者当业务需求没有合适的开源项目能满足时,可以改造现有的开源项目来满足业务。 作为要优秀开发,避免陷入“API操作工”的被动局面,学习开源项目的一个很重要目的就是知道其功能点是如何实现且优化的,学习其中的知识好比公式的推导过程,掌握基本API使用好比会数学公式可以应付考试,但是理解好的推导过程根据有助于记忆和理解,知其然也要知其所以然,当遇那些没法套公式的情况下,我们也知道如何解决。
- 思维的提升
通过学习成熟的开源项目的优秀架构,可以总结和理解一些软件设计常用的架构思路,例如实现高可用,主要是通过集群的数据冗余,例如Kafka集群,HDSF集群;实现可扩展可以考虑把变化层和不变层隔离,把业务实现抽象化,例如Spring的预留的一些可扩展接口。
2 常见错误观点
学习开源项目有一些常见的错误观点,导致新手容易望而生畏而轻易放弃,或者浪费大量时间而收获不大:
学习开源项目是架构师,技术大牛的事,我作为新手根本难以学会,就算学了也用不到。
复制代码
学习是一个过程,不是一朝一夕就可以成为大牛的,但是只要踏出第一步,总会有可能实现的大牛梦想的;另一方面,通过不断复盘不断总结,加以合适的方法论指导,相信是可以有所收获的,能力得到提升的。 学习之后对于逻辑思维,知识体系的构建有相信会有很大提升,即使项目没用到具体的开源项目,以后遇到相关问题可以触类旁通,举一反三,也是一种进步。
数据结构和算法很重要,我只要学习这项目中的2方面就可以了
复制代码
不要只盯着数据结构和算法,这2点在开源项目中并没有那么重要,例如Netty中的超时队列是基于红黑树来实现的,我们其实只需要知道这一点就够了,除非需要改造这方面的功能。更重要的是理解系统的设计,功能的实现方案。
一头扎进源码进行学习
复制代码
很多新手笃信社区论坛流行的一句话“Talk is cheap, show me the code”,一头扎进源码阅读,却最后陷入源码的泥潭中,在层层代码函数跳转中迷失了方向。
其实学习开源项目应该是自顶而下的,最底层的源码应该是最后才开始学习,在此之前,需要学习项目相关架构设计方面的知识,有了这些知识,就仿佛数据库有了索引,按照知识索引来进行源码针对性突破,如巡航导弹精准爆破,自然比地毯式轰炸更起到事半功倍的作用。
3 学习的4个层次
根据学习理解的深入程度不同,可以把学习分为4个层次
-
基础学习 对项目有一个大概性、基础性的了解,比如项目是什么,有什么作用,大概怎么用,解决了什么问题。 在面试中,不少初入职场的人的简历写到用到众多的技术框架,实际上往往仅仅只到了这个层次,再深入往下问,便支支吾吾答不上来了。
-
检视学习 对项目有一个系统性的了解,系统的各方面功能,基本原理,优缺点,使用场景,各配置项、API使用。 在实际工作中,如果作为一个团队的普通成员,达到这个级别已经可以满足基本业务开发需求,但是如果想有更高的技术追求,仅仅到此是不够的。
-
分析学习 在检视学习的基础上,对开源项目的各项性能参数,各自场景性能调优有比较全面的了解和实践经验。 到达这个层次,在项目生产中,已经有独当一面的能力,有一定能力承担核心主力开发的角色。
-
主题学习 在分析学习的基础上,对开源项目的关键功能模块的源码有所了解,能够根据实际需要封装、修改源码,或者借鉴项目造出新的轮子。 到达这个层次,往往有一定能力承担技术负责人、技术带头人的角色。
4 学习的4个步骤
针对上面提到的学习的层次,下面介绍如何“自顶而下”学习,来达到这4个层次。
4.1 基础性了解学习
目标是达到基础学习的层次,对项目有大概性的了解,包括项目背景,解决的问题场景,项目功能,使用场景,基本的API使用。通过查找官方文档、相关博客、视频资料学习即可。
通过对系统有大概性了解之后,会自然而然有一些疑问,例如实现的原理,优缺点等,后续学习带着这些疑问进行学习会更高效。
4.2 系统性学习与实践
目标是达到检视学习的层次,对项目有系统性、全面性的了解,包括项目的功能、组成模块、基本原理、使用场景、配置项、API使用、与其他类似项目的优缺点比较等。
方法步骤如下:
-
1 安装运行 按照相关文档,安装运行项目。在这个过程中,需要关注:
- 系统的依赖组件 因为依赖组件是系统设计和实现的基础,可以了解系统一下关键信息,例如 Memcached最重要的依赖是高性能的网络库 libevent,我们就能大概推测 Memcached 的网络实现应该是 Reactor 模型的。
- 安装目录 常见的安装目录是conf存放配置文件,logs存放日志文件,bin存放日志文件,而不同项目有些特殊目录,比如Nginx有html目录,这种目录能促使我们带着相关疑问继续去研究学习,带着问题去学习效率是最高的。
- 系统提供的工具 需要特别关注命令行和配置文件,它们提供2个非常重要的关键信息,系统具备哪些能力和系统将会如何运行。这些信息是我们学习系统内部机制和原理的一个观察窗口。 通常情况下,如果对每个命令行参数和配置项的作用和原理基本掌握了解的话,基本上对系统已经很熟悉了。实践中,可以不断尝试去修改配置项,然后观察系统有什么变化。
-
2 系统性研究原理与特性 这点相当重要,因为只有清楚掌握技术的原理特性,才能算真正掌握这门技术,才能做架构设计的时候做出合理的选择,在这个过程中,需要重点关注:
-
关键特性的基本实现原理 关键特性是该开源开源项目流行的重要卖点,常见的有高性能、高可用、可扩展等特性,项目是如何做到的,这是我们需要重点关注的地方。
-
优缺点比对分析 优缺点主要通过对比来分析,即:我们将两个类似的系统进行对比,看看它们的实现差异,以及不同的实现优缺点都是什么。典型的对比有 Memcached 和 Redis、Kafka和ActiveMQ、RocketMQ的比较。
-
使用场景 项目在哪些场景适用,哪些场景不适用,业界适用常见案例等。
-
在此阶段可以通过学习官方技术设计文档文档,架构图,原理图,或者相关技术博客,通常比较热门的开源项目都有很多分析文档,我们可以站在前人的基础上避免重复投入。但需要注意的是,由于经验、水平、关注点、使用的版本不同等差异,不同的人分析的结论可能有差异,甚至有的是错误的,因此不能完全参照。一个比较好的方式就是多方对照,也就是说看很多篇分析文档,比较它们的内容共同点和差异点。
同时,如果有些技术点难以查到资料,自己又不确定,可以通过写Example进行验证,通过日志打印、调试、监测工具观察理解具体的细节。例如可以写一个简单程序使用Netty,通过抓包工具观察网络包来理解其中的实现。
4.3 系统测试
如果是只是自己学习和研究,可以参考网上测试和分析的文档,但是如果要在生产环境投入使用必须进行测试。因为网上搜的测试结果,不一定与自己的业务场景很契合,如果简单参考别人的测试结果,很可能会得出错误的结论,或者使用的版本不同,测试结果差异也比较大。
要特别注意的是,测试必须建立在对这个开源项目有系统性了解的基础上,不能安装完就立马测试,否则可能会因为配置项不对,使用方法不当,导致没有根据业务的特点搭建正确的环境、没有设计合理的测试用例,从而使得最终的测试结果得出了错误结论,误导了设计决策。
下面提供测试常见的思路参考,需要根据具体项目具体业务进行测试用例的设计。
- 核对每个配置项的作用和影响,识别出关键配置项
- 进行多种场景的性能测试
- 进行压力测试,连续跑几天,观察 CPU、内存、磁盘 IO等指标波动
- 进行故障测试:kill,断电、拔网线、重启 100 次以上、倒换等
4.4 关键源码学习
钻研、领悟该项目的各种设计思想与代码实现细节,基本定位是“精通”,精益求精,学无止境。这是大神们追求的境界。如果希望成为团队技术担当、项目社区的重要贡献者,则应当以这个层次作为努力的目标。
代码不仅是读,还要理和试,有的人连API都没有调用过,上来就看代码,以为省了时间,实际是迈向自我摧残。
对源码进行理和试的关键如下:
-
1 在IDE拿到调用栈 在IDE里读。IDE里可以方便跳转,查看定义,比起网页上看效率高得多。 通过IDE工具,运行example程序进行跟踪调试,通过打断点可以得到程序运行的调用栈。 尽可能编译调试。能调试的代码,几乎没有看不懂的。
-
2 把调用栈画下来 把代码的调用逻辑梳理出来之后,再通过画图工具,把代码的图画出来,可以画:流程图、类图、调用图、时序图,更具实际情况选择最有表现力的图。
此外,平时多了解一些设计模式。这样看到名字里有proxy,builder,factory之类的,就心领神会了。横向分层,纵向分块。代码都是分模块的,有的是core,有的是util,parser之类的,要知道看的是哪一层,那一块。
有的小项目分层不明显,也不必强求。要看的不只是语法上的技巧,更重要的是设计上的思路和原理。读没读懂,最简单的标准是,假如给充足的时间,有没有信心写出一个差不多的东西来。
5 步骤总结
实际实践操作中,完整执行上面5个步骤花费时间就长,通常情况下,前面2个步骤,在研究开源项目的时候都必不可少,第3个步骤可以在工作中打算采用开源项目才实施,第4个步骤在有一定的时间和精力下灵活安排时间做。
与其每个项目走马观花去简单了解,不如集中火力把一个项目研究吃透,即使半年才吃透一个,积累几年之后数量还是很可观的。而且很多项目的思想是共同的,例如高可用方案、分布式协议等,研究透一个,再研究类似项目,会发现学习速度非常快,因为已经把共性的部分掌握了,只需要再研究新项目差异的部分。
同时,在学习的过程中,需要不断总结,复盘,输出学习笔记,一方面锻炼逻辑思维能力,一方面有利于建立知识索引,过一段时间回顾的时候通过索引可以快速重新掌握知识,不容易遗忘。
6 面向新手友好的几个开源项目推荐
介绍理论之后,下面就是需要通过实践来检验了,下面介绍服务端开发常见的几个比对对新手友好,而且资料比较多的开源项目参考:
-
Spring
-
Mybatis
MyBatis 作为业界流行的优秀持久层框架,支持普通 SQL 查询,存储过程和高级映射,代码量不大,网上相关源码解析的资料也比较多,项目的代码质量也是比较高,值得一读。
-
Elastic-Job
-
Dubbo
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务治理框架,使得应用可通过高性能的RPC 实现服务的输出和输入功能。Dubbo在17年年底重新启动维护,在业务广泛使用,通读了解源码,在服务治理,分布式协议方面的技术实力相信会有质的飞跃。